Skip to content

fix: reject composite policyType in createPolicy / createPolicyWithAccounts#176

Open
rayyan224 wants to merge 1 commit into
mainfrom
fix/createpolicy-reject-composite-type
Open

fix: reject composite policyType in createPolicy / createPolicyWithAccounts#176
rayyan224 wants to merge 1 commit into
mainfrom
fix/createpolicy-reject-composite-type

Conversation

@rayyan224

Copy link
Copy Markdown
Collaborator

Summary

Addresses @robriks' review comment on #174 (#174 (comment)).

The IPolicyRegistry natspec states that createPolicy and createPolicyWithAccounts revert IncompatiblePolicyType when policyType is a composite gate, but MockPolicyRegistry never enforced it:

policyRegistry.createPolicy(admin, PolicyType.UNION);      // created a 0-child UNION instead of reverting
policyRegistry.createPolicy(admin, PolicyType.INTERSECT);  // isAuthorized(id, anyAddr) == true (vacuous AND)
policyRegistry.createPolicyWithAccounts(admin, PolicyType.UNION, accts); // did not revert

A 0-child composite is degenerate: isAuthorized folds an empty child set (UNION → false, INTERSECT → true), silently minting an always-deny / always-authorize policy.

Changes

  • MockPolicyRegistry: createPolicy and createPolicyWithAccounts now revert IncompatiblePolicyType for UNION/INTERSECT, matching the documented precedence — after the zero-admin check, and (for createPolicyWithAccounts) before the batch-size check. Factored the type test into a shared _isCompositeType(PolicyType) helper (reused by createCompositePolicy and _isComposite).
  • Tests: added test_createPolicy_revert_incompatiblePolicyType and test_createPolicyWithAccounts_revert_incompatiblePolicyType, and extended both *_revertOrder walks with the new step.

Composites remain creatable only through createCompositePolicy, which requires a UNION/INTERSECT gate and a [2, 4] child set.

Testing

forge test → 661 passed, 0 failed, 4 skipped. python3 script/check-coverage.py → all covered (exit 0). forge fmt --check clean.

…counts

The IPolicyRegistry natspec documents that createPolicy and
createPolicyWithAccounts revert IncompatiblePolicyType for composite gates
(UNION/INTERSECT), but the mock never enforced it — a caller could mint a
degenerate 0-child composite whose isAuthorized short-circuits. Add the guard
to both simple-policy constructors (after the zero-admin check, before the
batch-size check), factor out _isCompositeType, and cover it with revert +
revert-order tests.

Addresses #174 (comment)

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Interface Coverage

✅ All interface functions have test coverage.

@github-actions

Copy link
Copy Markdown

📊 Forge Coverage (src/lib/)

🟡 ≥95% across all metrics — some metrics below 99%.

File Lines Stmts Branches Funcs
🟢 B20FactoryLib.sol 100.00% 100.00% 100.00% 100.00%
🔴 test/lib/ForceFeeder.sol 0.00% 0.00% 100.00% 0.00%
🔴 test/lib/PrecompileProbe.sol 0.00% 0.00% 0.00% 0.00%
🟢 MockActivationRegistry.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockActivationRegistryStorage.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockB20.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockB20Asset.sol 100.00% 100.00% 100.00% 100.00%
🟡 MockB20Factory.sol 98.96% 99.10% 100.00% 100.00%
🟢 MockB20Stablecoin.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockB20Storage.sol 100.00% 100.00% 100.00% 100.00%
🟡 MockPolicyRegistry.sol 100.00% 99.52% 97.56% 100.00%
🟢 MockPolicyRegistryStorage.sol 100.00% 100.00% 100.00% 100.00%
Total 96.92% 97.38% 97.84% 97.06%

Full report: download artifact. To browse locally: make coverage (runs forge coverage + genhtml + opens the HTML report).

@github-actions

Copy link
Copy Markdown

❌ Fork tests did not run

The build or setup step failed before any tests could execute. Check the workflow logs for details.

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