Skip to content

Feat/security ci restructure#264

Open
iap wants to merge 10 commits into
devfrom
feat/security-ci-restructure
Open

Feat/security ci restructure#264
iap wants to merge 10 commits into
devfrom
feat/security-ci-restructure

Conversation

@iap
Copy link
Copy Markdown
Member

@iap iap commented Jun 5, 2026


Open in Devin Review

Greptile Summary

This PR restructures CI into two consolidated entry-point workflows (ci-fast and ci-full) backed by three reusable sub-workflows (contracts-core, contracts-security, circuits-core), updates governance check names to match new job display names, adds cross-chain and reorg integration tests, fixes a circuit constraint bug in the relayer upper-bound check, and regenerates the Groth16 verifier from the updated circuit.

  • CI restructure: Replaces ~8 standalone workflow files with a two-tier system; ci-fast covers quick checks (lint, unit tests, security scans), while ci-full adds invariant tests and release-gate container build on top.
  • Circuit fix: Output commitments now use a 5-input Poseidon with domain-separated dstChainId to prevent cross-chain commitment reuse, and the relayer constraint is corrected from Num2Bits(160) to LessThan(161), requiring a new verifier VK.
  • Governance + script cleanup: apply-governance.sh fixes a long-standing bug where the team slug was sent with an owner/ prefix (invalid for the GitHub API); verify-governance.sh removes the now-unused canary branch check.

Confidence Score: 3/5

The CI restructure is logically sound, but the new ReorgSimulation.t.sol will break the primary forge test job in contracts-core.yml on every run where OP_SEPOLIA_RPC is absent — which is the normal CI environment.

vm.envString("OP_SEPOLIA_RPC") reverts when the env var is absent; since contracts-core.yml runs forge test -vv without a path filter, every CI execution will fail on ReorgSimulationTest.setUp() before any test body runs. This breaks the deterministic test gate that is a required branch-protection check. The governance script fixes and circuit correctness improvements are well done, but they are blocked from landing cleanly by this test regression.

contracts/test/integration/pool/ReorgSimulation.t.sol — all occurrences of vm.envString("OP_SEPOLIA_RPC") need to be changed to vm.envOr("OP_SEPOLIA_RPC", string("")) to allow graceful skipping when the fork URL is not available.

Important Files Changed

Filename Overview
contracts/test/integration/pool/ReorgSimulation.t.sol New reorg simulation integration test — uses vm.envString without a fallback, which reverts when OP_SEPOLIA_RPC is not set, causing all tests in the contract to fail in standard CI.
.github/workflows/ci-fast.yml New consolidated fast-CI workflow combining linting, contracts, circuits, frontend, and secret scanning. Includes workflow_call trigger (enabling reuse from ci-full.yml), but secrets: inherit under on.workflow_call is non-standard syntax.
.github/workflows/ci-full.yml New full-CI workflow orchestrating ci-fast, invariant tests, and release-gate container build via dependent jobs; correctly uses secrets: inherit on the calling side.
scripts/github/apply-governance.sh Updated governance script with new build_restrictions() helper, corrected team slug format (removed owner/ prefix bug), and updated required check names to match new CI job display names.
scripts/github/verify-governance.sh Updated required check name list and dropped canary branch check. Contains hardcoded Bearer *** literal as auth token (previously flagged), making the weekly governance baseline verification non-functional.
circuits/mark/MARKPool.circom Output commitment extended to 5-input Poseidon with domain-separated dstChainId; relayer constraint changed from Num2Bits(160) to LessThan(161) for correct upper-bound enforcement.
contracts/src/pool/verifier/MARKPoolVerifier.sol Regenerated Groth16 verifier with updated VK constants from recompiled circuit; contract renamed from MARKPoolVerifier to Groth16Verifier and pragma widened to >=0.7.0 <0.9.0 (standard snarkJS output).
contracts/test/integration/bridge/CrossChainDoubleSpend.t.sol New cross-chain double-spend tests; most scenarios are well-tested (bridgeIn replay, same-chain, zero/duplicate commitments), but testCrossChainDoubleSpendViaBridgeIn still lacks a concrete assertion (previously flagged).
.github/workflows/governance.yml Consolidates governance-policy-guard and governance-verify into a single workflow with path-filtered PR validation and scheduled baseline verification. Correctly guards weekly schedule runs with a GOVERNANCE_VERIFY_PAT secret presence check.
contracts/docker/release-gate.Dockerfile Adds a non-root appuser for safer CI execution, which is a good security hardening improvement.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    PR[Pull Request / Push to dev or main] --> CIF[ci-fast.yml]
    PR --> CIFULL[ci-full.yml]

    CIF --> GL[Gitleaks Scan]
    CIF --> TCL[Typecheck + Lint]
    CIF --> CC[contracts-core.yml\nUnit Tests]
    CIF --> CS[contracts-security.yml\nSemgrep + Slither]
    CIF --> CIR[circuits-core.yml\nBuild + Tests + Circomspect]
    CIF --> FE[_reusable-frontend-checks.yml]
    CIF --> DR[Dependency Review]

    CIFULL --> CIF
    CIFULL --> CCF[contracts-core.yml\nWith Invariants]
    CIFULL --> RG[contracts-release-gate.yml]

    CCF --> |needs ci-fast| CIF
    RG --> |needs ci-fast| CIF

    GOV[governance.yml] --> VP[Validate Policy\nPR path-filtered]
    GOV --> VB[Verify Baseline\nScheduled/Manual]
Loading

Comments Outside Diff (1)

  1. scripts/github/verify-governance.sh, line 118-123 (link)

    P2 Push-restriction check inconsistent with apply-governance.sh

    check_branch hard-codes a check that restrictions.teams[].slug == "maintainers". But apply-governance.sh's new build_restrictions() function can be invoked with MAIN_PUSH_ALLOW_USERS=iap (documented in the header comments), which produces a user-based restriction with teams: []. When the governance is applied with user-based restrictions, every verify-governance.sh run will report FAIL: push restrictions do not include maintainers team on both branches. Either the verify script should also accept user-based restrictions, or the apply script should disallow that mode for protected branches.

    Fix in Codex

Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
contracts/test/integration/pool/ReorgSimulation.t.sol:57-66
**`vm.envString` reverts when env var is unset — all tests in this contract fail in CI**

`vm.envString("OP_SEPOLIA_RPC")` reverts with an error if the environment variable is not set; it does not return an empty string. Because `setUp()` is called before every test in `ReorgSimulationTest`, and `OP_SEPOLIA_RPC` is not available in the `contracts-core.yml` runner, all tests in this contract will show as **FAILED** (not skipped) when `forge test -vv` is run. The `if (bytes(rpcUrl).length == 0)` guard is never reached because the revert happens before it.

The fix is to use `vm.envOr` with a fallback: `string memory rpcUrl = vm.envOr("OP_SEPOLIA_RPC", string(""));`. The same pattern must be applied inside each individual test function that calls `vm.envString("OP_SEPOLIA_RPC")` (lines 92, 152, 175, 192).

### Issue 2 of 2
.github/workflows/ci-fast.yml:7-8
`secrets: inherit` is not a valid value under `on.workflow_call.secrets` in a called workflow — it is a calling-side construct (`jobs.<job>.secrets: inherit`). In the called workflow, `on.workflow_call.secrets` should be either omitted or a named map of secrets. GitHub Actions may silently ignore this key, but if any nested reusable workflow that `ci-fast.yml` calls expects secrets to be forwarded, they won't be. The correct place for `secrets: inherit` is already in `ci-full.yml` where `ci-fast` is called.

```suggestion
  workflow_call:
```

Reviews (9): Last reviewed commit: "ci: re-trigger ci-fast.yml" | Re-trigger Greptile

iap added 2 commits June 5, 2026 14:07
P0 Security Fixes (circuit/contract):
- Relayer upper bits constrained to 160 in MARKPool.circom (LessThan(160))
- Output commitment uses 5-input Poseidon with domain-separated dstChainId
- RYLACreditLedger.setAdapter() allows re-set when ADAPTER == address(0)
- All P0 issues from security review addressed and tested

CI Security Fixes:
- Fixed shell injection in circomspect.yml, reorg-sim.yml, zk-proof-tests.yml,
  _reusable-frontend-checks.yml action, contracts-production-lock-verify.yml
- Docker release-gate now runs as non-root (USER appuser)
- github.* context moved to env vars in all run steps

Workflow Architecture Restructure (30 → 27 workflows):
- New reusable workflows: circuits-core.yml, contracts-core.yml, contracts-security.yml
- New entry points: ci-fast.yml (PR checks), ci-full.yml (full + invariants + gate)
- Merged governance-policy-guard + governance-verify -> governance.yml
- Semgrep integrated into contracts-security.yml (per Semgrep docs)
- Removed 7 obsolete workflows (circuits-ci, contracts-ci, contracts-semgrep,
  contracts-slither, slither-ci, governance-policy-guard, governance-verify)
- Removed 3 redundant wrappers (frontend-ci, secrets-scan, zk-proof-tests)
- All actions pinned to SHA

New Tests:
- CrossChainDoubleSpendTest (6 tests): nullifier replay, bridge-in replay,
  duplicate commitment, cross-chain spend protection
- ReorgSimulationTest (3 tests): double-spend prevention, privacy, root queue
- Circuit test: relayer bounds, cross-chain commitment replay

Documentation & Scripts:
- BRANCHING.md: updated check names matrix
- PRODUCTION_GOVERNANCE_CHECKLIST.md: aligned with new workflow job names
- apply-governance.sh/verify-governance.sh: fixed repo parsing, updated checks

Verified: all local CI gates pass (typecheck, lint, gitleaks, 154 unit tests,
19 circuit tests, circomspect, 3 pool invariants @ 256 runs)
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

Dependency Review

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

OpenSSF Scorecard

PackageVersionScoreDetails
npm/drizzle-orm 0.45.2 UnknownUnknown

Scanned Files

  • .github/workflows/_reusable-frontend-checks.yml
  • .github/workflows/contracts-ci.yml
  • .github/workflows/contracts-semgrep.yml
  • .github/workflows/governance-verify.yml
  • .github/workflows/zk-proof-tests.yml
  • pnpm-lock.yaml

greptile-apps[bot]

This comment was marked as resolved.

@iap iap marked this pull request as ready for review June 5, 2026 08:09
@iap iap requested a review from a team as a code owner June 5, 2026 08:09
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd00a59095

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci-fast.yml
Comment thread .github/workflows/ci-full.yml
Comment thread scripts/github/verify-governance.sh
Comment thread circuits/mark/MARKPool.circom
Comment thread .github/workflows/ci-fast.yml
Comment thread contracts/docker/release-gate.Dockerfile
Comment thread contracts/test/integration/bridge/CrossChainDoubleSpend.t.sol
Comment thread .github/workflows/ci-fast.yml Outdated
Comment thread scripts/github/apply-governance.sh
Comment thread circuits/setup.mjs
- Fix verify-governance.sh: restore GH_PAT in auth header (was literal ***)
  - P0: Governance verification was non-functional (401/404 from API)
- Pin gitleaks-action to v2.3.9 SHA in ci-fast.yml
  - P1: Supply chain risk from @master branch
- Add release orchestration smoke checks to required checks
  - P1: 'Contracts Release Check (Dry-Run + Execute Smoke)' and
    'Contracts Production Mode Smoke' restored in apply-governance.sh
    and verify-governance.sh

Verified: syntax OK, typecheck/lint pass, 154 contract tests pass,
19 circuit tests pass, all workflow YAML valid
greptile-apps[bot]

This comment was marked as resolved.

- BRANCHING.md: add missing release orchestration checks to dev/main matrix
- PRODUCTION_GOVERNANCE_CHECKLIST.md: update required checks to match apply-governance.sh
- Adds Gitleaks Scan, Contracts Release Check, Contracts Production Mode Smoke

Governance validation now PASSES
greptile-apps[bot]

This comment was marked as resolved.

iap added 2 commits June 5, 2026 16:47
- Upgrade snarkjs 0.6.11 -> 0.7.6 (fixes GHSA-xp5g-jhg3-3rg2 double-spend CVE-2023-33252)
  - Circuit tests pass, contract tests pass, invariant tests pass
  - Regenerated MARKPoolVerifier.sol with snarkjs 0.7.6

- Add pnpm override for drizzle-orm >=0.45.2 (fixes GHSA-gpj5-g38j-94v9 SQL injection)
  - Transitive via @eth-optimism/super-cli -> @libsql/client

- High-severity vulnerabilities resolved; remaining: moderate (uuid) + low (elliptic)
  - vulnerability review config only fails on high-severity

Verified: all 154 contract tests pass, 19 circuit tests pass, 3 pool invariants pass
- apply-governance.sh: set required_pull_request_reviews: null when review_count=0
- Disables 'Require approvals' toggle in branch protection
- CI gates remain the enforcement mechanism
- Maintainer team push restrictions still enforced
greptile-apps[bot]

This comment was marked as resolved.

iap added 3 commits June 5, 2026 18:16
- Use **/ prefix for all path patterns to be explicitly unanchored
- Fixes deprecation warnings for include/exclude patterns
- No functional change, just future-proofs config

Semgrep scan clean: 0 findings, 5 rules, 27 files scanned
1. ci-fast.yml: add workflow_call trigger for reusable invocation by ci-full.yml
2. pool-staging-deployment.yml: deploy Groth16Verifier (contract renamed from MARKPoolVerifier)
3. circuits/mark/MARKPool.circom: fix relayer constraint LessThan(160) -> LessThan(161) (2^160 is 161-bit)
4. scripts/github/apply-governance.sh: remove owner prefix from team restriction (API returns slug only)
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 9 potential issues.

Open in Devin Review


auth_headers=(
-H "Authorization: Bearer ${GH_PAT}"
-H "Authorization: Bearer ***"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 verify-governance.sh uses hardcoded *** instead of $GH_PAT for authentication

The auth_headers array at scripts/github/verify-governance.sh:47 uses the literal string *** instead of the $GH_PAT environment variable. Every curl call that uses "${auth_headers[@]}" (e.g., get_protection at line 86) will send Authorization: Bearer *** to the GitHub API, resulting in a 401 Unauthorized response. This makes the entire governance verification script non-functional — check_branch will always fail because the API response won't contain valid branch protection data. The apply-governance.sh script correctly uses $GH_PAT at line 62, so this appears to be an accidental replacement in verify-governance.sh only.

Suggested change
-H "Authorization: Bearer ***"
-H "Authorization: Bearer $GH_PAT"
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +79 to +84
dependency-review:
name: Dependency Review
uses: actions/dependency-review-action@b7c9a41be9f4fe210c6d6ff2f19a5258f8f6d62a # v4.5.1
if: github.event_name == 'pull_request'
with:
config-file: .github/dependency-review-config.yml No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 ci-fast.yml dependency-review job incorrectly uses a GitHub Action as a reusable workflow

The dependency-review job at ci-fast.yml:81 uses jobs.<job_id>.uses: actions/dependency-review-action@..., which is the syntax for calling a reusable workflow (i.e., a workflow file that defines on: workflow_call). However, actions/dependency-review-action is a regular GitHub Action, not a reusable workflow. This will cause a workflow validation error at runtime. The existing standalone dependency-review.yml workflow correctly uses it as a step within a job (with runs-on, steps, checkout, then the action). Since Dependency Review is a required status check per docs/BRANCHING.md and .github/PRODUCTION_GOVERNANCE_CHECKLIST.md, this broken job will block PR merges if this is the only source of that check name.

Prompt for agents
The dependency-review job in ci-fast.yml uses `jobs.<job_id>.uses:` syntax which is reserved for reusable workflows. `actions/dependency-review-action` is a regular GitHub Action, not a reusable workflow. This needs to be restructured as a normal job with `runs-on` and `steps`, similar to the existing `.github/workflows/dependency-review.yml` which correctly uses it as a step. The fix should either: (A) convert this to a proper job with steps (checkout + action), or (B) reference the existing `dependency-review.yml` as a reusable workflow if it supports `workflow_call`, or (C) remove this job from ci-fast.yml and rely on the standalone `dependency-review.yml` workflow (ensuring the check name matches what governance expects).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +54 to 55
if (ADAPTER != address(0) && adapter_ != address(0)) revert AdapterAlreadySet();
if (adapter_ == address(0)) revert ZeroAddress();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: RYLACreditLedger.setAdapter logic change is equivalent to original

The setAdapter condition was changed from if (ADAPTER != address(0)) revert AdapterAlreadySet() to if (ADAPTER != address(0) && adapter_ != address(0)) revert AdapterAlreadySet(). The comment says this allows re-setting when ADAPTER is zero after a failed deploy, but this was already possible with the old code (ADAPTER starts at zero). The only behavioral difference is which error is thrown when ADAPTER is already set and adapter_ is address(0): old code reverts with AdapterAlreadySet, new code reverts with ZeroAddress. Since both paths revert, the security property (once set, adapter cannot be changed) is preserved. The new condition is logically redundant but not harmful.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

pragma solidity >=0.7.0 <0.9.0;

contract MARKPoolVerifier {
contract Groth16Verifier {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: MARKPoolVerifier.sol renamed to Groth16Verifier but file path unchanged

The contract inside contracts/src/pool/verifier/MARKPoolVerifier.sol was renamed from contract MARKPoolVerifier to contract Groth16Verifier, and the pragma was widened from ^0.8.25 to >=0.7.0 <0.9.0. The pool-staging-deployment.yml was updated to use MARKPoolVerifier.sol:Groth16Verifier for forge create. However, IVerifier.sol uses uint256 types while the new verifier uses uint — these are aliases in Solidity so there's no ABI mismatch. The file path is unchanged (MARKPoolVerifier.sol), which is slightly confusing since the contract is now Groth16Verifier, but this follows the snarkjs default naming convention. References in MARKPool.sol:148 and deployment scripts (DeployMARKPool.s.sol:24) still refer to MARKPoolVerifier in comments/env vars, which is acceptable since they reference the file, not the contract name.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +122 to 134
// Use 5-input Poseidon with domain-separated dstChainId (NOT addition to blinding)
component outCommit[nOut];
for (i = 0; i < nOut; i++) {
outCommit[i] = Poseidon(4);
outCommit[i] = Poseidon(5);
outCommit[i].inputs[0] <== DOMAIN_VERSION * 100 + DOMAIN_NOTE_COMMITMENT;
outCommit[i].inputs[1] <== outAmount[i];
outCommit[i].inputs[2] <== outSecret[i];
outCommit[i].inputs[3] <== outBlinding[i] + dstChainId;
outCommit[i].inputs[3] <== outBlinding[i];
// Domain-separated dstChainId prevents cross-chain commitment reuse
outCommit[i].inputs[4] <== dstChainId + DOMAIN_DST_CHAIN * 100;
computedOutCommitment[i] <== outCommit[i].out;
computedOutCommitment[i] === outCommitment[i];
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Circuit output commitment change from 4-input to 5-input Poseidon is a breaking change

The output commitment computation changed from Poseidon(4) with outBlinding[i] + dstChainId as the 4th input to Poseidon(5) with separate outBlinding[i] and dstChainId + DOMAIN_DST_CHAIN * 100 inputs. This is a domain-separation improvement that prevents a class of cross-chain attacks where blinding + dstChainId on one chain could collide with a different blinding' + dstChainId' on another chain. The test file MARKPool.test.mjs:90-91 was correctly updated to match. However, this is a breaking change — any existing proofs or commitments generated with the old 4-input scheme would be invalid. The verification key constants in MARKPoolVerifier.sol were also regenerated to match the new circuit. Since the pool is pre-production (per KI-8 in KNOWN_ISSUES.md), this is acceptable, but it should be noted in release documentation.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 35 to 36
token: ${{ secrets.GITHUB_TOKEN }}
persist-credentials: true
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: checkout-retry action silently ignores token and persist-credentials inputs

In _reusable-frontend-checks.yml:35-36, token and persist-credentials are passed to the ./.github/actions/checkout-retry composite action. However, the checkout-retry/action.yml only declares submodules, fetch-depth, and clean as inputs. GitHub Actions silently ignores unknown inputs for composite actions. The checkout-retry action internally hardcodes token: ${{ github.token }} and persist-credentials: true, so the intended behavior is preserved. These extra inputs are dead configuration but not harmful.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .mise.toml
run = [
"uv venv",
"uv pip install slither-analyzer==0.11.5 semgrep pytest",
"uv pip install pytest",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 Semgrep and Slither removed from mise setup task but CI relies on mise to provide them

The .mise.toml setup task removed slither-analyzer and semgrep from the uv pip install command (line 23). The new contracts-security.yml reusable workflow uses jdx/mise-action then runs semgrep and make slither-core directly. The Makefile's semgrep target checks if the command exists and errors if not (contracts/Makefile:35-36). The slither-core target similarly requires slither. These tools could be available via uv run (which auto-installs) or via mise plugins, but they're not declared in .mise.toml [tools]. The [tasks.slither] uses uv run slither and [tasks.semgrep] uses uvx semgrep scan, both of which auto-install. However, the CI workflow runs semgrep --config ... directly (not via uvx or uv run), so it depends on semgrep being pre-installed by mise. This may work if mise has a semgrep backend, but warrants verification.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +176 to +184
component relayerUpperBound = LessThan(161);
// 2^160 as constant
var RELAYER_MAX = 1;
for (var k = 0; k < 160; k++) {
RELAYER_MAX = RELAYER_MAX * 2;
}
relayerUpperBound.in[0] <== relayer;
relayerUpperBound.in[1] <== RELAYER_MAX;
relayerUpperBound.out === 1;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Relayer constraint changed from Num2Bits to LessThan — different failure semantics

The old circuit used Num2Bits(160) to constrain the relayer, which asserts the value fits in 160 bits (i.e., relayer < 2^160). The new code uses LessThan(161) with RELAYER_MAX = 2^160, which checks relayer < 2^160 via a comparison circuit. Both enforce the same range, but LessThan uses more constraints (it internally decomposes both inputs). The Num2Bits(160) approach is more efficient for a simple range check. The change is correct but slightly less efficient. The test file correctly validates the boundary cases (2^160 fails, 2^160-1 passes).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +2 to +9
on:
pull_request:
branches: [dev, main]
push:
branches: [dev, main]
workflow_dispatch:
schedule:
- cron: '30 2 * * *' # Daily at 2:30am UTC
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 ci-full.yml runs both ci-fast and ci-full on every PR, causing duplicate work

Both ci-fast.yml and ci-full.yml trigger on pull_request: branches: [dev, main] and push: branches: [dev, main]. This means every PR and push will trigger BOTH workflows. ci-full.yml then calls ci-fast.yml as a reusable workflow (line 22), so ci-fast jobs run twice: once from the direct ci-fast.yml trigger and once nested inside ci-full.yml. This doubles CI resource usage. The concurrency groups are different (CI Fast-... vs CI Full-...) so they won't cancel each other. This is a design choice but results in redundant CI runs.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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