Skip to content

Feat: granular allowlist#141

Open
TheDZhon wants to merge 7 commits intomainfrom
feat/granular-allowlist
Open

Feat: granular allowlist#141
TheDZhon wants to merge 7 commits intomainfrom
feat/granular-allowlist

Conversation

@TheDZhon
Copy link
Contributor

@TheDZhon TheDZhon commented Mar 13, 2026

Summary

Implements granular allowed_diffs allowlists for both source and bytecode comparisons (closes #136).

Instead of blanket --allow-source-diff/--allow-bytecode-diff CLI flags that silently suppress all diffs for an address, diffs can now be declared precisely in config with mandatory reason fields and composable facets.

Bytecode facets

  • immutables — pin expected values at exact byte offsets
  • cbor_metadata — allow Solidity CBOR metadata hash differences
  • byte_ranges — allow arbitrary byte ranges
  • constructor_args / constructor_calldata — override constructor parameters per-rule
  • any — blanket allow (also suppresses RPC simulation errors)

Source facets

  • line_ranges — allow diffs in specific file regions (github/explorer line counts)
  • files — allow diffs in specific files
  • any — blanket allow

Auto-suggestions

When diffs are detected but not covered by rules, the tool prints a ready-to-paste JSON allowed_diffs snippet with the exact facets needed. This makes adopting granular rules trivial — run once, copy the suggestion, fill in the reason.

Key changes

Area What changed
diffyscan/utils/allowed_diffs.py (new, 660 lines) Validation, evaluation, normalization, and suggestion engine
diffyscan/diffyscan.py Integrates allowlist evaluation into source/bytecode pipelines; prints suggestions in final summary; "any" bytecode rules now suppress RPC simulation errors
diffyscan/utils/common.py Config loading validates allowed_diffs structure, boolean fields, and YAML hex quoting for allowlist addresses
diffyscan/utils/custom_types.py Config TypedDict includes allowed_diffs and missing optional fields
pyproject.toml Added mypy + type stubs to dev deps; [tool.mypy] config for incremental type checking
Regression configs (6 files) Replaced all CLI --allow-*-diff flags with precise in-config allowed_diffs entries discovered via real runs against mainnet and hoodi RPCs
.github/workflows/regression.yml Removed flags matrix, DIFFYSCAN_FLAGS env var, and bash flag-parsing; run command is now just uv run diffyscan -Y -E -G "$DIFFYSCAN_CONFIG"

Config example

{
  "allowed_diffs": {
    "bytecode": {
      "0xd6A6...9426": [{
        "reason": "Escrow stores own deployed address as immutable",
        "immutables": [
          {"offset": 1093, "value": "0x000...9426"},
          {"offset": 6887, "value": "0x000...9426"}
        ]
      }]
    },
    "source": {
      "0x8aa3...9F3": [{
        "reason": "Import paths differ between GitHub and explorer-verified source",
        "line_ranges": [{
          "file": "contracts/CuratedSubmitExitRequestHashes.sol",
          "github": {"start": 6, "count": 7},
          "explorer": {"start": 6, "count": 7}
        }]
      }]
    }
  }
}

Test plan

  • 130 unit tests pass (pytest -q) — covers validation, evaluation, edge cases, suggestions, and config loading
  • mypy diffyscan/ — 0 errors across 16 source files
  • All 12 regression matrix jobs pass (4 mainnet clean, 4 mainnet with allowed_diffs, 2 hoodi with allowed_diffs, 2 mainnet clean governance/voting)
  • Verify suggestion output: run any config without its allowed_diffs section and confirm the printed snippet can be pasted back to make it pass

Base automatically changed from feat/remove-hardhat-and-js to main March 13, 2026 13:57
@TheDZhon TheDZhon marked this pull request as ready for review March 13, 2026 14:34
@TheDZhon TheDZhon requested review from a team as code owners March 13, 2026 14:34
@TheDZhon TheDZhon changed the title Feat/granular allowlist Feat: granular allowlist Mar 13, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements granular allowed_diffs allowlists for both source and bytecode comparisons, replacing the blanket --allow-source-diff/--allow-bytecode-diff CLI flags. Diffs can now be declared precisely in config files with mandatory reason fields and composable facets (immutables, cbor_metadata, byte_ranges, line_ranges, files, etc.). When uncovered diffs are detected, the tool prints ready-to-paste config snippets.

Changes:

  • New allowed_diffs validation, evaluation, normalization, and suggestion engine in diffyscan/utils/allowed_diffs.py
  • Refactored bytecode analysis into structured analyze_bytecode_diff() returning detailed mismatch information, with deep_match_bytecode() preserved as backward-compatible wrapper
  • Integrated allowlist evaluation into the main source/bytecode pipelines, with suggestion output in final summary

Reviewed changes

Copilot reviewed 32 out of 33 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
diffyscan/utils/allowed_diffs.py New module: validation, evaluation, normalization, suggestion engine for granular allowlists
diffyscan/utils/binary_verifier.py Refactored to expose analyze_bytecode_diff() and log_bytecode_diff_analysis(); normalized 0x prefix
diffyscan/diffyscan.py Integrated allowlist evaluation into source/bytecode pipelines; structured result dicts; suggestion printing
diffyscan/utils/common.py Config validation for allowed_diffs, boolean fields, YAML hex quoting in allowlist entries
diffyscan/utils/custom_types.py TypedDict definitions for allowlist rules and missing optional Config fields
pyproject.toml Added mypy + type stubs to dev deps; mypy and black config
tests/test_allowed_diffs.py New comprehensive tests for allowlist validation, evaluation, and suggestions
tests/test_config_loading.py Tests for allowed_diffs config validation edge cases and boolean field validation
tests/test_binary_verifier.py Tests for new analyze_bytecode_diff function
tests/*.py (other) Type annotation fixes for mypy compliance
tests/fixtures/full_config.* Added allowed_diffs sections to test fixtures
config_samples/**/*.json Replaced CLI flags with in-config allowed_diffs entries
.github/workflows/regression.yml Removed flags matrix and bash flag-parsing; simplified run command
.pre-commit-config.yaml Added mypy pre-commit hook
diffyscan/utils/explorer.py, compiler.py, etc. Type annotation fixes for mypy compliance
uv.lock Updated lock file with new dev dependencies
README.md Documentation for granular allowlists feature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

files_with_diffs = sum(row[2] and row[3] > 0 for row in report)

logger.report_table(report)
files_with_diffs = sum(bool(file_result["hunks"]) for file_result in file_results)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

haha, I disagree with Copilot here

@TheDZhon
Copy link
Contributor Author

Self-reminder: need to rebase on the latest main and update skills ⚠️

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.

Feature request: Granular bytecode diff allowlists — specify *what* is allowed, not just *where*

2 participants