Skip to content

Give the backdoor its own rulebook, so it stops mismatching the front one - #761

Merged
xmap merged 1 commit into
mainfrom
backdoor-policy
Sep 1, 2026
Merged

Give the backdoor its own rulebook, so it stops mismatching the front one#761
xmap merged 1 commit into
mainfrom
backdoor-policy

Conversation

@xmap

@xmap xmap commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Item 1 from the deferred list on #760: reading 2-BM's shadow log after the Conduit + Surface fixes landed found that 99.998% of a 152,000-event window was every in-process call (RunWitness, the two capture readers, the scan ingestor, the inference recorder) mismatching the one configured Policy's surface binding, drowning out anything a real front-door near-miss would show. The reason: every in-process call now carries SYSTEM_IN_PROCESS_SURFACE_ID (#760), but the deployment's one Policy is bound to the HTTP door, and evaluate strict-matches surface. There was no way to give the backdoor its own rules, because Settings.trust_policy_id and Policy.surface_id are both single scalars.

What ships

The small option, not the general one. Policy.surface_id stays a scalar — widening it to govern multiple surfaces at once is deferred until there's live MCP traffic to validate that shape against. Instead, TrustAuthorize gets a second, optional configured policy:

  • Settings.trust_in_process_policy_id: UUID | None = None — mirrors trust_conduit_id's shape from Let a deployment name its one real Conduit, so the verdict log can populate #759 exactly: an opt-in default for the UNSPECIFIED case, never an override.
  • TrustAuthorize._effective_policy_id(surface_id) resolves which policy governs a call: the backdoor one when both a backdoor policy is configured AND the call arrived via SYSTEM_IN_PROCESS_SURFACE_ID, the front one otherwise. Every log line and Verdict row is stamped with whichever policy actually governed, so a reader can tell them apart.
  • Two new boot guards close the same "looks wired, governs nothing" gap the conduit knob already guards against: build_authorize refuses to boot when a backdoor policy is configured with no front policy to anchor it (same shape as the existing conduit guard); verify_in_process_policy_matches_surface refuses to boot when the configured backdoor policy doesn't actually govern the in-process surface, or (once trust_conduit_id is set) the right conduit — either misconfiguration would deny every in-process call at the surface/conduit check, indistinguishable from having no backdoor policy at all.
  • promote_seeded_fleet now always promotes through AllowAllAuthorize, matching pilot_seed.py's own kernel construction, instead of the caller's kernel.authz. It's a rare, explicitly-operator-run bulk recovery outside every request surface — it shouldn't need enrollment in whichever policy ends up governing the in-process door just to run.

What this doesn't change

Every existing deployment and test: trust_in_process_policy_id defaults to None, so an in-process call keeps resolving to the one front policy exactly as it does today (and, under the starter Policy currently shadowing at 2-BM, still mismatches on surface — this PR gives a deployment the option to fix that, "opening the notebook" with real policy content is a separate, operational next step).

Verification

Unit: full suite green (14,695 passed). Architecture + contract: 37,860 passed, 639 skipped. Integration (real Postgres testcontainers): 1,367 passed. ruff, pyright, tach, make docs-build all clean.

Mutation-verified every new conditional myself: inverting the surface comparison in _effective_policy_id, disabling each new boot guard's raise individually, and reverting promote_seeded_fleet's gate-bypass — each turns exactly its paired test(s) red.

Co-Authored-By: Claude Sonnet 5 (1M context) noreply@anthropic.com

… one

Every in-process call (RunWitness, the capture readers, the inference
recorder, promote_seeded_fleet) now carries SYSTEM_IN_PROCESS_SURFACE_ID
per #760, but the deployment's one configured Policy is bound to the HTTP
door, so every one of those calls strict-denies at the surface check.
Reading 2-BM's shadow log confirmed it: 99.998% of a 152,000-event window
was exactly this mismatch, drowning out anything a real front-door
near-miss would show.

Gives the in-process door its own second, optional rulebook instead of
widening Policy itself (Policy.surface_id stays a scalar; that general
multi-surface case is deferred until MCP traffic exists to validate it
against). TrustAuthorize resolves which configured policy governs a call
from its surface_id, mirroring the trust_conduit_id shape from #759:
Settings.trust_in_process_policy_id, default None, existing deployments
and tests unaffected. Two new boot guards close the same "looks wired,
governs nothing" gap the conduit knob already guards against: a backdoor
policy set without a front one, and a backdoor policy that doesn't
actually govern the in-process surface (or, once trust_conduit_id is set,
the right conduit).

promote_seeded_fleet now always promotes through AllowAllAuthorize rather
than the caller's kernel.authz, matching pilot_seed.py's own kernel
construction -- it is a rare, explicitly-operator-run bulk recovery
outside every request surface, and should not need enrollment in
whichever policy ends up governing the in-process door to run at all.

Co-Authored-By: Claude Sonnet 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  apps/api/src/cora/agent
  promote_seeded_fleet.py
  apps/api/src/cora/api
  main.py
  apps/api/src/cora/infrastructure
  config.py
  apps/api/src/cora/trust
  _bootstrap.py
  authorize.py
  build_authorize.py
Project Total  

This report was generated by python-coverage-comment-action

@xmap
xmap merged commit f41731d into main Sep 1, 2026
19 checks passed
@xmap
xmap deleted the backdoor-policy branch September 1, 2026 00:34
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