Skip to content

chore: pin GitHub Actions to immutable commit SHAs (FEPLAT-5068) - #51

Draft
casper-phantom[bot] wants to merge 1 commit into
masterfrom
casper/feplat-5068-pin-github-action-shas
Draft

chore: pin GitHub Actions to immutable commit SHAs (FEPLAT-5068)#51
casper-phantom[bot] wants to merge 1 commit into
masterfrom
casper/feplat-5068-pin-github-action-shas

Conversation

@casper-phantom

@casper-phantom casper-phantom Bot commented Aug 5, 2026

Copy link
Copy Markdown

Closes FEPLAT-5068

Note

Low risk: Every SHA is the commit its tag already resolved to, so CI runs the same action code as before the change and no workflow logic, inputs, or versions were altered.

Summary

  • Replaces every mutable action tag across the seven workflows with the 40-character commit SHA that tag resolved to, keeping the version as a trailing comment so reviewers can still read the intended version.
  • Removes the ability for a moved upstream tag or a compromised action repository to change executable CI code without a change landing here.
  • Each pinned action is a JavaScript action with no nested uses:, so the pinned closure is complete and no recursive or vendored pinning is needed.
  • Also pins actions/stale@v3.0.14 in stale.yml, which the finding did not list but carries the same mutable-tag exposure.

Pinned references

Each SHA is the commit the previous tag pointed to at the time of this change, verified against the upstream repository.

  • actions/checkout v4 -> 11d5960a326750d5838078e36cf38b85af677262 (v4.4.0) - android-ci, detox, ios-ci, macos-ci, release, windows-ci
  • actions/setup-node v4 -> 49933ea5288caeca8642d1e84afbd3f7d6820020 (v4.4.0) - android-ci, detox, ios-ci, macos-ci, windows-ci
  • actions/setup-node v3 -> 3235b876344d2a9aa001b8d1453c930bba69e610 (v3.9.1) - release
  • actions/setup-java v4 -> cf277c60eb25467037889841efdb72551f06f6c3 (v4.9.1) - android-ci
  • gradle/gradle-build-action v2 -> a8f75513eafdebd8141bd1cd4e30fcd194af8dfa (v2.12.0) - android-ci
  • microsoft/setup-msbuild v1.1.3 -> 34cfbaee7f672c76950673338facd8a73f637506 - windows-ci
  • actions/stale v3.0.14 -> 87c2b794b9b47a9bec68ae03c01aeb572ffebdb1 - stale

changesets/action in release.yml was already pinned and is unchanged.

Verification

  • No uses: reference in .github/workflows/ resolves to anything other than a 40-character hex SHA.
  • Every SHA was confirmed to exist in its upstream repository and to be the commit the replaced tag resolved to.
  • Each pinned action declares a JavaScript runs.using and contains no nested uses:, so there is no deeper mutable edge to pin. That matches the finding's "no recursive mutable references" conclusion.
  • All seven workflow files still parse as YAML.

Follow-ups (deliberately not in this PR)

These are pre-existing and unchanged by pinning, but worth separate tickets:

  • actions/setup-node@v3 in release.yml is a major version behind the rest of the repo.
  • gradle/gradle-build-action is deprecated upstream in favor of gradle/actions/setup-gradle.
  • actions/stale@v3.0.14 declares the long-retired node12 runtime.
  • actions/setup-java@v4.9.1 emits an upstream deprecation warning for v4.
  • There is no .github/dependabot.yml covering the github-actions ecosystem, so these pins will not be refreshed automatically.

casper-run-id: 019fd2d5-2366-7b72-8760-b5d0fc4bf411

Summary by CodeRabbit

  • Chores
    • Pinned continuous integration, release, and maintenance workflow actions to immutable versions.
    • Improved build and release process consistency without changing existing workflow configurations.

Every action reference in the active workflows resolved through a mutable
tag, so a moved tag or a compromised upstream could change executable CI
code without any change landing in this repository. Each reference is now
pinned to the 40-character commit SHA the tag resolved to at the time of
the change, with the version retained as a trailing comment.

All pinned actions are JavaScript actions with no nested `uses:`, so the
pinned closure is complete and no recursive pinning is required.

Closes FEPLAT-5068

Co-authored-by: casper-phantom[bot] <208212958+casper-phantom[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Workflow action pinning

Layer / File(s) Summary
CI workflow action pins
.github/workflows/android-ci.yml, .github/workflows/detox.yml, .github/workflows/ios-ci.yml, .github/workflows/macos-ci.yml, .github/workflows/windows-ci.yml
CI workflows now reference immutable commit SHAs for their GitHub Actions dependencies. Existing versions and configuration remain unchanged.
Release and maintenance action pins
.github/workflows/release.yml, .github/workflows/stale.yml
Release and stale workflows now reference fixed commit SHAs for their GitHub Actions dependencies. Version comments remain where present.

Suggested reviewers: jamonholmgren, titozzz

🚥 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 and concisely describes the main change: pinning GitHub Actions to immutable commit SHAs.
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 casper/feplat-5068-pin-github-action-shas

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

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedgithub/​gradle/​gradle-build-action@​fe583dc97e032f41ccc310ea5176f2d7306abbc4 ⏵ a8f75513eafdebd8141bd1cd4e30fcd194af8dfa98 +17100100100100

View full report

@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

🤖 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/android-ci.yml:
- Line 31: Update the workflow step using gradle/gradle-build-action to
gradle/actions/setup-gradle, preserving gradle-version: wrapper and
build-root-directory: example/android. Remove the action’s arguments
configuration and add a separate run step that executes the existing Gradle
command.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2204d7bc-57d4-453b-9f54-8a839078b62c

📥 Commits

Reviewing files that changed from the base of the PR and between 4b99048 and a24e746.

📒 Files selected for processing (7)
  • .github/workflows/android-ci.yml
  • .github/workflows/detox.yml
  • .github/workflows/ios-ci.yml
  • .github/workflows/macos-ci.yml
  • .github/workflows/release.yml
  • .github/workflows/stale.yml
  • .github/workflows/windows-ci.yml

shell: bash
- name: Build Android test app
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@a8f75513eafdebd8141bd1cd4e30fcd194af8dfa # v2.12.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
file=".github/workflows/android-ci.yml"
printf '%s\n' "--- workflow context ---"
sed -n '1,100p' "$file"
printf '%s\n' "--- Gradle action references ---"
rg -n -C 3 'gradle/(gradle-build-action|actions)|setup-gradle|build-action' .github
printf '%s\n' "--- repository metadata ---"
if command -v gh >/dev/null 2>&1; then
  gh api repos/gradle/gradle-build-action --jq '{archived,disabled,default_branch,updated_at}'
  gh api repos/gradle/actions --jq '{archived,disabled,default_branch,updated_at}'
else
  curl -fsSL https://api.github.com/repos/gradle/gradle-build-action | jq '{archived,disabled,default_branch,updated_at}'
  curl -fsSL https://api.github.com/repos/gradle/actions | jq '{archived,disabled,default_branch,updated_at}'
fi

Repository: phantom/react-native-webview

Length of output: 2171


🌐 Web query:

Gradle Build Action archived replacement gradle/actions/setup-gradle migration existing inputs

💡 Result:

The gradle/gradle-build-action has been officially archived and superseded by gradle/actions/setup-gradle [1][2]. This change is part of an effort to standardize Gradle's GitHub Actions, aligning them with other common actions like setup-java or setup-node [3]. Key migration details: 1. Replacement: Replace any instance of uses: gradle/gradle-build-action@v3 (or earlier) in your GitHub Actions workflow files with uses: gradle/actions/setup-gradle@v6 (or the latest available version) [3][4][1]. 2. Functionality: The two actions are functionally equivalent, and existing workflows using v3 of the old action will transparently delegate to the new setup-gradle action [1][5]. 3. Arguments Parameter Deprecation: The arguments parameter, previously used to execute Gradle builds directly within the action, is deprecated [3]. You should migrate away from this pattern by splitting your workflow step into two parts: - Step 1: Call setup-gradle to configure the environment. - Step 2: Use a standard run step (e.g., run:./gradlew build) to execute your build [3]. 4. Wrapper Validation: The setup-gradle action now automatically validates the Gradle Wrapper [4][6]. If you were using the standalone wrapper-validation action previously, it is likely no longer necessary [6][7]. For detailed documentation and advanced configuration, refer to the official gradle/actions repository [3][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -fsSL https://raw.githubusercontent.com/gradle/gradle-build-action/v2.12.0/action.yml \
  -o "$tmpdir/old.yml"
curl -fsSL https://raw.githubusercontent.com/gradle/actions/v6/action.yml \
  -o "$tmpdir/new.yml"
curl -fsSL https://raw.githubusercontent.com/gradle/actions/main/docs/deprecation-upgrade-guide.md \
  -o "$tmpdir/guide.md"

python3 - "$tmpdir/old.yml" "$tmpdir/new.yml" "$tmpdir/guide.md" <<'PY'
import re, sys
from pathlib import Path

old, new, guide = map(Path, sys.argv[1:])
old_text, new_text, guide_text = old.read_text(), new.read_text(), guide.read_text()

def inputs(text):
    block = text.split("inputs:", 1)[1] if "inputs:" in text else ""
    return re.findall(r"(?m)^  ([A-Za-z0-9_-]+):\s*$", block)

print("old action inputs:", inputs(old_text))
print("new action inputs:", inputs(new_text))
for name in ("gradle-version", "arguments", "build-root-directory"):
    print(f"{name}: old={'yes' if re.search(rf'(?m)^  {re.escape(name)}:\\s*$', old_text) else 'no'} "
          f"new={'yes' if re.search(rf'(?m)^  {re.escape(name)}:\\s*$', new_text) else 'no'}")
for term in ("arguments", "build-root-directory", "gradle-version", "setup-gradle"):
    hits = [line.strip() for line in guide_text.splitlines() if term in line]
    print(f"guide {term}:", hits[:8])
PY

Repository: phantom/react-native-webview

Length of output: 435


🏁 Script executed:

#!/bin/bash
set -eu
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -fsSL https://raw.githubusercontent.com/gradle/gradle-build-action/v2.12.0/action.yml \
  -o "$tmpdir/old.yml"
curl -fsSL https://raw.githubusercontent.com/gradle/actions/v6/action.yml \
  -o "$tmpdir/new.yml"
curl -fsSL https://raw.githubusercontent.com/gradle/actions/main/docs/deprecation-upgrade-guide.md \
  -o "$tmpdir/guide.md"

python3 - "$tmpdir/old.yml" "$tmpdir/new.yml" "$tmpdir/guide.md" <<'PY'
import re, sys
from pathlib import Path

old, new, guide = map(Path, sys.argv[1:])
old_text = old.read_text()
new_text = new.read_text()
guide_text = guide.read_text()

def inputs(text):
    block = text.split("inputs:", 1)[1] if "inputs:" in text else ""
    return re.findall(r"(?m)^  ([A-Za-z0-9_-]+):\s*$", block)

print("old action inputs:", inputs(old_text))
print("new action inputs:", inputs(new_text))
for name in ("gradle-version", "arguments", "build-root-directory"):
    pattern = rf"(?m)^  {re.escape(name)}:\s*$"
    old_has = bool(re.search(pattern, old_text))
    new_has = bool(re.search(pattern, new_text))
    print(f"{name}: old={'yes' if old_has else 'no'} new={'yes' if new_has else 'no'}")

for term in ("arguments", "build-root-directory", "gradle-version", "setup-gradle"):
    hits = [line.strip() for line in guide_text.splitlines() if term in line]
    print(f"guide {term}:", hits[:8])
PY

Repository: phantom/react-native-webview

Length of output: 2182


Other (CWE-1104)

Reachability: External

Replace the archived Gradle action.

Replace gradle/gradle-build-action with gradle/actions/setup-gradle. Move the arguments command to a separate run step. Preserve gradle-version: wrapper and build-root-directory: example/android.

🧰 Tools
🪛 zizmor (1.29.0)

[warning] 31-31: action or reusable workflow from archived repository (archived-uses): repository is archived

(archived-uses)

🤖 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/android-ci.yml at line 31, Update the workflow step using
gradle/gradle-build-action to gradle/actions/setup-gradle, preserving
gradle-version: wrapper and build-root-directory: example/android. Remove the
action’s arguments configuration and add a separate run step that executes the
existing Gradle command.

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