[AAASM-4130] 🔒 (core): Make default enforcement posture coherent (no silent local fail-open)#213
Conversation
init_assembly's None default is advertised as the gateway's live enforce, but build_governance_interceptor computed enforce = (mode == "enforce"), so under the default an unreachable runtime or an unauthoritative query silently allowed a would-be-denied tool — diverging from go (denies) and node (raises ConfigurationError). Treat None as an enforce posture for the SDK's local error handling: deny on an unreachable runtime / failed query, and emit a loud one-time warning when the native extension is absent (no in-process deny possible) instead of failing open silently. The SDK stays advisory and never hard-fails on a missing runtime. Refs AAASM-4130
The init_assembly docstring said the None default only defers to the gateway's server-side enforce; it omitted that the SDK's local pre-execution fast path now also fails closed under None (deny on unreachable runtime / failed query) and warns when the native extension is absent. Refs AAASM-4130
Assert the AAASM-4130 contract: under the None default an unreachable runtime yields a deny-all interceptor (not a silent allow), a missing native extension warns loudly while staying graceful, and an explicit observe dry-run with no native extension still fails open silently. Refs AAASM-4130
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Senior review — APPROVE-READY (comment only, not an approval)Verdict: LGTM. Resolves the MED fail-open/cross-SDK-inconsistency (AAASM-4130) without regressing graceful degradation. 1. CI: Green — 19/19 checks pass. 2. Scope vs ticket: Full coverage. 3. Side effects — verified against the IPC-deadlock history:
4. FE: N/A. Local validation (worktree @ 9ed0561): Independence: disjoint from #212 and #214 — independently mergeable. — Claude Code |



Description
init_assembly(enforcement_mode=None)is advertised as the gateway's liveenforcedefault, butbuild_governance_interceptorcomputedenforce = (enforcement_mode == "enforce"), so under the default the SDK's local pre-execution fast path silently failed open: a native-present-but-unreachable runtime returned a bare client (no check), and a raising / malformed / emptyquery_policyreturned{"status":"allow"}— a would-be-denied tool proceeded with no warning. This diverged from go (denies, fail-closed) and node (raisesConfigurationError).This PR makes the default posture coherent while keeping the SDK advisory and graceful:
Noneas an enforce posture for the SDK's local error handling (new_local_posture_is_enforce): an unreachable runtime yields a deny-all interceptor and an unauthoritativequery_policydenies, matching the advertised default.observe/disabledstill fail open locally._coreextension absent) no in-process deny is possible, so emit a loud one-time warning instead of failing open silently. The gateway / proxy / eBPF layers remain authoritative, so init stays graceful and never hard-fails on a missing runtime (no IPC hang / hard crash).init_assemblydocstring and the module docstrings to state the actual behavior.Scope is limited to
agent_assembly/core/runtime_interceptor.pyandagent_assembly/core/assembly.py.Type of Change
Breaking Changes
Behavior tightens only for the advertised
enforcedefault: a would-be-denied tool that previously slipped through the local fast path is now denied (or a warning surfaces when no local check can run).observe/disabledare unchanged.Related Issues
Testing
Added
test_default_mode_unreachable_runtime_fails_closed(deny-all under the default with an unreachable runtime),test_default_mode_warns_when_native_core_missing(loud warning, still graceful), andtest_observe_mode_does_not_warn_when_native_core_missing(warning scoped to the enforce posture). Updated the existing..._returns_bare_client_when_connect_failstest to assert the fail-open path under an explicitobserve(theNonedefault now fails closed there). Fulltest/unitsuite green; pre-commit (isort/autoflake/black/mypy) passes.Checklist
🤖 Generated with Claude Code