Skip to content

test: cover policy hardening regressions - #4

Merged
tblakex01 merged 1 commit into
mainfrom
codex/test-coverage-regressions
Jul 18, 2026
Merged

tblakex01 merged 1 commit into
mainfrom
codex/test-coverage-regressions

Conversation

@tblakex01

@tblakex01 tblakex01 commented Jul 18, 2026 •

Copy link
Copy Markdown
Owner

Why

  • Close meaningful test gaps found while reviewing the repository's recent pull requests and policy-hardening changes.
  • Protect fail-closed enforcement, trust validation, regex safety, and legacy audit compatibility from regressions.

How

  • Add async decorator, policy-loader, trust-manager, and trust-metadata failure-path tests.
  • Extend regex safety and legacy event-integrity coverage.
  • Verify orphaned trust configuration warns once.

Tests

  • pytest -q — 256 passed
  • pytest -q --cov=policyforge --cov-branch — 95% branch-aware coverage
  • ruff check policyforge tests
  • black --check policyforge tests
  • mypy policyforge
  • git diff --check

Summary by Sourcery

Expand test coverage for trust enforcement, policy loading, regex safety, and audit/trust compatibility to guard against regressions in policy hardening.

Tests:

  • Add async decorator tests to ensure uninspectable async callables are denied with appropriate policy decisions.
  • Add policy loader tests for missing condition keys and invalid trust verdict configuration.
  • Broaden regex safety tests to cover multiple nested-quantifier patterns and long input handling.
  • Add audit entry tests to ensure legacy event integrity hashes remain verifiable.
  • Extend trust manager tests to cover untrusted tool metadata objects and orphaned trust configuration warning behavior.

Summary by CodeRabbit

  • Tests
    • Added regression coverage for safely denying uninspectable async callables.
    • Verified trust configuration warnings are emitted only once.
    • Expanded validation tests for missing condition values and invalid verdicts.
    • Broadened regex-safety and legacy audit-integrity coverage.
    • Added checks for invalid tool metadata and non-hex schema hashes.

@sourcery-ai

sourcery-ai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Adds regression-focused tests around policy engine trust handling, decorators, loader validation, regex safety, audit integrity, and trust metadata to harden fail-closed and compatibility behaviors.

File-Level Changes

Change Details Files
Ensure orphaned trust configuration only emits a single warning when loading policies repeatedly without a TrustManager.
  • Add integration test that loads the same policy twice with no TrustManager configured and asserts only one warning is logged
  • Filter captured log records for the specific orphaned TrustManager warning and assert its count
tests/test_engine_trust_integration.py
Extend decorator coverage to async callables when argument binding fails so they fail closed with a policy denial.
  • Introduce an asyncio-marked test for async targets wrapped with policy_gate
  • Monkeypatch inspect.signature to raise ValueError to simulate an uninspectable async callable
  • Assert wrapped async calls raise PolicyDeniedError with the argument_binding_failed rule
tests/test_decorators.py
Tighten policy loader validation around malformed conditions and trust config verdict values.
  • Add loader test for conditions missing the required value key, expecting PolicyValidationError
  • Add parametrized trust-config tests that reject invalid verdict strings for on_mismatch and on_unknown
tests/test_loader.py
Broaden regex safety checks and preserve legacy audit entry integrity verification.
  • Parametrize unsafe nested-quantifier regex tests with several catastrophic patterns to ensure they are all rejected
  • Add test that legacy audit entries with pre-existing integrity hashes remain verifiable via the current verification path
tests/test_models.py
Harden TrustManager behavior when given untrusted or invalid tool metadata.
  • Add test that passing a non-ToolMetadata object to TrustManager.check in enforce mode results in a DENY verdict with reason tool_meta_untrusted
tests/test_trust_manager.py
Strengthen ToolMetadata validation to reject non-hex hash values.
  • Add test that ToolMetadata construction fails when schema_hash is not valid hexadecimal, raising a ValueError with an appropriate message
tests/test_trust_models.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b49e1bf-e1ed-4df9-9c3b-2423ceee6ab6

📥 Commits

Reviewing files that changed from the base of the PR and between 46d5d49 and 32d9752.

📒 Files selected for processing (6)
  • tests/test_decorators.py
  • tests/test_engine_trust_integration.py
  • tests/test_loader.py
  • tests/test_models.py
  • tests/test_trust_manager.py
  • tests/test_trust_models.py

📝 Walkthrough

Walkthrough

The test suite adds regression coverage for fail-closed decorator behavior, trust warnings and denials, loader and model validation, unsafe regex rejection, schema hash validation, and legacy audit integrity verification.

Changes

Regression Test Coverage

Layer / File(s) Summary
Enforcement and trust regressions
tests/test_decorators.py, tests/test_engine_trust_integration.py, tests/test_trust_manager.py
Tests cover async argument-binding failure denial, one-time orphaned trust warnings, and denial of untrusted non-dictionary tool metadata in enforce mode.
Validation contract coverage
tests/test_loader.py, tests/test_models.py, tests/test_trust_models.py
Tests cover missing condition keys, invalid trust verdicts, multiple unsafe nested-quantifier patterns, and non-hexadecimal schema hashes.
Legacy audit integrity
tests/test_models.py
A regression test verifies legacy audit entries using legacy integrity hashes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/test-coverage-regressions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tblakex01
tblakex01 merged commit 78def0f into main Jul 18, 2026
6 of 7 checks passed

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In test_orphaned_trust_config_warns_only_once, the assertion relies on the exact warning message substring; consider keying off a more stable attribute (e.g., a specific warning class, log code, or constant message) to make the test less brittle to wording changes.
  • The async decorator test overrides inspect.signature globally via monkeypatch.setattr("policyforge.decorators.inspect.signature", ...); consider scoping this more narrowly (or restoring the original in a finally) to reduce the risk of surprising interactions if additional tests in this module start relying on inspect.signature.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `test_orphaned_trust_config_warns_only_once`, the assertion relies on the exact warning message substring; consider keying off a more stable attribute (e.g., a specific warning class, log code, or constant message) to make the test less brittle to wording changes.
- The async decorator test overrides `inspect.signature` globally via `monkeypatch.setattr("policyforge.decorators.inspect.signature", ...)`; consider scoping this more narrowly (or restoring the original in a `finally`) to reduce the risk of surprising interactions if additional tests in this module start relying on `inspect.signature`.

## Individual Comments

### Comment 1
<location path="tests/test_engine_trust_integration.py" line_range="227-230" />
<code_context>
         assert decision.verdict == Verdict.DENY
         assert decision.matched_rule == "tool_trust_unwired"

+    def test_orphaned_trust_config_warns_only_once(self, tmp_path, caplog):
+        import logging
+
+        policy_yaml = tmp_path / "p.yaml"
+        policy_yaml.write_text(
+            """
+tool_trust:
+  mode: enforce
+name: demo
+default_verdict: ALLOW
+""",
+            encoding="utf-8",
+        )
+
+        with caplog.at_level(logging.WARNING, logger="policyforge.engine"):
+            engine = PolicyEngine()
+            engine.load(policy_yaml)
+            engine.load(policy_yaml)
+
+        warnings = [
+            record for record in caplog.records if "no TrustManager was passed" in record.message
+        ]
+        assert len(warnings) == 1
+
     def test_no_warning_when_trust_manager_present(self, tmp_path, ledger_path, caplog):
</code_context>
<issue_to_address>
**suggestion (testing):** Strengthen the "warns only once" behavior by exercising more than two load calls.

This test only covers two loads before asserting a single warning. To better lock in the "warn once" behavior, consider either looping over multiple `engine.load(policy_yaml)` calls within the same `caplog` context, or performing additional loads after the current assertion and checking that `len(warnings)` does not increase. This would more robustly guard against regressions where future changes re‑emit the warning on subsequent loads.

```suggestion
        with caplog.at_level(logging.WARNING, logger="policyforge.engine"):
            engine = PolicyEngine()
            # Call load multiple times to ensure the warning is only ever emitted once
            for _ in range(5):
                engine.load(policy_yaml)
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +227 to +230
with caplog.at_level(logging.WARNING, logger="policyforge.engine"):
engine = PolicyEngine()
engine.load(policy_yaml)
engine.load(policy_yaml)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Strengthen the "warns only once" behavior by exercising more than two load calls.

This test only covers two loads before asserting a single warning. To better lock in the "warn once" behavior, consider either looping over multiple engine.load(policy_yaml) calls within the same caplog context, or performing additional loads after the current assertion and checking that len(warnings) does not increase. This would more robustly guard against regressions where future changes re‑emit the warning on subsequent loads.

Suggested change
with caplog.at_level(logging.WARNING, logger="policyforge.engine"):
engine = PolicyEngine()
engine.load(policy_yaml)
engine.load(policy_yaml)
with caplog.at_level(logging.WARNING, logger="policyforge.engine"):
engine = PolicyEngine()
# Call load multiple times to ensure the warning is only ever emitted once
for _ in range(5):
engine.load(policy_yaml)

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