feat(policy): capability field + opt-in fail-closed exposure (audit #31, P2)#33
Merged
Merged
Conversation
… (audit #31, P2) Two structural weaknesses in the policy schema, fixed without breaking back-compat: 1. NO FIRST-CLASS CAPABILITY LABEL. Adds an optional `capability` field at the route level. When set, it propagates onto `PolicyCompiler.CompiledRule` so downstream consumers (audit log, future chimichanga attenuation, the new EgressPolicy seam in audit/egress-mode-scaffold) can read it. Validator rejects empty strings and non-strings; nil/omitted is back-compat. 2. parse_exposure WAS UNCONDITIONALLY FAIL-OPEN. Existing behaviour: `parse_exposure("typo") -> :public`. Documented as intentional but combined with the `Map.get(route, "exposure", "public")` compiler default this means an omitted-or-typoed exposure silently makes the route public. Adds an opt-in `:exposure_fail_closed = true` flag that flips unknown values to `:internal` (most restrictive). Default remains fail-open for back-compat; this is opt-in for environments where confidentiality is weighted above availability (e.g., neurophone egress). Test coverage: * PolicyValidator: capability accept (non-empty, omitted) / reject (empty, non-string) * PolicyCompiler: capability propagation onto CompiledRule * SafeTrust: default-fail-open, opt-in-fail-closed, known-values-unchanged Refs: #31 (self-audit, priority 2)
3 tasks
🔍 Hypatia Security ScanFindings: 65 issues detected
View findings[
{
"reason": "Issue in boj-build.yml",
"type": "missing_timeout_minutes",
"file": "boj-build.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in casket-pages.yml",
"type": "missing_timeout_minutes",
"file": "casket-pages.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in casket-pages.yml",
"type": "missing_timeout_minutes",
"file": "casket-pages.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql.yml",
"type": "missing_timeout_minutes",
"file": "codeql.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in governance.yml",
"type": "missing_timeout_minutes",
"file": "governance.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
hyperpolymath
added a commit
that referenced
this pull request
Jun 2, 2026
…audit #31, P3) (#34) Pure documentation — no code change. Adds docs/CAPABILITY-INTEGRATION.md describing the contract surfaces by which the gateway connects (or, in v0.x, *will connect*) to: * the estate capability model (chimichanga capability attenuation, boj-server cartridges already partially wired via PolicyLoader.load_from_boj_catalog/1) * service discovery via groove-protocol Documented as a CONTRACT, not a feature list, because: 1. The cross-repo contracts are still stabilising 2. The compiler-side schema change is in flight in #33 3. The egress mode in #32 is the more urgent consumer Also extends PROOFS_NEEDED.md with the two open obligations and a fresh echo-types record-as-not-relevant audit per estate convention. Refs: #31 (self-audit, priority 3), related to #32, #33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Audit issue: #31 (priority 2 — policy schema is allowlist-shaped but shallow).
Two structural weaknesses in the policy DSL, fixed without breaking
back-compat:
No first-class capability label. Today the only capability binding
is via the implicit trust-level total order in
SafeTrust. Adds anoptional
capabilityfield at the route level and propagates it ontoPolicyCompiler.CompiledRuleso downstream consumers (audit log,future chimichanga-style attenuation, the new
EgressPolicyseam infeat(egress): draft EgressPolicy schema + decide/3 (audit #31, P1) #32) can read it.
parse_exposureis unconditionally fail-open. Documented asintentional but combined with the
Map.get(route, \"exposure\", \"public\")compiler default this means a typoed or omitted exposure silently makes
the route public. Adds an opt-in
:exposure_fail_closed = trueflagthat flips unknown values to
:internal(most restrictive level).Default remains fail-open for back-compat; this is opt-in for
environments where confidentiality is weighted above availability
(e.g., neurophone egress).
Diff: 4 files, +173 / -5 LoC (under the 300-LoC PR ceiling).
Test plan
mix test test/policy_capability_test.exsmix test— confirm no existing tests broke (capability defaults tonil so all existing CompiledRule callers continue to work)
parse_exposure(\"typo\")returns:publicby default and:internalwhen:exposure_fail_closedis setEcho-types audit
record-as-not-relevant. Capability label is a passive string in v1; itdoes not interact with echo types. Re-check when chimichanga attenuation
attaches to it.
Refs: #31, related to #32