output

package
v0.8.0 Latest Latest
Warning

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

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

Documentation

Overview

Package output ports src/sec_af/output: the four artifact generators the orchestrator writes at the end of an audit — SARIF, the full/summary JSON, the Markdown report and the compliance report.

Every generator's output is compared byte-for-byte against the Python one by golden_test.go, which feeds both implementations the same testdata/audit_result.json fixture. That is why this package carries its own JSON writer (pyjson_local.go) instead of using encoding/json, and why every number and string below is formatted through pyfmt.

Index

Constants

This section is empty.

Variables

View Source
var SecAfCompliance = ComplianceBrand{
	Heading:   "# SEC-AF Compliance Report",
	Signature: "*Report generated by SEC-AF -- Composite Intelligence Security Auditor*",
}

SecAfCompliance is sec-af's own heading and signature.

View Source
var SecAfTool = SarifTool{Name: "SEC-AF", SemanticVersion: pythonPackageVersion,
	InformationURI: "https://github.com/Agent-Field/sec-af", PropertyPrefix: "sec-af"}

SecAfTool is sec-af's own identity, as its Python original wrote it.

Functions

func GenerateComplianceReport

func GenerateComplianceReport(result schemas.SecurityAuditResult) string

GenerateComplianceReport ports generate_compliance_report: a compliance-focused Markdown report, structured for direct PDF conversion via pandoc/weasyprint.

The header stamps the CURRENT time, exactly as the Python function does (`datetime.now(UTC)`), so two calls a minute apart differ. Tests and any caller that needs a reproducible document use GenerateComplianceReportAt.

func GenerateComplianceReportAs

func GenerateComplianceReportAs(result schemas.SecurityAuditResult, now time.Time, brand ComplianceBrand) string

GenerateComplianceReportAs is GenerateComplianceReportAt signed by brand.

func GenerateComplianceReportAt

func GenerateComplianceReportAt(result schemas.SecurityAuditResult, now time.Time) string

GenerateComplianceReportAt is GenerateComplianceReport with the "Generated:" timestamp supplied by the caller.

This seam is Go-only: Python reads the clock inline, so pinning it there takes monkeypatching (which is what scripts/gen_golden.py does to produce the committed golden). Nothing about the rest of the document depends on it.

func GenerateJSON

func GenerateJSON(result schemas.SecurityAuditResult, pretty bool) string

GenerateJSON ports generate_json:

full_json = result.model_dump_json()
if not pretty: return full_json
return json.dumps(json.loads(full_json), indent=2)

so pretty=false yields pydantic's whitespace-free dump and pretty=true the two-space-indented re-serialisation of the same document. Both are produced here by walking the Go struct directly.

THE TWO BRANCHES DO NOT SPELL FLOATS THE SAME WAY, and that is not a formatting detail — it is why each branch configures its own encoder. `model_dump_json()` is pydantic-core's Rust serializer; `json.dumps` is CPython's, which renders through repr(). They agree on ordinary magnitudes and disagree below 1e-4 (VERIFIED on the pinned interpreter):

value      pretty=False (pydantic)   pretty=True (repr)
1e-7       1e-7                      1e-07
8e-05      0.00008                   8e-05
1.23e-05   0.0000123                 1.23e-05

So Python's `json.loads` round trip is NOT value-preserving in its printed form, and a Go port that used one spelling for both branches is wrong for one of them. See the pydanticFloat flag in pyjson_local.go, the shared rule in pyfmt.PydanticFloat, and the audit_result_floats golden.

See pyjson_local.go for the rest of why encoding/json is not used: the ensure_ascii escaping, key order, and the "...Z" datetime form that only `model_dump_json()` produces.

func GenerateReport

func GenerateReport(result schemas.SecurityAuditResult) string

GenerateReport ports generate_report: the full Markdown audit report, joined with "\n" and carrying NO trailing newline (Python's `"\n".join`).

Python parity divergence: the cost-breakdown section iterates a dict, whose order in CPython is insertion order; a Go map carries none, so the phases are listed in SORTED key order. Same deviation as the JSON writer's — see pyjson_local.go encodeMap.

func GenerateSarif

func GenerateSarif(result schemas.SecurityAuditResult) string

GenerateSarif ports output/sarif.py generate_sarif: the SARIF 2.1.0 document for one audit result, serialised with `json.dumps(sarif, indent=2)`.

Findings whose verdict is "not_exploitable" are dropped entirely — they appear in neither the results nor the rules — which is what makes the SARIF artifact the "signal only" view of an audit.

The key order below is the Python dict literal's order and is part of the artifact (see pyjson_local.go).

func GenerateSarifAs

func GenerateSarifAs(result schemas.SecurityAuditResult, tool SarifTool) string

GenerateSarifAs is GenerateSarif for another tool's identity.

func GenerateSummaryJSON

func GenerateSummaryJSON(result schemas.SecurityAuditResult) string

GenerateSummaryJSON ports generate_summary_json: the compact, dashboard-shaped view of a result, serialised with `json.dumps(summary, indent=2)`.

The timestamp here is `result.timestamp.isoformat()` — the "+00:00" spelling, NOT the "...Z" one GenerateJSON produces.

func RenderJSON

func RenderJSON(auditResult schemas.SecurityAuditResult) (map[string]any, error)

RenderJSON ports render_json: the pretty document parsed back into a map.

Python returns `json.loads(generate_json(result, pretty=True))`, a plain dict; the Go equivalent is map[string]any with the same JSON-decoded value kinds (every number becomes a float64, as it does in Go generally). An error is impossible for a document this package just generated, so it is reported as a nil map plus the error rather than being swallowed.

func RenderReport

func RenderReport(auditResult schemas.SecurityAuditResult) string

RenderReport ports render_report, the alias generate_report is exported under.

func RenderSarif

func RenderSarif(auditResult schemas.SecurityAuditResult) string

RenderSarif ports render_sarif, the alias generate_sarif is exported under.

func RuleIDsAs

func RuleIDsAs(findings []schemas.VerifiedFinding, tool SarifTool) []schemas.VerifiedFinding

RuleIDsAs is findings with their SARIF rule ids under tool's prefix in place of sec-af's (`sec-af/sast/cwe-78` is `sec/sast/cwe-78`), so a log names one tool throughout. sec-af's own identity leaves them as they are; the slice is a copy, and the findings handed in are not changed.

Types

type ComplianceBrand

type ComplianceBrand struct {
	Heading, Signature string
}

ComplianceBrand is who a compliance report says wrote it: its first line and its last. sec-af's is SecAfCompliance, which the golden holds; codeaf's program signs its own (internal/secaf's sec).

type SarifTool

type SarifTool struct {
	Name string
	// SemanticVersion is a semver and Version anything else; an empty one
	// is left out of the log.
	SemanticVersion, Version string
	InformationURI           string
	// PropertyPrefix leads the driver's own result properties
	// (`<prefix>/verdict`) and its automation id.
	PropertyPrefix string
}

SarifTool is who a SARIF log says produced it: the driver's name, its version, where to read about it, and the prefix its own properties carry. sec-af's is SecAfTool, which the goldens hold byte for byte; codeaf's program names itself (internal/secaf's sec), because a code-scanning tool shows the driver's name beside every result, and the program a person ran is sec.

Jump to

Keyboard shortcuts

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