Skip to content

feat: #297 — --disable-ocap/--yolo interim exec escape hatch#298

Merged
hartsock merged 1 commit into
mainfrom
feat/297-disable-ocap
Jun 12, 2026
Merged

feat: #297 — --disable-ocap/--yolo interim exec escape hatch#298
hartsock merged 1 commit into
mainfrom
feat/297-disable-ocap

Conversation

@hartsock

Copy link
Copy Markdown
Member

Ref #297.

What this PR does

The explicit, loud, interim bypass for the stub-shell fail-closed exec problem (#297):

Test plan

13 new tests (8 newt-core, 4 newt-tui, 1 newt-cli), all env-mutating ones serialized behind async-aware locks with RAII env restore:

  • Flag off = current behavior pinned: the stub dispatch error surfaces verbatim (error: … reubeno/brush/pull/1184).
  • Flag on: a command the stub shell fails closed on succeeds via host shell (echo yolo-okyolo-ok\n); empty output keeps the (exit N) shape.
  • Envelope parity: exit_code/stdout/stderr/sandbox_kind present, denied/denials omitted, envelope_denied reads false, shell_envelope_output formats it identically.
  • venv/PATH prefix rides the host shell (echo "$VIRTUAL_ENV" under NEWT_VENV).
  • Banner content; ocap-disabled record shape + jsonl round-trip.
  • fs fence still enforced under yolo (workspace-escape write denied, file not created; out-of-scope read denied) — in both newt-core and newt-tui suites.
  • Precedence: exec never consults the gate under yolo (panic-gate + decision-count proofs); an fs denial still prompts and an allow-once still grants.
  • NEWT_DISABLE_OCAP exact-value semantics (1 on; 0/empty/true/yes off) — the env-var-equivalence half (the flag just exports the var).
  • --disable-ocap and --yolo alias parse (bare and explicit code), off by default.
  • Corrective tool-name guard still answers before the bypass.

Gates: just check green, just cov-ci green at 90.10% (floor 80%), just shell-check green (no patch-wiring changes).

Out of scope

🤖 Generated with Claude Code

@hartsock hartsock force-pushed the feat/297-disable-ocap branch from a5eb976 to d52e440 Compare June 12, 2026 03:44
Operator-reported: on stub-shell builds (the only crates.io-publishable
configuration) agent-bridle's shell tool fails closed on every command,
so run_command cannot do agentic coding at all without the brush
CommandInterceptor patch underneath. This adds the explicit, loud,
interim bypass the issue specifies:

- newt-core: `ocap_disabled()` (NEWT_DISABLE_OCAP=1, exact-value,
  fail-closed read; env-only — deliberately NO config key) and a
  run_command bypass that executes on the plain host shell (bash -c,
  sh fallback; cmd /C on Windows) with the SAME venv/PATH prefix and
  an envelope structurally identical to the bridle one
  ({exit_code, stdout, stderr, sandbox_kind}, denied/denials omitted),
  so envelope_denied/shell_envelope_output and the loop need no changes.
- Scope: exec only. web_fetch is NOT bypassed — determined empirically
  that the stub-shell branch stubs only the shell tool; the web tool at
  agent-bridle rev 2129c91 is the real leash-enforcing implementation.
  fs tools keep the newt-native workspace fence: yolo is unconfined
  exec, fenced fs — never authority-off.
- Precedence: --disable-ocap > --prompt-for-permissions for exec
  (nothing is denied, so the #263 gate is structurally unreachable);
  fs prompting unaffected.
- newt-cli: --disable-ocap with visible alias --yolo (global), threads
  via NEWT_DISABLE_OCAP=1 exactly like #289's --prompt-for-permissions.
- newt-tui: unmissable session-start banner + ONE ocap-disabled record
  ({decision: "ocap-disabled", scope: "session", kind: exec, target: *})
  in the #263 permission log so the audit trail shows the session ran open.
- Everything is doc-marked INTERIM, referencing #297, agent-bridle#20,
  and reubeno/brush#1184 — removed (or demoted to a debug flag) when
  brush upstreams CommandInterceptor.

13 new tests: flag-off pinned bit-for-bit (stub error verbatim), yolo
runs the denied command on the host shell with envelope parity, banner,
log record round-trip, fs fence enforced under yolo, precedence over
prompt mode (exec never prompts, fs still does), env-var equivalence,
exact-value flag parsing, --yolo alias. Coverage 90.10% (floor 80%).

Refs #297

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hartsock hartsock force-pushed the feat/297-disable-ocap branch from d52e440 to 88554f1 Compare June 12, 2026 03:52
@hartsock hartsock merged commit fa3eba3 into main Jun 12, 2026
10 checks passed
@hartsock hartsock deleted the feat/297-disable-ocap branch June 12, 2026 03:58
hartsock added a commit that referenced this pull request Jun 27, 2026
Operator-reported: on stub-shell builds (the only crates.io-publishable
configuration) agent-bridle's shell tool fails closed on every command,
so run_command cannot do agentic coding at all without the brush
CommandInterceptor patch underneath. This adds the explicit, loud,
interim bypass the issue specifies:

- newt-core: `ocap_disabled()` (NEWT_DISABLE_OCAP=1, exact-value,
  fail-closed read; env-only — deliberately NO config key) and a
  run_command bypass that executes on the plain host shell (bash -c,
  sh fallback; cmd /C on Windows) with the SAME venv/PATH prefix and
  an envelope structurally identical to the bridle one
  ({exit_code, stdout, stderr, sandbox_kind}, denied/denials omitted),
  so envelope_denied/shell_envelope_output and the loop need no changes.
- Scope: exec only. web_fetch is NOT bypassed — determined empirically
  that the stub-shell branch stubs only the shell tool; the web tool at
  agent-bridle rev 2129c91 is the real leash-enforcing implementation.
  fs tools keep the newt-native workspace fence: yolo is unconfined
  exec, fenced fs — never authority-off.
- Precedence: --disable-ocap > --prompt-for-permissions for exec
  (nothing is denied, so the #263 gate is structurally unreachable);
  fs prompting unaffected.
- newt-cli: --disable-ocap with visible alias --yolo (global), threads
  via NEWT_DISABLE_OCAP=1 exactly like #289's --prompt-for-permissions.
- newt-tui: unmissable session-start banner + ONE ocap-disabled record
  ({decision: "ocap-disabled", scope: "session", kind: exec, target: *})
  in the #263 permission log so the audit trail shows the session ran open.
- Everything is doc-marked INTERIM, referencing #297, agent-bridle#20,
  and reubeno/brush#1184 — removed (or demoted to a debug flag) when
  brush upstreams CommandInterceptor.

13 new tests: flag-off pinned bit-for-bit (stub error verbatim), yolo
runs the denied command on the host shell with envelope parity, banner,
log record round-trip, fs fence enforced under yolo, precedence over
prompt mode (exec never prompts, fs still does), env-var equivalence,
exact-value flag parsing, --yolo alias. Coverage 90.10% (floor 80%).

Refs #297

Co-authored-by: hartsock <hartsock@users.noreply.github.com>
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.

1 participant