Skip to content

fix(py): caveats=None and omitted axes are deny-all, not full authority (AB-009) - #303

Merged
hartsock merged 1 commit into
mainfrom
fix/ab-009-python-deny-all-default
Jul 28, 2026
Merged

fix(py): caveats=None and omitted axes are deny-all, not full authority (AB-009)#303
hartsock merged 1 commit into
mainfrom
fix/ab-009-python-deny-all-default

Conversation

@hartsock

Copy link
Copy Markdown
Member

Summary

Fixes #271 / AB-009 — the Python facade defaulted fail-open. invoke(caveats=None) minted Caveats::top() (full ambient authority) behind a stderr warning, and caveats_from_py defaulted every omitted axis to top — so a partial dict like {"exec": {"only": ["echo"]}} silently granted top fs_read/fs_write/net and unlimited max_calls.

Both now default to deny-all, mirroring the MCP frontend's already-correct caveats_source::deny_all:

  • new deny_all() helper; invoke's None branch returns it (warning removed — a warning is not an authority boundary);
  • caveats_from_py omitted-axis defaults flip top → bottom (Scope::none(), CountBound::AtMost(0));
  • module docs corrected.

Full ambient authority must now be asked for explicitly (every axis "all") — the existing "all" literals already support it, so no new API surface.

Test plan

Validated locally against a built wheel (isolated venv, never ~/venv) — 18/18 pass:

  • test_caveats_none_is_deny_allcaveats=NoneBridleDenied (was: ran unconfined).
  • test_missing_axis_defaults_to_bottom — omitting max_calls under an exec grant → BridleDenied.
  • test_explicit_all_axes_still_runs_unconfined — the deliberate escape hatch works.
  • Positive fixtures (ECHO_ONLY) now name the axes they need (previously implicit under omitted-defaults-to-top; a restricted fs/net axis the host can't enforce correctly refuses to run).

CI's "python wheel + pytest (Pillar A)" job runs these. Rust clippy -D warnings clean; pre-push [pre-push] OK.

Scope

Contained to the agent-bridle-py facade. Brings it to parity with MCP's fail-closed default. No cross-crate API change.

Fixes #271

🤖 Generated with Claude Code

…ty (AB-009)

WHAT: The Python facade defaulted fail-OPEN. `invoke(caveats=None)` minted
Caveats::top() (full ambient authority) behind a stderr warning, and
caveats_from_py defaulted every OMITTED axis to top (Scope::top() /
CountBound::top()). So a partial dict like {"exec": {"only": ["echo"]}} silently
granted top fs_read/fs_write/net and unlimited max_calls.

Now both default to DENY-ALL, mirroring the MCP frontend's caveats_source::deny_all:
- new `deny_all()` helper; invoke's None branch returns it (warning removed — a
  warning is not an authority boundary);
- caveats_from_py omitted-axis defaults flip top -> bottom (Scope::none(),
  CountBound::AtMost(0));
- module docs corrected. Full ambient authority must now be asked for explicitly
  (every axis "all") — the existing "all" literals already support it.

WHY: #271 / AB-009 — a fail-open confinement default reachable through a shipped
frontend. Regression tests (validated locally against a built wheel): caveats=None
denies; an omitted axis (max_calls) denies; and the explicit all-axes escape hatch
still runs. Positive fixtures now name the axes they need (previously implicit
under omitted-defaults-to-top).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@hartsock hartsock added the risk:high High-risk change label Jul 28, 2026
@cursor

cursor Bot commented Jul 28, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@hartsock
hartsock merged commit 562ea7d into main Jul 28, 2026
10 checks passed
@hartsock
hartsock deleted the fix/ab-009-python-deny-all-default branch July 28, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high High-risk change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AB-009: Python caveats=None grants full authority; omitted axes default to top

1 participant