Skip to content

fix(evaluator): fail closed when external backend returns an error - #3008

Merged
Imran Siddique (imran-siddique) merged 1 commit into
mainfrom
fix/evaluator-backend-error-fail-closed
Jun 13, 2026
Merged

Imran Siddique (imran-siddique) merged 1 commit into
mainfrom
fix/evaluator-backend-error-fail-closed

Conversation

@imran-siddique

Copy link
Copy Markdown
Collaborator

Fixes #2992.

Summary

  • PolicyEvaluator._evaluate_flat and _evaluate_rules silently skipped backends whose BackendDecision.error was non-None, letting evaluation fall through to the configurable default action (which can be allow). A transient backend crash could produce a permit.
  • Fix: invert the condition -- a non-None error immediately returns a fail-closed deny PolicyDecision with audit_entry["error"]=True and error_detail captured for post-incident investigation. Subsequent backends in the list are not consulted.
  • Security audit added at docs/security/audits/2026-06-12-evaluator-backend-error-fail-closed.md.

Test plan

  • test_backend_error_fails_closed_not_fallthrough -- error backend denies, not falls through to default
  • test_backend_error_does_not_consult_subsequent_backends -- later backends not reached after first errors
  • test_healthy_backend_after_yaml_miss_still_allows -- non-error backend path still works correctly
  • Full evaluator suite: python -m pytest agent-governance-python/agent-os/tests/ -q -k "evaluator" -- 116 passed (1 pre-existing crewai failure unrelated: missing agt compiled extension)

🤖 Generated with Claude Code

…2992)

Previously _evaluate_flat and _evaluate_rules silently skipped backends
whose BackendDecision carried a non-None error field. If every registered
backend errored, evaluation fell through to the configurable default action
(which can be allow), converting a backend crash into a permit decision.

Fix: invert the condition so a non-None error immediately returns a deny
PolicyDecision with audit_entry["error"]=True and error_detail captured for
post-incident investigation. Later backends in the list are not consulted.

Adds three regression tests in test_policy_backends.py covering:
- error backend denies instead of falling through to default
- subsequent backends not reached after an error
- healthy backend after YAML miss still returns its own decision correctly

Security audit: docs/security/audits/2026-06-12-evaluator-backend-error-fail-closed.md

Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests security Security-related issues labels Jun 13, 2026
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions github-actions Bot added the size/M Medium PR (< 200 lines) label Jun 13, 2026
@github-actions

Copy link
Copy Markdown

PR Review Summary

Check Status Details
🔍 Code Review ⚠️ Missing No current-run comment
🛡️ Security Scan ⚠️ Missing No current-run comment
🔄 Breaking Changes ⚠️ Missing No current-run comment
📝 Docs Sync ⚠️ Missing No current-run comment
🧪 Test Coverage ⚠️ Missing No current-run comment

Verdict: ⚠️ AI review incomplete; ready for human review

AI review comments are untrusted advisory output. The summary reports workflow-generated completion status only, not model-authored pass/fail claims.

@imran-siddique
Imran Siddique (imran-siddique) merged commit a1c6ff8 into main Jun 13, 2026
133 of 134 checks passed
@imran-siddique
Imran Siddique (imran-siddique) deleted the fix/evaluator-backend-error-fail-closed branch June 13, 2026 23:04
jlaportebot (jlaportebot) pushed a commit to jlaportebot/agent-governance-toolkit that referenced this pull request Jun 17, 2026
…icrosoft#3008)

Previously _evaluate_flat and _evaluate_rules silently skipped backends
whose BackendDecision carried a non-None error field. If every registered
backend errored, evaluation fell through to the configurable default action
(which can be allow), converting a backend crash into a permit decision.

Fix: invert the condition so a non-None error immediately returns a deny
PolicyDecision with audit_entry["error"]=True and error_detail captured for
post-incident investigation. Later backends in the list are not consulted.

Adds three regression tests in test_policy_backends.py covering:
- error backend denies instead of falling through to default
- subsequent backends not reached after an error
- healthy backend after YAML miss still returns its own decision correctly

Security audit: docs/security/audits/2026-06-12-evaluator-backend-error-fail-closed.md

Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: jlaportebot <jlaportebot@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation security Security-related issues size/M Medium PR (< 200 lines) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Policy backends that fail closed (error + action=deny) are skipped by PolicyEvaluator — evaluation can fall through to a default allow

1 participant