Skip to content

docs: HMAC v2 promote runbook, status pairing detector, PIV pin honesty - #31

Draft
cursor[bot] wants to merge 2 commits into
mainfrom
cursor/engineering-documentation-updates-c9e3
Draft

cursor[bot] wants to merge 2 commits into
mainfrom
cursor/engineering-documentation-updates-c9e3

Conversation

@cursor

@cursor cursor Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Why

#25 (HMAC v2) and the pins-only slice of #27 landed on main after the 2026-08-31 docs pass. Draft #29 still describes v1-only tokens. Draft #30 (2026-09-07) had the v2 runbook but never merged, so main still listed 7 CI suites and had no operator mint/promote path. #27's title is easy to over-read as a hardware signer plus SSH/NETCONF/Batfish.

This is documentation only. Behavior is verified against serve.py, core/promote/{tokens,gate,promote,connectors}.py, core/seal/{pins,signing}.py, evidence/{oscal,cab}.py, and .github/workflows/test.yml.

Supersedes draft #29 and draft #30.

Docs added/updated

  • docs/DEVELOPER.md — §4 v1+v2 token contract; §5 GET /api/status field table; §7 HMAC approval + promote runbook (curl, TTL, pairing table, status detector, digest recompute, live inventory override, connector HTTP codes); §8 PIV pins (step 0 only).
  • docs/EVIDENCE.md — OSCAL/CAB field contract, filenames, intents_that_hold rule, to_oscal/to_cab do not verify.
  • docs/ARCHITECTURE.md — component map + §6 gate notes; new §11 exports, §12 HMAC v2 + status detector, §13 PIV pins; tech-stack CI count 9.
  • docs/PIV_HARDWARE_SIGNER_PLAN.md — step 0 pins landed; ECDSA helpers / PivSigner / C_Sign did not.
  • docs/index.html — Pages honesty for HMAC v2, pairing hole, inert live connector, OSCAL/CAB limits, pins.py; quickstart lists all nine CI suites.
  • docs/GO_LIVE.md, docs/PHASES.md, README.md, CHANGELOG.md — pointers, triage rows, pairing-hole note, complete CI command list.

Codepaths covered

  • GET /api/status (api_auth, approve_hmac, seal, egress)
  • POST /api/approve/mint (bundle → v2, hash-only → v1), POST /api/preflight/promote (inventory_sha256 override)
  • core/promote/tokens.py v1 + v2 (c config digest, inv inventory fingerprint)
  • core/promote/gate.py G1–G5 (G1 is bundler.verify, not verify_seal)
  • core/promote/connectors.py (dry_run default; live is DisabledLiveConnector → HTTP 500)
  • core/seal/pins.py compiled-in Yubico root fingerprint only
  • POST /api/preflight/evidence/{oscal,cab} via _verified_bundle

Knowledge gaps addressed

  • How to mint a v2 token and dry-run promote on community :8088
  • How to see the pairing hole: GET /api/status returns api_auth=open + approve_hmac=required
  • How to recompute config_digest / inventory_digest when a v2 token dies on drift
  • v2 dies on config or inventory drift, including a live inventory_sha256 override
  • AEGIS_APPROVE_KEY without AEGIS_API_KEY is still an unauthenticated mint on main (do not treat draft fix: refuse HMAC mint when API auth is unset #28 as shipped)
  • feat: PIV step-0, audited SSH/NETCONF connector, Batfish sidecar #27 shipped pins only — not PivSigner, ECDSA raw→DER helpers, SSH/NETCONF, or a Batfish sidecar
  • OSCAL is AEGIS-shaped AR, not a FedRAMP package; CAB rollback was not executed in the twin
  • connector=live is HTTP 500; unknown connector names are 400; CI is 9 suites (README now lists twin_test + api_test)

Out of scope

Unmerged draft #28 (startup refuse HMAC-without-API-key). Did not invent SSH/NETCONF or Batfish sidecar docs from the #27 PR title.

Open in Web View Automation 

Summary by Sourcery

Bring the project documentation in line with the shipped HMAC v2, promotion, evidence-export, CI, and PIV step-0 behavior while clearly documenting current security and implementation limitations.

Enhancements:

  • Document the HMAC v1/v2 approval and promotion contracts, including configuration and inventory binding, status-based pairing detection, drift troubleshooting, and connector behavior.
  • Clarify OSCAL and CAB evidence export fields, verification boundaries, and honesty constraints.
  • Correct project documentation to reflect nine CI suites and provide the complete operator and developer workflows.
  • Document the scope of the landed PIV step-0 root pin while explicitly separating it from the unimplemented hardware signer and related integrations.

Documentation:

  • Expand the developer, architecture, evidence, go-live, phases, README, changelog, hardware-signer plan, and Pages documentation with current operational behavior and limitations.

Tests:

  • Extend API documentation tests to cover unknown connectors and the live connector's 403/partial-response contract.

Operators still had no mint/promote curl path for v2 tokens after #25/#27.
ARCHITECTURE still listed 7 CI suites, and #27's title is easy to over-read
as a hardware signer plus SSH/NETCONF/Batfish.

Adds the pairing-hole detector on GET /api/status, a local
config/inventory digest recompute for v2 deny debug, connector HTTP
codes, and the two CI commands the README table listed but the
copy-paste omitted. Supersedes draft #29 and #30.

Verified against serve.py, core/promote/{tokens,gate,promote,connectors}.py,
core/seal/{pins,signing}.py, evidence/{oscal,cab}.py, and test.yml.

Co-authored-by: georgy75 <georgy75@gmail.com>
@sourcery-ai

sourcery-ai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Reviewer's Guide

Documentation-only PR that promotes the HMAC v2 operator runbook, exposes the current HMAC/API-key pairing hole through the status contract, specifies OSCAL/CAB evidence limitations, accurately scopes PIV work to compiled-in pins, and synchronizes CI and feature references across the documentation set.

Sequence diagram for HMAC v2 mint and dry-run promote

sequenceDiagram
    actor Operator
    participant Server as serve.py
    participant Tokens as core/promote/tokens.py
    participant Gate as core/promote/gate.py
    participant Connector as core/promote/connectors.py

    Operator->>Server: POST /api/approve/mint
    Server->>Tokens: mint_token_for_bundle()
    Tokens-->>Server: v2 token with config_digest and inventory_digest
    Server-->>Operator: token
    Operator->>Server: POST /api/preflight/promote
    Server->>Gate: evaluate()
    Gate->>Tokens: verify_approval()
    Tokens-->>Gate: v2 approval result
    Gate-->>Server: GateDecision
    Server->>Connector: push()
    Connector-->>Server: dry-run result
    Server-->>Operator: promotion record
Loading

State diagram for HMAC and API-key pairing status

stateDiagram-v2
    [*] --> OpenUnverified: AEGIS_APPROVE_KEY unset
    [*] --> Paired: Both keys set
    [*] --> PairingHole: AEGIS_APPROVE_KEY set, AEGIS_API_KEY unset

    OpenUnverified: api_auth=open or required
    OpenUnverified: approve_hmac=asserted-unverified
    Paired: api_auth=required
    Paired: approve_hmac=required
    PairingHole: api_auth=open
    PairingHole: approve_hmac=required

    OpenUnverified --> [*]
    Paired --> [*]
    PairingHole --> [*]
Loading

Flow diagram for v1 and v2 approval token minting

flowchart TD
    Request["POST /api/approve/mint"] --> HasBundle{Bundle supplied?}
    HasBundle -->|Yes| V2["mint_token_for_bundle() → v2\napprover + bundle hash + config digest + inventory digest + expiry"]
    HasBundle -->|No| Hashes{Config and inventory hashes supplied?}
    Hashes -->|Yes| V2Hash["v2 token\nconfig_sha256 + inventory_sha256"]
    Hashes -->|No| V1["mint_token() → v1\napprover + bundle hash + expiry"]
    V2 --> Promote["POST /api/preflight/promote"]
    V2Hash --> Promote
    V1 --> Promote
    Promote --> Drift{v2 digests still match?}
    Drift -->|No| Deny["Deny"]
    Drift -->|Yes or v1| DryRun["DryRunConnector"]
Loading

File-Level Changes

Change Details Files
Documented the complete HMAC approval and promotion lifecycle, including v1/v2 token semantics and operational drift handling.
  • Added v2 bundle-bound claims for config and inventory digests while preserving v1 hash-only minting.
  • Added curl-based mint/promote workflow, TTL and approver constraints, digest recomputation guidance, inventory override behavior, and promotion-record fields.
  • Documented G1–G5 behavior, dry-run defaults, disabled live connector responses, and the unauthenticated HMAC/API-key pairing hole with a status detector.
docs/DEVELOPER.md
docs/ARCHITECTURE.md
docs/GO_LIVE.md
docs/PHASES.md
docs/index.html
README.md
CHANGELOG.md
Expanded evidence-export documentation with explicit field mappings and integrity/authenticity limitations.
  • Defined OSCAL Assessment Results and CAB output fields, filenames, and honesty flags.
  • Clarified that pure exporters do not verify bundles; verification occurs in the HTTP wrapper, and exports are not origin-proof or FedRAMP packages.
  • Documented rollback as unverified and the conditions under which intents are reported as holding.
docs/EVIDENCE.md
docs/ARCHITECTURE.md
docs/index.html
README.md
CHANGELOG.md
Corrected PIV hardware-signer scope and status to reflect that only compiled-in pins shipped.
  • Documented the Yubico root fingerprint, empty serial allowlist, unset pinned key identifier, and edit-and-rebuild rotation model.
  • Explicitly marked PivSigner, PKCS#11 signing, ECDSA helpers, attestation gates, SSH/NETCONF, and Batfish integration as unimplemented.
  • Updated the implementation plan and architecture/changelog references to distinguish step-0 pins from future hardware signing.
docs/PIV_HARDWARE_SIGNER_PLAN.md
docs/DEVELOPER.md
docs/ARCHITECTURE.md
docs/PHASES.md
docs/index.html
CHANGELOG.md
Aligned project-facing documentation with the current CI inventory and newly documented capabilities.
  • Corrected the CI count to nine suites and added missing twin, token, OSCAL, and API test commands to copy-paste instructions.
  • Updated README, Pages, architecture, phase, go-live, and changelog pointers for HMAC v2, evidence exports, pairing detection, and PIV-pin limitations.
README.md
docs/index.html
docs/ARCHITECTURE.md
docs/DEVELOPER.md
docs/GO_LIVE.md
docs/PHASES.md
CHANGELOG.md

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

promote() catches DisabledLiveConnector.push per device, so
connector=live after G4 is HTTP 200 status=partial, not 500.
G4 without the env stays 403. Lock the contract in api_test.

Co-authored-by: georgy75 <georgy75@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant