Skip to main content

Contract-First Schemas

Stave uses contract-first JSON schemas so validation is deterministic, offline, and portable across toolchains. All schemas use JSON Schema Draft 2020-12.


Schema Versions

ContractVersionSchema ID
Controlctrl.v1urn:stave:schema:control:v1
Observationobs.v0.1urn:stave:schema:observation:v1
Snapshot (external producer)n/aurn:stave:schema:snapshot:external
Outputout.v0.1urn:stave:schema:output:v1
Findingv1urn:stave:schema:finding:v1
Diagnosev1urn:stave:schema:diagnose:v1

Two observation schemas — one engine-internal, one for external producers. urn:stave:schema:observation:v1 is the strict wire-format the engine validates inbound snapshots against (schemas/observation/v1/observation.schema.json). urn:stave:schema:snapshot:external at docs/snapshot.schema.json is a documented producer-side contract for external tools (Terraform plan renderers, CloudFormation renderers, test-fixture generators) — the same shape, with looser language about field meaning, intended for reading by humans writing extractors. Use the strict schema for validation; reference the external schema for documentation.

Version strings vs schema URNs. The Version column carries the user-facing wire-format identifier emitted in document schema_version fields (e.g. out.v0.1 lands in the JSON output under "schema_version": "out.v0.1"). The Schema ID column carries the internal URN the schema registry compiles each contract under. The two evolve independently: a wire-format revision (e.g. out.v0.2) does not require a new URN if the schema document is backward-compatible, and a URN bump (urn:…:v2) does not require all consumers to switch wire versions in lockstep. Forward-compatibility note: both obs.v0.1 and a future obs.v1 are accepted by the loader so producers can ship the new wire string ahead of consumer rollout.


Control Contract (ctrl.v1)

A control defines a safety check. Required fields:

FieldTypeRequiredDescription
dsl_versionstringyes"ctrl.v1"
idstringyesUnique ID (e.g., CTL.S3.PUBLIC.001)
namestringyesShort human-readable name
descriptionstringyesWhat unsafe condition this detects
typestringyesCheck category (e.g., unsafe_state, authorization_boundary)

One of:

FieldDescription
unsafe_predicateInline predicate logic (any/all + field operators)
unsafe_predicate_aliasNamed alias expanded at load time (e.g., s3.is_public_readable)

Optional fields:

FieldTypeDescription
versionstringControl document version
domainstringGrouping label (exposure, governance, access)
scope_tagsarrayApplicability tags (aws, s3, prod)
severitystringcritical, high, medium, low, info
complianceobjectFramework mappings (cis_aws_v1.4.0: "2.1.1")
paramsobjectValues for value_from_param in predicates
exposureobjectExposure classification (type + principal_scope)
remediationobjectFix guidance (description, action, example)

See Evaluation Semantics for predicate operators and matching rules.


Observation Contract (obs.v0.1)

A point-in-time snapshot of asset state. The directory loader accepts two file shapes: a flat per-timestamp JSON object (one snapshot per file, fields below) or a bundle file with {"schema_version":"obs.v0.1","snapshots":[{…},{…}]} that expands inline. Per-timestamp files run the strict obs.v0.1 schema validator; bundle files route through ParseBundle and skip per-file validation. The single-snapshot stdin/composition path requires per-timestamp shape and errors explicitly on bundles.

FieldTypeRequiredDescription
schema_versionstringyes"obs.v0.1"
captured_atstringyesRFC 3339 capture time
assetsarrayyesAsset state objects
generated_byobjectnoExtraction metadata
identitiesarraynoIAM identity objects

Each asset: id, type, vendor, properties (required), source (optional).

See Observation Contract for the full field dictionary.


Output Contract (out.v0.1)

Evaluation output. Two kinds distinguished by the kind field:

Evaluation output (kind: "ASSESSMENT")

FieldTypeRequiredDescription
schema_versionstringyes"out.v0.1"
kindstringyes"ASSESSMENT"
runobjectyesRun metadata (tool version, timing, parameters)
summaryobjectyesAggregate counts (violations, assets, controls)
findingsarrayyesIndividual violation findings

Verification output (kind: "ATTESTATION")

FieldTypeRequiredDescription
schema_versionstringyes"out.v0.1"
kindstringyes"ATTESTATION"
runobjectyesRun metadata
summaryobjectyesBefore/after counts
resolvedarrayyesFindings resolved between runs
remainingarrayyesFindings still present
introducedarrayyesNew findings since baseline

Finding Contract (v1)

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

Required fields:

FieldTypeDescription
control_idstringControl that was violated
control_namestringHuman-readable control name
control_descriptionstringWhat was detected
asset_idstringAsset that violated the control
asset_typestringAsset type (storage_bucket)
asset_vendorstringCloud vendor (aws)
evidenceobjectTemporal proof of violation
remediationobjectFix guidance

Optional fields:

FieldTypeDescription
sourceobjectSource file + line reference
fix_planobjectMachine-readable fix actions
exposureobjectExposure classification (type + principal_scope)
posture_driftobjectTemporal pattern (persistent, degraded, intermittent) + exposure window count

Evidence structure

FieldTypeDescription
first_unsafe_atstringRFC 3339 timestamp of first unsafe observation
unsafe_duration_hoursnumberHours continuously unsafe
threshold_hoursnumberMax-unsafe threshold that was exceeded
reasonstringWhy the asset is unsafe
valueanyMatched field value (optional)
source_evidencearraySnapshot source references (optional)

Remediation structure

FieldTypeRequiredDescription
descriptionstringyesHow to fix the condition
actionstringyesSpecific action to take
examplestringnoExample command or config

Schema Layout

schemas/
control/v1/control.schema.json
observation/v1/observation.schema.json
output/v1/output.schema.json
finding/v1/finding.schema.json
diagnose/v1/diagnose.schema.json

Embedded Runtime Schemas

The CLI embeds schemas in internal/contracts/schema/embedded/ for offline use. Programmatic access:

schema.LoadSchema(kind, version)

Supported kinds: control, observation, finding, output, diagnose.

Validate vs Lint

CommandPurpose
stave validateSchema conformance (structural contract validity)
stave lintAuthoring quality (design conventions, determinism)

Deterministic Guarantees

  • Offline-only schema loading (embedded files).
  • Deterministic diagnostic ordering.
  • Stable lint output format: path:line:col RULE_ID message.

Polyglot Validation

Schemas are published as versioned JSON files. Non-Go tools can validate the same contracts without Stave runtime dependencies.