Skip to main content

Output Schema — out.v0.1

This page documents the evaluation output contract used by Stave. Every apply and apply --profile aws-s3 command produces JSON conforming to this structure.

The output contract is defined by Go struct types in internal/core/evaluation/ and internal/adapters/output/dto/types.go, with runtime validation against embedded JSON Schema (schemas/output/v1/output.schema.json) before emission. The schema version constant is SchemaOutput in internal/core/kernel/schema.go.

Top-Level Structure

{
"schema_version": "out.v0.1",
"kind": "ASSESSMENT",
"run": { ... },
"summary": { ... },
"findings": [ ... ],
"skipped": [ ... ],
"skipped_resources": [ ... ],
"extensions": { ... }
}
FieldTypeRequiredDescription
schema_versionstringYesAlways "out.v0.1"
kindstringYesAlways "ASSESSMENT"
runrunYesRun metadata
summarysummaryYesAggregate counts
findingsarray of findingYesDetected violations (empty array when none)
skippedarray of skipped_controlNoControls that could not be evaluated
skipped_resourcesarray of skipped_resourceNoAssets exempted by ignore rules
extensionsobjectNoExtension metadata (for example selected control source and resolved pack IDs)

run

FieldTypeRequiredDescription
tool_versionstringYesStave binary version
offlinebooleanYesAlways true (Stave is architecturally offline)
nowstring (RFC 3339)YesEvaluation timestamp (from --now or derived from last snapshot)
sla_thresholdstringYesMaximum unsafe duration threshold (e.g., "168h0m0s")
snapshotsintegerYesNumber of observation snapshots loaded
input_hashesinput_hashesNoSHA-256 hashes of input files (for auditability)

input_hashes

FieldTypeDescription
filesobjectMaps each observation filename to its SHA-256 hex digest
overallstringSHA-256 of the canonical "filename=hash\n" string (files sorted lexicographically)

summary

FieldTypeDescription
assets_evaluatedintegerNumber of assets evaluated
attack_surfaceintegerNumber of assets currently in an unsafe state
violationsintegerNumber of findings (violations)

finding

Each finding represents a single control violation for a specific asset.

FieldTypeRequiredDescription
control_idstringYesID of the violated control (e.g., "CTL.S3.PUBLIC.001")
control_namestringYesHuman-readable control name
control_descriptionstringYesWhat the control checks
asset_idstringYesID of the violating asset
asset_typestringYesAsset type (e.g., "storage_bucket")
asset_vendorstringYesCloud vendor (e.g., "aws")
sourcesource_refNoSource file reference from the observation
evidenceevidenceYesProof of the violation
control_severitystringNoSeverity level of the violated control (critical, high, medium, low, info)
control_complianceobjectNoCompliance framework mappings from the control (framework name → control ID)
remediationremediationYesRemediation guidance
fix_planfix_planNoMachine-readable deterministic fix actions

source_ref

FieldTypeDescription
filestringSource file path
lineintegerLine number in source file

evidence

Fields are populated depending on the control type.

Duration controls:

FieldTypeDescription
first_unsafe_atstring (RFC 3339)When the asset first entered the unsafe state
last_seen_unsafe_atstring (RFC 3339)When the asset was last observed unsafe
unsafe_duration_hoursnumberHours the asset has been continuously unsafe
threshold_hoursnumberMaximum allowed unsafe duration (from --max-unsafe or per-control param)

Recurrence controls:

FieldTypeDescription
exposure_window_countintegerNumber of unsafe exposure windows within the window
window_daysintegerRolling window for counting recurrence
recurrence_thresholdintegerInclusive count at which a violation fires — recurrence_threshold: 3 means 3 OR MORE exposure windows in the rolling window_days trip the control
first_exposure_window_atstring (RFC 3339)When the first unsafe exposure window started
last_exposure_window_atstring (RFC 3339)When the most recent unsafe exposure window ended

Common fields (all control types):

FieldTypeDescription
misconfigurationsarrayProperty-level unsafe conditions (property, actual_value, operator, unsafe_value)
root_causesarray of stringsMechanisms causing the violation (e.g., "policy", "acl")
source_evidencesource_evidencePointers to specific policy/ACL entries
why_nowstringHuman-readable explanation of timing context

source_evidence

FieldTypeDescription
policy_public_statementsarray of stringsSIDs or indices of policy statements granting public access
acl_public_granteesarray of stringsGrantee URIs granting public access (e.g., "AllUsers")

remediation

FieldTypeRequiredDescription
descriptionstringYesWhat the violation means
actionstringYesHow to remediate
examplestringNoExample safe configuration

fix_plan

FieldTypeRequiredDescription
idstringYesStable fix-plan identifier
targetobjectYesAsset target (asset_id, asset_type)
preconditionsarray of stringsNoConditions to verify before applying actions
actionsarrayYesDeterministic action list
actions[].action_typeenumYesset, add, remove
actions[].pathstringYesCanonical model path to change
actions[].valueanyNoValue to set/add
expected_effectstringNoExpected security effect

skipped_control

FieldTypeDescription
control_idstringID of the skipped control
control_namestringName of the skipped control
reasonstringWhy the control was skipped

skipped_resource

FieldTypeDescription
asset_idstringID of the skipped asset
matched_patternstringIgnore pattern that matched
reasonstringExemption reason

rows[] (optional, --explain-all)

When --explain-all is enabled, each row represents one (control, asset) evaluation decision.

FieldTypeDescription
control_idstringControl ID
asset_idstringAsset ID
decisionenumVIOLATION, PASS, INCONCLUSIVE, NOT_APPLICABLE, SKIPPED
confidenceenumhigh, medium, low, inconclusive
evidenceevidenceEvidence (present for violations)
why_nowstringTiming explanation
reasonstringReason for SKIPPED or NOT_APPLICABLE decisions

Minimal Example

{
"schema_version": "out.v0.1",
"kind": "ASSESSMENT",
"run": {
"tool_version": "0.0.1",
"offline": true,
"now": "2026-01-11T00:00:00Z",
"sla_threshold": "168h0m0s",
"snapshots": 2
},
"summary": {
"assets_evaluated": 1,
"attack_surface": 0,
"violations": 0
},
"findings": []
}

Violation Example

{
"schema_version": "out.v0.1",
"kind": "ASSESSMENT",
"run": {
"tool_version": "0.0.1",
"offline": true,
"now": "2026-01-11T00:00:00Z",
"sla_threshold": "168h0m0s",
"snapshots": 3,
"input_hashes": {
"files": {
"2026-01-01T000000Z.json": "26770e3c...",
"2026-01-10T000000Z.json": "cce8bb1c...",
"2026-01-11T000000Z.json": "9218f381..."
},
"overall": "8761e974..."
}
},
"summary": {
"assets_evaluated": 2,
"attack_surface": 1,
"violations": 1
},
"findings": [
{
"control_id": "CTL.EXP.DURATION.001",
"control_name": "Unsafe Exposure Duration Bound",
"control_description": "An asset must not remain unsafe beyond the configured time window.",
"asset_id": "res:aws:s3:bucket:public-bucket",
"asset_type": "storage_bucket",
"asset_vendor": "aws",
"source": { "file": "infra/main.tf", "line": 42 },
"evidence": {
"first_unsafe_at": "2026-01-01T00:00:00Z",
"last_seen_unsafe_at": "2026-01-11T00:00:00Z",
"unsafe_duration_hours": 240,
"threshold_hours": 168,
"misconfigurations": [
{ "property": "public", "actual_value": true, "operator": "eq", "unsafe_value": true }
],
"why_now": "Asset has been unsafe for 240 hours (threshold: 168 hours). Unsafe since 2026-01-01T00:00:00Z."
},
"control_severity": "critical",
"control_compliance": {
"cis_aws_v1.4.0": "2.1.5",
"pci_dss_v3.2.1": "1.2.1",
"soc2": "CC6.1"
},
"remediation": {
"description": "Security control violation detected.",
"action": "Review the finding evidence and remediate the configuration."
}
}
]
}

Contract Sources

This reference is derived from the runtime output implementation: