Skip to content

fix: enforce governed Desktop egress boundaries - #116

Draft
abrichr wants to merge 5 commits into
mainfrom
codex/security-raw-egress-boundary
Draft

fix: enforce governed Desktop egress boundaries#116
abrichr wants to merge 5 commits into
mainfrom
codex/security-raw-egress-boundary

Conversation

@abrichr

@abrichr abrichr commented Aug 18, 2026

Copy link
Copy Markdown
Member

Outcome

This draft closes reproduced Desktop raw-egress, credential, policy-cache, hosted-handoff, and experimental Runner safety defects.

  • Hosted push delegates to Flow. Direct hosted adapters refuse network egress.
  • The Desktop accepts only the closed openadapt.push-result/v1 result. It retains review, accepted-ingest, and uncertain-delivery handoffs with exact server and artifact bindings.
  • Hosted credentials and cached organization policy bind to the canonical destination origin and principal.
  • The policy cache rejects stale, tampered, cross-host, cross-principal, cross-organization, and same-version authority changes.
  • Sanitized derivative tree hashes use type-aware, length-delimited records. The queue freezes only the exact reviewed bytes.
  • External URLs pass structured validation before the native opener receives them.
  • The experimental Runner journals the pre-action boundary durably, requires start confirmation, enforces lease expiry, renews active leases, serializes actuation, and treats crash or lease uncertainty as uncertain.
  • Runner bundle staging validates the digest path and URL, bounds archive input, rejects traversal, links, and special members, and publishes the staged directory atomically.
  • Runner callbacks remove Flow free text. Only controlled identifiers, digests, booleans, timing, and counts can cross the evidence boundary.
  • The legacy runner lane no longer reports confirmed from process exit code zero. Exit code zero proves only that the local process returned, not the governed effect. Until this lane consumes Flow's shared qualification-v2 verifier and binds an exact signed VERIFIED result to the run, authorization, policy, identity, effect, and event sequence, a completed run terminates halted-needs-attention with a constant completion-proof reason and lands in the operator's local needs-attention list.

Reproduced failures

Focused tests first reproduced these four queue defects:

  1. A corrupt started journal could re-execute the run.
  2. An expired lease could execute.
  3. A failed start-evidence request could still permit GUI action.
  4. Concurrent ticks could actuate two jobs at the same time.

The new tests also cover lease-renewal expiry, ZIP traversal and symlinks, invalid digest paths, remote clear-text staging URLs, signed-query error redaction, and free-text halt suppression.

Exact-head validation

Head: b8d8648f9f78e008f1e60f513c76cf9e89221a84

  • Python: 990 passed, 1 skipped
  • UI: 72 passed
  • TypeScript and Vite production build: passed
  • Rust: 14 passed, 1 ignored
  • Ruff, rustfmt, and diff checks: passed
  • Frozen sidecar artifact: passed
  • Frozen browser lifecycle: 11 steps; zero model calls; zero silent incorrect successes; COMPLETED_UNVERIFIED, correctly not production-eligible
  • Wheel and sdist inspection: passed
  • Release consistency: passed at 0.15.0
  • Source boundary: passed, policy digest sha256:09e5092a6f84cbad0b588a9aec65cc7d26492dced2ddce26ca288a3ff81992c9

Draft release dependency

Do not merge or release this PR with the current Flow pin. The published Flow 1.31.0 wheel is immutable and does not contain schemas/push-result-v1.json. This branch still freezes Flow 1.27.1.

The required order is:

  1. Merge and publish the next Flow release that contains the reviewed push-result contract.
  2. Review the exact Cloud managed-runtime candidate URL, SHA-256, and commit.
  3. Deploy and acknowledge that runtime upgrade.
  4. Update the allowed compiler version.
  5. Requalify the managed workflow and prove live acceptance.
  6. Update Desktop's exact Flow pin, lock, documentation, artifact inventory, and qualification evidence.

The PR remains a draft until this sequence and the independent exact-head security review pass.

Comment thread engine/policy.py Fixed
The experimental runner lane mapped FlowBridge exit code 0 straight to a
`confirmed` terminal outcome. Exit code zero proves only that the local
process returned; it does not prove the governed effect. This lane does not
yet consume Flow's shared qualification-v2 verifier, so it cannot bind an
exact signed VERIFIED result to the run, authorization, policy, identity,
effect, and event sequence.

Until it can, a run that completes without a Flow halt terminates as
`halted-needs-attention` with the constant reason
COMPLETION_PROOF_REQUIRED_REASON. The reason crosses the ack boundary and
the local journal verbatim, and the run is mirrored into the operator's
local needs-attention list (kind `completion_proof_missing`) so it cannot
pass silently. `confirmed` never leaves this path.

- A real Flow halt keeps its own structural halt event and reason path.
- A non-zero exit stays `failed`.
- No halt evidence event is fabricated for the completion-proof case.

Tests: the happy-path, signed-URL staging, and admin-toggle tests now assert
the fail-closed contract; a new TestCompletionProof class covers the status,
reason, journal, local mirror, PHI-free constant, halt precedence, and
failed-exit paths. This is a temporary fail-closed boundary, not the final
path: the lane still has to move to the Flow Connector contract and the
frozen signed terminal-v2 result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

2 participants