Help us shape the future of Go! Take the 2026 Go Developer Survey

report

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package report builds the compliance evidence report of `agentguard report`: what AgentGuard decided over a period, how far the audit log that recorded it can be trusted, and how that maps to SOC 2 criteria.

It does no I/O. The caller reads the audit log (files or a server), runs the checks it can, and hands the entries to Aggregate as an iterator; the renderers write the finished Report as Markdown, JSON or HTML. That keeps every number in the report testable from a fixed list of entries.

The JSON form is a stable shape for 1.x: fields are only ever added. FormatVersion changes only if that ever stops being true. See docs/COMPLIANCE.md.

Index

Constants

View Source
const (
	// MethodVerify: the files were checked with audit verify.
	MethodVerify = "verify"
	// MethodSealHead: the server's GET /v1/audit/head was read. The chain
	// itself was not checked.
	MethodSealHead = "seal_head"
)

Integrity methods: how the report learned about the audit log's seal.

View Source
const (
	IntegrityIntact      = "intact"       // the chain verified
	IntegrityBroken      = "broken"       // audit verify found tampering or damage
	IntegrityNotSealed   = "not_sealed"   // the log has no seal chain
	IntegrityNotVerified = "not_verified" // sealed, but the chain was not checked
	IntegrityUnknown     = "unknown"      // can't tell whether the log is sealed
)

Integrity statuses.

View Source
const (
	SectionSummary   = "Summary"
	SectionIntegrity = "Audit log integrity"
	SectionActivity  = "Activity"
	SectionRules     = "Top rules"
	SectionApprovals = "Approvals"
	SectionSeen      = "Agents and sessions"
	SectionPosture   = "Posture checks"
	SectionControls  = "Control mapping"
	SectionLimits    = "Limits"
)

Section names, as the renderers title them. Control.Where refers to them.

View Source
const (
	FormatMarkdown = "md"
	FormatJSON     = "json"
	FormatHTML     = "html"
)

Output formats.

View Source
const (
	SourceFile   = "file"   // the audit log files were read directly
	SourceServer = "server" // a running server was asked over GET /v1/audit
)

Source modes.

View Source
const (
	CheckPass    = "pass"
	CheckWarn    = "warn"
	CheckFail    = "fail"
	CheckUnknown = "unknown"
)

Check statuses.

View Source
const Disclaimer = "" /* 156-byte string literal not displayed */

Disclaimer heads the control mapping in every format.

View Source
const FormatVersion = 1

FormatVersion is the version of the report's JSON shape.

Variables

Formats lists the output formats Write accepts.

Functions

func Aggregate

func Aggregate(entries iter.Seq[audit.Entry], p Period) (Activity, Approvals)

Aggregate tallies the entries that fall in p. Entries outside it are skipped, so the caller can pass a whole log.

func Finish

func Finish(r *Report)

Finish fills the parts of r that follow from the rest: the posture checks, the control mapping and the limits. Call it once everything else is set.

func Limits

func Limits(r *Report) []string

Limits lists what the report can't show, for the reader to weigh the numbers against.

func Write

func Write(w io.Writer, r *Report, format string) error

Write renders r in format to w.

func WriteHTML

func WriteHTML(w io.Writer, r *Report) error

WriteHTML writes r as one self-contained HTML page: inline CSS, no scripts, nothing loaded from elsewhere, so it can be mailed or archived as is. html/template escapes every value; it leaves control and bidi characters alone, so the page goes through visible as well (the template's own text has none).

func WriteJSON

func WriteJSON(w io.Writer, r *Report) error

WriteJSON writes r as indented JSON: the documented, stable shape.

func WriteMarkdown

func WriteMarkdown(w io.Writer, r *Report) error

WriteMarkdown writes r as a Markdown document. Every value that comes from the log or the command line is escaped, so an agent id can't add table columns, links or HTML.

Types

type Activity

type Activity struct {
	// Entries is the number of audit entries in the period.
	Entries int `json:"entries"`
	// FirstEntry and LastEntry are the earliest and latest timestamps among
	// them; omitted when there are none.
	FirstEntry *time.Time `json:"first_entry,omitempty"`
	LastEntry  *time.Time `json:"last_entry,omitempty"`
	// Decisions always lists ALLOW, DENY and REQUIRE_APPROVAL, in that
	// order, then any other value found.
	Decisions  []Count `json:"decisions"`
	Scopes     Tally   `json:"scopes"`
	Transports Tally   `json:"transports"`
	Tenants    Tally   `json:"tenants"`
	Agents     Tally   `json:"agents"`
	// DenyRules and ApprovalRules are the matched rules of DENY and
	// REQUIRE_APPROVAL entries. A DENY no rule matched counts as
	// "(default deny)".
	DenyRules     Tally `json:"deny_rules"`
	ApprovalRules Tally `json:"approval_rules"`
	// AgentsSeen and SessionsSeen list the agent and session ids (entries
	// without a session id are not counted as a session).
	AgentsSeen   NameList `json:"agents_seen"`
	SessionsSeen NameList `json:"sessions_seen"`
	// RedactedEntries counts entries holding "[REDACTED]", the mask the
	// server's --audit-redact writes. UnmaskedSecretEntries counts entries
	// whose request or reason still matches one of the built-in secret
	// patterns.
	RedactedEntries       int `json:"redacted_entries"`
	UnmaskedSecretEntries int `json:"unmasked_secret_entries"`
	// UnsealedEntries counts entries in the period without a seal (no hash
	// or no seq). In server mode it is the only seal evidence per entry.
	UnsealedEntries int `json:"unsealed_entries"`
}

Activity is what was decided in the period.

type Approvals

type Approvals struct {
	// Requested counts approval ids first sent for approval in the period.
	Requested int `json:"requested"`
	// Approved and Denied count approval ids whose human decision shows in
	// the period (allow:approved or deny:approved entries).
	Approved int `json:"approved"`
	Denied   int `json:"denied"`
	// NoOutcome counts ids requested in the period with no approved or
	// denied entry in it: timed out, resolved but never retried, resolved
	// after the period, or still pending.
	NoOutcome int `json:"no_outcome"`
	// TimedOut is always null: the audit log does not record time-outs.
	// They are among NoOutcome.
	TimedOut *int `json:"timed_out"`
}

Approvals is the approval lifecycle as the audit log records it. The log has an entry when an action is sent for approval, and another when the agent comes back with the approval id after a human resolved it. It has none for the resolution itself or for a request that timed out.

type Check

type Check struct {
	Name string `json:"name"`
	// Status is pass, warn, fail or unknown (it can't be told from what the
	// report read).
	Status string `json:"status"`
	Detail string `json:"detail"`
}

Check is one posture check.

func Assess

func Assess(r *Report) []Check

Assess runs the posture checks that can be decided from what the report read. A check that can't is "unknown", never a guess.

type Control

type Control struct {
	Criterion string `json:"criterion"`
	Title     string `json:"title"`
	// Shows is what this report holds that bears on the criterion.
	Shows string `json:"shows"`
	// Where names the report's sections that hold it.
	Where []string `json:"where"`
}

Control maps the report's evidence to one SOC 2 criterion. It is supporting evidence for that criterion, not a finding that it is met.

func MapControls

func MapControls(r *Report) []Control

MapControls maps the report's evidence to the SOC 2 criteria it bears on. The wording says what the report shows, never that a criterion is met.

type Count

type Count struct {
	Name  string `json:"name"`
	Count int    `json:"count"`
}

Count is one name and how many entries had it.

type Head struct {
	Seq       uint64     `json:"seq"`
	Hash      string     `json:"hash"`
	SegmentID string     `json:"segment_id,omitempty"`
	At        *time.Time `json:"at,omitempty"`
}

Head is a seal anchor: the entry with this seq has this hash. SegmentID and At are set when a server reported it.

type Integrity

type Integrity struct {
	Method string `json:"method"`
	Status string `json:"status"`
	// Summary is one sentence for a person.
	Summary string `json:"summary"`
	// Seals says how the entries are sealed, e.g. "hmac-sha256 key
	// 3f9a…" or "sha256", in the order they appear. Empty when unknown.
	Seals []string `json:"seals,omitempty"`
	// KeyBased is true for an HMAC key, false for plain SHA-256, nil when
	// not sealed or not known. It is read from the log's _meta header,
	// which anyone who can write the file can forge: only Status intact
	// confirms it.
	KeyBased *bool `json:"key_based"`
	// Head is the latest seal anchor: the last sealed entry's seq and hash.
	Head *Head `json:"head,omitempty"`
	// Verify is audit verify's full report (verify method only).
	Verify *audit.VerifyReport `json:"verify,omitempty"`
}

Integrity is what the report knows about the audit log's seal chain.

func FromServerHead

func FromServerHead(head *audit.Anchor, sealingOff bool, why string) Integrity

FromServerHead describes a server's GET /v1/audit/head answer: a head (sealed), sealingOff (the server says sealing is off), or neither (an older server without the route, or an error, given as why).

func FromVerify

func FromVerify(rep *audit.VerifyReport) Integrity

FromVerify describes the outcome of audit.VerifyChain.

type NameList

type NameList struct {
	Count     int      `json:"count"`
	Names     []string `json:"names"`
	Truncated bool     `json:"truncated"`
}

NameList is the set of values a field had: how many, and the first of them in sorted order. Truncated is true when Names does not hold them all.

type Period

type Period struct {
	Since time.Time `json:"since"`
	Until time.Time `json:"until"`
}

Period is the time range the report covers: Since inclusive, Until exclusive, both UTC.

func (Period) Contains

func (p Period) Contains(t time.Time) bool

Contains reports whether t falls in the period.

type PolicyFile

type PolicyFile struct {
	Path string `json:"path"`
	// SHA256 is the hex SHA-256 of the file's bytes when the report was
	// made.
	SHA256 string `json:"sha256"`
	// Found says how the file was chosen: "--policy", "AGENTGUARD_POLICY",
	// "the default" or "found automatically".
	Found string `json:"found"`
}

PolicyFile identifies a policy file by content.

type Report

type Report struct {
	FormatVersion int `json:"format_version"`
	// GeneratedAt is when the report was made (UTC).
	GeneratedAt time.Time `json:"generated_at"`
	// AgentGuardVersion is the version of the binary that made the report,
	// e.g. "1.4.0 (abc1234)".
	AgentGuardVersion string `json:"agentguard_version"`
	Period            Period `json:"period"`
	Source            Source `json:"source"`
	// Policy is the policy file the report names, or nil when none was
	// given or found.
	Policy    *PolicyFile `json:"policy"`
	Integrity Integrity   `json:"integrity"`
	Activity  Activity    `json:"activity"`
	Approvals Approvals   `json:"approvals"`
	Posture   []Check     `json:"posture"`
	Controls  []Control   `json:"controls"`
	// Limits says what the report can't show. Read it with the numbers.
	Limits []string `json:"limits"`
}

Report is the whole report. Its JSON form is what `--output json` prints.

type Source

type Source struct {
	Mode string `json:"mode"`
	// AuditLog is the live audit file (file mode).
	AuditLog string `json:"audit_log,omitempty"`
	// Files are the files read, oldest first, by base name (file mode).
	Files []string `json:"files,omitempty"`
	// BadLines counts lines in those files that are not audit entries
	// (file mode; always 0 in server mode, where the server skips them).
	BadLines int `json:"bad_lines"`
	// ReadErrors are files that could not be read to the end (file mode).
	// Entries before the error are in the report.
	ReadErrors []string `json:"read_errors,omitempty"`
	// Server is the server's URL and Tenant the tenant asked for (server
	// mode; Tenant is "local" for the legacy /v1/audit route).
	Server string `json:"server,omitempty"`
	Tenant string `json:"tenant,omitempty"`
	// Fetched counts the entries the server returned, and OutsidePeriod
	// those of them the report dropped because their timestamp is outside
	// the period: a server older than 1.4 does not filter by time.
	Fetched       int `json:"fetched,omitempty"`
	OutsidePeriod int `json:"outside_period,omitempty"`
	// AuthRequired is whether the server refused an audit query that
	// carried no API key (server mode). nil when it was not checked.
	AuthRequired *bool `json:"auth_required,omitempty"`
	// Warnings say why the entries may be incomplete, e.g. the server's
	// live file rotated while the report read it.
	Warnings []string `json:"warnings,omitempty"`
}

Source says where the entries came from.

type Tally

type Tally struct {
	Distinct int     `json:"distinct"`
	Top      []Count `json:"top"`
}

Tally is a breakdown of entries by one field: how many different values it had, and the most frequent ones, most first (ties by name).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL