approval-engine flagged the class one message earlier -- a contract whose examples contradict its prose gets implemented as its examples -- and yesterday's package was a fresh instance of it, committed while flagging it. The published rule required context.approval.status == "approved" and counted context.approval.approvals[].subject_id. Neither field exists. approval-engine's approval_claim.schema.json has `state` (whose operative value is `valid`, not `approved`) and carries no approver list at all. The rule was unsatisfiable: every live destroy would have denied dual_control_required no matter how good the approval was. It failed closed, so it was never a hole, but it was policy written against a shape of our own devising rather than a published one. The rule now consumes valid_now from the real claim, guarded on kind and issuer. valid_now is the summary predicate that already folds in the distinct-approver threshold, with reason_code insufficient_approvers for a claim that failed it -- so this is also the correct layering, not just the correct shape. Counting approvers here is exactly the duplication GH-DEC-2026-005 removes; the compensating property is reconstructability at the issuer under 9.6, which is approval-engine's. Recorded as a correction section in the package and the vocabulary doc rather than quietly rewritten. 25 Rego tests and 29 fixtures pass, covering insufficient_approvers, consumed, revoked, approved-but-not-yet- valid, foreign issuer, and wrong kind. Two things the package deliberately does not do, both now written down: it does not compare binding.pdp_digest, because the request digest is computed after policy evaluation and a Rego rule cannot see it; and it makes no cross-check that the claim was approved for this action and target, because the claim's binding uses approval-engine's vocabulary and no mapping between the two is published. Inventing one would silently accept a claim approved for something else. Both belong to the PEP until a mapping exists, and that is worth closing before SECRETS-WP-0007-T04 makes destroy reachable. Also swept the other published fixtures on approval-engine's reasoning. One more instance: the inner decision in examples/caring/action_authorization.json declared contract_version flex-auth.decision-record.v1 while its provenance omitted policy_package_digest, registry_snapshot_digest, and input_claim_digests -- all published contract fields since 2026-09-02. Completed. The remaining example context vocabularies are consumer-owned and match their integrations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JTbVXpEiXA7mNJVpDnEPcB Assistant: claude-code Assistant-Model: opus Assistant-Process: 412054@bnt-lap001 Assistant-Session: 3968fae1-8d59-4209-9bd6-c22594b8ab19
36 lines
1.5 KiB
Markdown
36 lines
1.5 KiB
Markdown
# secrets-engine example
|
|
|
|
Policy package, manifests, and fixtures for `secrets-engine`'s gated
|
|
catalog-lane operations. Opened by `FLEX-DEC-2026-005`, carried by
|
|
`FLEX-WP-0021`.
|
|
|
|
| File | What it is |
|
|
| --- | --- |
|
|
| `policy_package.md` | `secrets-engine.catalog-lane.lifecycle` v1, `allow_ttl: 15m` |
|
|
| `protected_system_manifest.yaml` | the `secret-catalog-lane` resource type and twelve actions |
|
|
| `subject_manifest.yaml` | the single `secrets-engine` service identity |
|
|
| `registry_snapshot.json` | loadable snapshot combining both manifests |
|
|
| `policy_fixtures.yaml` | 29 fixtures — 11 allows, dual control both ways, and every denial branch |
|
|
| `check_request_*.json` | standalone requests for `POST /v1/check` |
|
|
|
|
The action vocabulary is **secrets-engine's**, delivered under
|
|
`FLEX-WP-0021-T01` and recorded in
|
|
[`../../docs/secrets-engine-action-vocabulary.md`](../../docs/secrets-engine-action-vocabulary.md).
|
|
Read that before changing any action string here.
|
|
|
|
## Verify
|
|
|
|
```bash
|
|
go run ./cmd/flex-auth validate -kind policy -file examples/secrets-engine/policy_package.md
|
|
go run ./cmd/flex-auth load-registry -file examples/secrets-engine/registry_snapshot.json
|
|
```
|
|
|
|
25 Rego tests and 29 fixtures.
|
|
|
|
## Not yet deployed
|
|
|
|
There is no `flex-auth-secrets-engine` pin yet (`FLEX-WP-0021-T04`), so
|
|
secrets-engine has no address to call. Their policy pin
|
|
(`SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE` / `_VERSION`) stays **unset and
|
|
fail-closed** until `FLEX-WP-0021-T05` hands them the published package and the
|
|
Service DNS. Do not configure it from this directory.
|