Skip to content

[AAASM-4130] 🔒 (core): Make default enforcement posture coherent (no silent local fail-open)#213

Merged
Chisanan232 merged 3 commits into
masterfrom
v0.0.1/AAASM-4130/default_mode_fail_closed_or_warn
Jul 5, 2026
Merged

[AAASM-4130] 🔒 (core): Make default enforcement posture coherent (no silent local fail-open)#213
Chisanan232 merged 3 commits into
masterfrom
v0.0.1/AAASM-4130/default_mode_fail_closed_or_warn

Conversation

@Chisanan232

Copy link
Copy Markdown
Contributor

Description

init_assembly(enforcement_mode=None) is advertised as the gateway's live enforce default, but build_governance_interceptor computed enforce = (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 / empty query_policy returned {"status":"allow"} — a would-be-denied tool proceeded with no warning. This diverged from go (denies, fail-closed) and node (raises ConfigurationError).

This PR makes the default posture coherent while keeping the SDK advisory and graceful:

  • Treat None as 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 unauthoritative query_policy denies, matching the advertised default. observe / disabled still fail open locally.
  • On a pure-Python install (native _core extension 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).
  • Correct the init_assembly docstring and the module docstrings to state the actual behavior.

Scope is limited to agent_assembly/core/runtime_interceptor.py and agent_assembly/core/assembly.py.

Type of Change

  • 🔧 Bug fix

Breaking Changes

  • No

Behavior tightens only for the advertised enforce default: 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 / disabled are unchanged.

Related Issues

  • Related JIRA ticket: AAASM-4130

Testing

  • Unit tests added/updated

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), and test_observe_mode_does_not_warn_when_native_core_missing (warning scoped to the enforce posture). Updated the existing ..._returns_bare_client_when_connect_fails test to assert the fail-open path under an explicit observe (the None default now fails closed there). Full test/unit suite green; pre-commit (isort/autoflake/black/mypy) passes.

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Comments added for complex logic
  • Documentation updated if needed
  • All tests passing

🤖 Generated with Claude Code

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
@sonarqubecloud

sonarqubecloud Bot commented Jul 4, 2026

Copy link
Copy Markdown

@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Chisanan232

Copy link
Copy Markdown
Contributor Author

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. _local_posture_is_enforce() now treats the None default identically to explicit enforce for the local error posture (the ticket's preferred fix), and _warn_sdk_enforcement_unavailable() emits the loud one-time warning the ticket asked for when no in-process deny can run. Docstrings in assembly.py + runtime_interceptor.py corrected to match advertised behavior. Three new tests cover: (a) default-mode + unreachable runtime → _FailClosedInterceptor deny, (b) default-mode + native-missing → warns + graceful bare client, (c) explicit observe + native-missing → silent (warning correctly scoped to enforce posture).

3. Side effects — verified against the IPC-deadlock history:

  • Native runtime absent (pure-Python install) under None/enforce: returns the bare client and only warns — no hang, no hard-crash. Init stays graceful; gateway/proxy/eBPF remain authoritative. ✅
  • Native present but socket unreachable under None/enforce: deny-all interceptor (fail closed) — the intended fix. ✅
  • observe / disabled still fail open and stay silent — confirmed by the new scoped-warning test and the amended existing test (observe explicitly passed where the old test relied on the default). ✅
  • Full existing interceptor suite unaffected.

4. FE: N/A.

Local validation (worktree @ 9ed0561): pytest test/unit/core/test_runtime_interceptor.py51 passed. Pre-commit gate green — isort / autoflake / black / mypy all Passed. (ruff check flags UP035 on assembly.py:9 — an untouched import line, identical on master; pre-existing baseline, not this PR, and not part of the pre-commit gate.)

Independence: disjoint from #212 and #214 — independently mergeable.

— Claude Code

@Chisanan232 Chisanan232 merged commit fdafdc7 into master Jul 5, 2026
26 checks passed
@Chisanan232 Chisanan232 deleted the v0.0.1/AAASM-4130/default_mode_fail_closed_or_warn branch July 5, 2026 00:43
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