net-kingdom/tools/security-case-types
tegwick 015694ee41
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(cases): validate optional exact machine descriptor pins
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 21:23:04 +02:00
..
tests fix(cases): validate optional exact machine descriptor pins 2026-10-16 21:23:04 +02:00
README.md fix(cases): validate optional exact machine descriptor pins 2026-10-16 21:23:04 +02:00
security_case_evidence.py fix(cases): validate optional exact machine descriptor pins 2026-10-16 21:23:04 +02:00
security_case_validator.py fix(cases): validate optional exact machine descriptor pins 2026-10-16 21:23:04 +02:00

security-case-types tools

Validator and renderer for SecurityCaseTypes and SecurityCases (canon/standards/security-case-types_v0.1.md, schemas canon/schemas/security-case-type_v0.1.schema.json and security-case_v0.1.schema.json).

# a type directory: type.yaml, README.md sections, tests, example cases
python3 tools/security-case-types/security_case_validator.py validate-type security-case-types/<type-id>

# a case against its type (security-case-types/<type-id>/type.yaml)
python3 tools/security-case-types/security_case_validator.py validate-case <case.yaml> --types security-case-types

# render a case into the composer's plan plus materialization, follow-through,
# verification and rollback; execution is never permitted
python3 tools/security-case-types/security_case_validator.py render <case.yaml> \
  --types security-case-types capabilities/playbooks/*.yaml

Only implemented types accept cases. --allow-unimplemented exists for a type's own example cases while the type is being written and acknowledged.

The validator refuses, among other things: missing sections, unknown or unpinned capabilities, attended steps without justification, steps or materialized items without a rollback, verification without a negative check or that reads a value, templates with unknown parameters, credential-shaped values anywhere, secret parameters that are not custody references, and high-risk types without founder acceptance.

To start a type: copy security-case-types/_template/, rename the directory to the type id, and rewrite every section. The template's tests travel with it: rename tests/test_type.py to tests/test_<type_id>_contract.py so module names stay unique.

Tests: python3 -m pytest tools/security-case-types/tests security-case-types/*/tests.

Explicit source versions

The default --types root is unchanged. Select a separately acknowledged source version explicitly, without moving its package into the default root:

python3 tools/security-case-types/security_case_validator.py validate-case \
  security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml \
  --types security-case-types \
  --version-root 1.2=security-case-type-revisions/1.2

This ordinary command refuses:1.2 is acknowledged, not implemented. For source-only preparation, the existing --allow-unimplemented option may be added; its render is deterministic and execution.permitted remains false. Current canonical1.1 is also acknowledged and its historical accepted case/normal refusal/preparation render remain exactly retained. No source acknowledgment or historical case acceptance is an implementation/native proof waiver.

The Python API is load_type(default_root, exact_reference, version_roots={"1.2": explicit_root}). Each key must be an exact major.minor and each root a Path. CLI --version-root VERSION=PATH may repeat for DIFFERENT versions. A matching explicit version selects exactly one root; a missing/wrong/ambiguous source refuses without trying the default or another revision. Versions without a mapping continue using --types. No directory discovery, highest/latest selection, status promotion or automatic owner-adapter adoption occurs. Duplicate mappings (even identical), duplicate YAML fields, mismatched source ID/version, malformed/traversal references and selected symlinks refuse. Direct case validation also requires the case reference to match the supplied type ID/version.

An explicit root is source input, not an owner acknowledgment or grant. Callers retain exact source hashes/type/case/render in their own reviewed receipts. Existing two-argument load_type callers, including ops-mason, retain their default behavior until their owner deliberately adopts the optional input. Adapter/global provenance/native first-reference gates remain separate in NK-WP-0048-T06 and the existing ORGREF driver.

Check existing owner evidence compatibility

The normal validator CLI now accepts check-evidence using the same exact type selection, declarations, validation and deterministic render as render:

python3 tools/security-case-types/security_case_validator.py check-evidence \
  security-cases/forgejo-netkingdom-oidc.yaml --types security-case-types \
  --structure-request /path/to/mason-structure-request.json \
  --warden-journal /path/to/existing/journal.sqlite

Normal admission still refuses the acknowledged 1.1 and 1.2 types. Explicit --allow-unimplemented permits source preparation, with the existing --version-root 1.2=security-case-type-revisions/1.2 for that version. No owner protocol is automatically adopted, no journal is created, and no status changes.

This is the cross-owner compatibility preflight, not native acceptance. It consumes the existing ops-mason.case-structure-request.v1 and reads latest rows from the existing warden.case.step-journal.v1 SQLite journal in read-only mode. Mason source/request hashes, complete current structural inventory and structural projection must match the fresh render. Warden case/type and type-declared machine descriptor pins, owners, bounded histories, created-object scope and successful attempt/revocation fingerprints must match. Unknown or duplicate fields, source substitution and missing completed-attempt fingerprints refuse. Running, uncertain, failed or rolled-back outcomes retain their exact meanings; an earlier success never overrides the latest journal row. Generated-value paths require distinct parent-session and broker-grant fingerprint fields.

Exit 0 means these supplied artifacts are source-compatible; it never means the case is complete. No artifact is required solely to render missing gates. Output always has native_complete: false, execution.permitted: false, and explicit unresolved native gates. A Mason Request has no native Observation provenance; a Warden journal retains fingerprints rather than portable signed/native proof. This command deliberately offers no trust callback, native-success flag, dispatch or way to promote self-authored JSON into native evidence. Actual independent owner evidence admission, status-hash binding, accepted machine descriptors, delivery, human sign-in/consumer denial, revocation and created-only rollback remain NK-WP-0048-T06 owner integration work. It does not mark any type implemented.

Integration tests invoke actual sibling Mason prepare and Warden Journal.save with metadata fixtures only. They need those owner source checkouts, and existing type suites need the public KeyCape request file and provider declarations beside the checkout. NET_KINGDOM_ROOT selects the source root for the 1.2 package tests.

Machine descriptor source pins

The optional spec.execution_descriptors map uses the existing Warden kernel's step-to-exact-descriptor-byte SHA-256 contract. The JSON schema accepts at most 128 lowercase sha256:<64 hex> pins. The semantic validator additionally requires every key to name a declared follow-through step. Malformed maps are refused by the direct evidence API too. Absent and partial maps remain legal for source preparation; missing steps remain explicit in the evidence report.

A valid pin is source metadata. It does not authenticate its owner, acknowledge a machine seam, admit an adapter or change the implemented-type requirement. The existing browser types contain no descriptors; their bytes and lifecycle states are unchanged. Owner descriptor/provenance acceptance and actual native receipts remain prerequisites to execution and acceptance.