Skip to content

ci(solidity): run contracts CI on stacked PRs, and filter it by path - #4217

Open
mswilkison wants to merge 1 commit into
mainfrom
ci/contracts-path-filter
Open

ci(solidity): run contracts CI on stacked PRs, and filter it by path#4217
mswilkison wants to merge 1 commit into
mainfrom
ci/contracts-path-filter

Conversation

@mswilkison

@mswilkison mswilkison commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Both contracts workflows only trigger on pull_request targeting main:

on:
  pull_request:
    branches:
      - main

So a PR based on any other branch gets no solidity CI at all. That is currently true of the entire in-flight stack — #4203, #4206, #4207 and #4208 have not run a single contracts job between them. #4207 adds a tsc --noEmit gate to contracts-lint; that gate has never executed in CI.

Each PR only gets verified when it is retargeted to main, which is the moment it merges — the least useful time to find out.

Why this is three changes and not one

Opening the trigger on its own is wrong. contracts-detect-changes was a stub:

- name: Set path-filter output
  id: set-output
  run: echo "path-filter=true" >> $GITHUB_OUTPUT

Unconditionally true, so both suites would then run on every PR to the repo, including client-only Go changes. And it turns out nothing consumed the output — none of the four jobs carried an if: referencing it, so the filter has been decorative for as long as it has existed. Wiring a real filter without adding those conditions would have changed nothing at all.

So:

  1. Drop the branches: [main] restriction.
  2. Replace the stub with a real dorny/paths-filter@v2, scoped to the package the workflow builds — matching contracts-ecdsa-docs.yml, contracts-random-beacon-docs.yml and client.yml, which all already do this.
  3. Add the if: that consumes the result, in the exact form client.yml uses:
if: |
  github.event_name != 'pull_request'
    || needs.contracts-detect-changes.outputs.path-filter == 'true'

The github.event_name != 'pull_request' half keeps workflow_dispatch runs unconditional, since the filter step is skipped for those and the output would be empty.

Two things checked rather than assumed

Filtering per package is safe. ecdsa depends on @keep-network/random-beacon through the npm development dist-tag, not the local sources, so a random-beacon-only change cannot affect an ecdsa build.

Deployment jobs are untouched. contracts-deployment-testnet and contracts-dapp-development-deployment-testnet gate on github.event_name == 'workflow_dispatch' and need contracts-build-and-test, which still runs unconditionally for that event.

Verification

Both files parse (js-yaml), pull_request resolves to the bare all-branches form, all four jobs in each workflow are gated, and contracts-detect-changes now runs actions/checkout + dorny/paths-filter.

Beyond that, this PR is its own test case: it edits both workflow files, and both are named in their own filters, so both suites should run here. If they do, the trigger and the filter are both correct.

Summary by CodeRabbit

  • Chores
    • Updated contract validation workflows to run for pull requests targeting any branch.
    • Added change detection so contract checks run only when relevant Solidity files or workflow configurations are modified.
    • Improved conditional execution for linting, security analysis, builds, tests, and deployment dry runs.

Both contracts workflows only triggered on `pull_request` targeting
`main`, so a PR based on another branch got no solidity CI at all. Every
PR in a stack is therefore unverified until the moment it is retargeted,
which is the moment it merges -- the least useful time to find out.

Opening the trigger alone would run both suites on every PR to the repo,
including client-only Go changes, because `contracts-detect-changes` was
a stub that echoed `path-filter=true` unconditionally. Worse, nothing
consumed the output: none of the four jobs had an `if:` referencing it,
so the filter has been decorative for as long as it has existed.

So this does three things together, since any one alone is wrong:

- drops the `branches: [main]` restriction,
- replaces the stub with a real `dorny/paths-filter@v2` scoped to the
  package the workflow builds, matching the two contracts-*-docs
  workflows and client.yml,
- adds the `if:` that actually consumes the result, in the form client.yml
  already uses, so `workflow_dispatch` runs continue to be unconditional.

Filtering per package is safe: `ecdsa` depends on
`@keep-network/random-beacon` through the npm `development` tag, not the
local sources, so a random-beacon-only change cannot alter an ecdsa
build.

Deployment jobs are untouched. They gate on
`github.event_name == 'workflow_dispatch'` and need
`contracts-build-and-test`, which still runs unconditionally for that
event.

This PR edits both workflow files, so it exercises both filters.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The ECDSA and random-beacon contract workflows now run for pull requests targeting any branch, detect relevant file changes with dorny/paths-filter, and conditionally execute contract validation and deployment dry-run jobs.

Changes

Contract workflow filtering

Layer / File(s) Summary
Pull request triggers and path detection
.github/workflows/contracts-ecdsa.yml, .github/workflows/contracts-random-beacon.yml
Pull request branch restrictions were removed, and each workflow now detects changes in its contract directory or workflow file.
Conditional contract jobs
.github/workflows/contracts-ecdsa.yml, .github/workflows/contracts-random-beacon.yml
Lint, Slither, build-and-test, and deployment dry-run jobs run conditionally for pull request changes matching the detected paths.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: piotr-roslaniec, lrsaturnino

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main CI workflow change: enabling stacked PR runs and adding path-based filtering.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/contracts-path-filter

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/contracts-ecdsa.yml (1)

38-39: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Remove the unnecessary checkout from both PR detector jobs. dorny/paths-filter can use the pull-request API directly; explicitly grant pull-requests: read, and disable credential persistence on any checkout that remains.

  • .github/workflows/contracts-ecdsa.yml#L38-L39: remove or harden the detector checkout.
  • .github/workflows/contracts-random-beacon.yml#L38-L39: remove or harden the detector checkout.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/contracts-ecdsa.yml around lines 38 - 39, Remove the
conditional detector checkout from the PR detector jobs in
.github/workflows/contracts-ecdsa.yml lines 38-39 and
.github/workflows/contracts-random-beacon.yml lines 38-39, relying on
dorny/paths-filter’s pull-request API access instead. Explicitly grant
pull-requests: read permission in both jobs; if either checkout remains, set
credential persistence to false.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/contracts-ecdsa.yml:
- Line 40: Update the dorny/paths-filter action in
.github/workflows/contracts-ecdsa.yml at line 40 and
.github/workflows/contracts-random-beacon.yml at line 40 from the legacy v2
Node16 release to a current Node20+/Node24 release, and pin each action
reference immutably to its commit SHA rather than using a mutable version tag.

---

Nitpick comments:
In @.github/workflows/contracts-ecdsa.yml:
- Around line 38-39: Remove the conditional detector checkout from the PR
detector jobs in .github/workflows/contracts-ecdsa.yml lines 38-39 and
.github/workflows/contracts-random-beacon.yml lines 38-39, relying on
dorny/paths-filter’s pull-request API access instead. Explicitly grant
pull-requests: read permission in both jobs; if either checkout remains, set
credential persistence to false.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7be31235-2508-4225-9703-0e7719469314

📥 Commits

Reviewing files that changed from the base of the PR and between 0085279 and 2d3131a.

📒 Files selected for processing (2)
  • .github/workflows/contracts-ecdsa.yml
  • .github/workflows/contracts-random-beacon.yml

run: echo "path-filter=true" >> $GITHUB_OUTPUT
- uses: actions/checkout@v3
if: github.event_name == 'pull_request'
- uses: dorny/paths-filter@v2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Tracked workflow files matching dorny/paths-filter:"
for f in $(git ls-files '.github/workflows/*.yml' '.github/workflows/*.yaml'); do
  if grep -q 'dorny/paths-filter' "$f"; then
    echo "### $f"
    grep -n 'dorny/paths-filter' "$f"
  fi
done

echo
echo "Relevant dorny/paths-filter blocks:"
for f in .github/workflows/contracts-ecdsa.yml .github/workflows/contracts-random-beacon.yml; do
  if [ -f "$f" ]; then
    echo "### $f"
    nl -ba "$f" | sed -n '34,46p'
  else
    echo "missing $f"
  fi
done

echo
echo "Check whether refs exist locally or via public repo metadata:"
if command -v gh >/dev/null 2>&1; then
  for ref in dorny/paths-filter:v2 dorny/paths-filter:v3; do
    echo "ref $ref"
    gh api repos/dorny/paths-filter/git/refs/tags/${ref#*:} --jq '{ref, object_type: .object.type, object_sha: .object.sha}' || true
    sha=${ref#*:}
    if [ "$sha" = "$ref" ]; then
      # not a tag with tag prefix ok
      true
    fi
  done
else
  echo "gh command not available"
fi

echo
echo "Public release/tag availability from GitHub (lightweight probe):"
curl -fsSL -o /tmp/paths-tags.json "https://api.github.com/repos/dorny/paths-filter/tags" && jq '.[0:10] | map({name, commit_sha: .commit.sha})' /tmp/paths-tags.json || true

Repository: threshold-network/keep-core

Length of output: 798


🌐 Web query:

dorny paths-filter GitHub release v2 latest

💡 Result:

The latest version of the dorny/paths-filter GitHub action as of July 27, 2026, is v4.0.2 [1]. The project has evolved significantly beyond version 2 [2][3]. Version 4 represents a major update that includes support for Node 24 and contains breaking changes compared to previous versions [4][5][6]. Users are encouraged to use the latest release (v4.x) for current projects [4]. Version 2 is now considered a legacy major version [2][3].

Citations:


🌐 Web query:

dorny/paths-filter v3 v2 Node version action.yml

💡 Result:

The dorny/paths-filter GitHub Action uses different Node.js runtimes depending on the major version selected in the action.yml configuration [1][2]. - Version v4.x (current): Uses node24 [3][4][2]. This transition was implemented in v4.0.0 to support the GitHub Actions migration to Node 24 [3][4]. - Version v3.x: Uses node20 [5][6][2]. This was the standard for v3.x releases [5][6]. - Version v2.x: Uses node16 [5]. This is the legacy runtime for v2.x [5]. You can verify the specific runtime used by an installed version by inspecting the runs section in the action.yml file within the respective release tag or branch [2]. The update from node20 to node24 in v4.0.0 was a non-functional change intended to maintain compatibility with GitHub's runner environment deprecation schedule [4].

Citations:


🌐 Web query:

GitHub Actions JavaScript v1/v2 node16 deprecation date

💡 Result:

Node.js 16 reached its end of life within GitHub Actions on November 12, 2024 [1]. Following the end of Node.js 16 support, GitHub Actions removed Node.js 16 from the runner environment, meaning actions configured to run on Node 16 (often associated with older v1 or v2 versions of GitHub Actions) ceased to function correctly on that date [1]. To resolve issues related to this deprecation, users must update their workflow definitions to use newer versions of actions (typically v3 or v4+) that are configured to run on newer Node.js runtimes (such as Node 20 or Node 24) [2][1][3]. While GitHub previously provided an environment variable (ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true) as a temporary opt-out to allow continued use of Node 16 during the transition period, that option is no longer valid following the November 2024 cutoff [1][4]. For context, GitHub has since moved on to deprecating Node.js 20, which is scheduled to reach its end of life on GitHub Actions runners on June 16, 2026, with a transition to Node 24 [2].

Citations:


🌐 Web query:

dorny paths-filter Node 20 Node 24 support v4 action.yml master

💡 Result:

As of July 27, 2026, the dorny/paths-filter action supports Node 24, which was introduced in version 4.0.0 [1]. The action was updated to use node24 in its action.yml file to maintain compatibility with GitHub Actions runners [2][3]. This change was part of a major version bump to v4.0.0 on March 12, 2026, which replaced the previous node20 runtime [1][2][3]. Users are encouraged to use version 4.0.0 or higher to avoid deprecation warnings and ensure compatibility with GitHub's updated environment [4][5]. You can verify this in the repository's action.yml file, which specifies using: 'node24' [3].

Citations:


Update dorny/paths-filter to a current Node20+/Node24 release.

dorny/paths-filter@v2 is a legacy node16 action; v3 uses Node20 and v4 is Node24. Pin current releases immutably instead of moving tags.

  • .github/workflows/contracts-ecdsa.yml
  • .github/workflows/contracts-random-beacon.yml
🧰 Tools
🪛 actionlint (1.7.12)

[error] 40-40: the runner of "dorny/paths-filter@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

📍 Affects 2 files
  • .github/workflows/contracts-ecdsa.yml#L40-L40 (this comment)
  • .github/workflows/contracts-random-beacon.yml#L40-L40
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/contracts-ecdsa.yml at line 40, Update the
dorny/paths-filter action in .github/workflows/contracts-ecdsa.yml at line 40
and .github/workflows/contracts-random-beacon.yml at line 40 from the legacy v2
Node16 release to a current Node20+/Node24 release, and pin each action
reference immutably to its commit SHA rather than using a mutable version tag.

Source: Linters/SAST tools

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