ci: pin all GitHub Actions to SHAs + add 7-day Dependabot cooldown#1455
Conversation
Tag and branch refs (@v6, @main, @stable) let a compromised maintainer account re-point the ref under us. Pin every `uses:` to a full commit SHA with the original ref in a trailing comment so Dependabot keeps both in sync. Cooldown defers update PRs for 7 days after a release, giving time for compromises to be flagged before they land here.
WalkthroughThis pull request pins all GitHub Actions across CI, build, and release workflows from floating tags and branches to specific commit SHAs for deterministic, reproducible builds. A Dependabot cooldown configuration is added to control update frequency. Changes span foundational CI workflows, Docker and artifact infrastructure, and language-specific release pipelines for Rust, Kotlin, Swift, Python, and JavaScript packages. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/libmoq.yml:
- Around line 37-39: Update both actions/checkout steps (the lines using
actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd) to explicitly disable
persisting credentials by adding persist-credentials: false under their with:
blocks so the build and release jobs do not keep Git credentials in the
workspace.
In @.github/workflows/moq-gst.yml:
- Around line 64-67: The checkout step using actions/checkout (currently pinned
to de0fac2...) is missing persist-credentials: false so the write-scoped
GITHUB_TOKEN is being persisted; update the actions/checkout step by adding
persist-credentials: false under its with: block (keep fetch-depth: 0 unchanged)
so credentials are not stored in the local git config while still allowing tag
listing and gh-based release creation.
In @.github/workflows/release-rs.yml:
- Around line 28-32: The create-github-app-token step (uses:
actions/create-github-app-token, id: generate-token) currently mints an
installation token with full installation permissions; add explicit permission-*
inputs to this step to scope the token to least privilege required by the job
(for example: permission-actions, permission-packages, permission-workflows,
permission-contents, etc.) and remove any broad access: specify only the exact
permission names and levels the downstream steps need so the generated token is
restricted.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7ea0bf81-f7bf-496c-b79e-7dd2bebd3bfd
📒 Files selected for processing (13)
.github/dependabot.yml.github/workflows/cachix.yml.github/workflows/check.yml.github/workflows/docker.yml.github/workflows/libmoq.yml.github/workflows/moq-gst.yml.github/workflows/moq-relay.yml.github/workflows/release-js.yml.github/workflows/release-kt.yml.github/workflows/release-py.yml.github/workflows/release-rs.yml.github/workflows/release-swift.yml.github/workflows/update-flake.yml
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| with: | ||
| fetch-depth: 0 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Inspect release script for authenticated git operations:"
rg -n -C2 '\bgit\s+(push|pull|fetch|remote|credential)\b' .github/scripts/release.sh
echo
echo "Inspect workflow checkout steps:"
rg -n -C2 'actions/checkout|persist-credentials' .github/workflows/libmoq.ymlRepository: moq-dev/moq
Length of output: 112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== libmoq.yml lines 20-110 ==="
nl -ba .github/workflows/libmoq.yml | sed -n '20,110p'
echo
echo "=== libmoq.yml checkout steps (with context) ==="
rg -n -C3 'uses:\s*actions/checkout@' .github/workflows/libmoq.yml || true
rg -n -C3 'persist-credentials' .github/workflows/libmoq.yml || true
echo
echo "=== Scripts directory listing ==="
ls -la .github/scripts || true
echo
echo "=== Search for release script invocation in workflow ==="
rg -n -C2 'release\.sh|scripts/.*release|\.github/scripts' .github/workflows/libmoq.yml || true
echo
echo "=== release.sh (if exists): any git usage ==="
if [ -f .github/scripts/release.sh ]; then
rg -n '\bgit\b' .github/scripts/release.sh || true
rg -n -C2 'push|pull|fetch|remote|credential' .github/scripts/release.sh || true
else
echo "Missing: .github/scripts/release.sh"
fi
echo
echo "=== Any other shell scripts invoked by workflow: any git usage ==="
rg -n -C2 '\.github/scripts/|bash\s+\.github/scripts/|sh\s+\.github/scripts/' .github/workflows/libmoq.yml || true
# Best-effort: find referenced scripts in the workflow and scan them for git
scripts=$(rg -o '\.github/scripts/[^"'\'' ]+' .github/workflows/libmoq.yml | sort -u || true)
if [ -n "${scripts:-}" ]; then
echo "$scripts" | while read -r s; do
if [ -f "$s" ]; then
echo "--- $s (git lines) ---"
rg -n '\bgit\b' "$s" || true
else
echo "--- $s (missing) ---"
fi
done
fiRepository: moq-dev/moq
Length of output: 148
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== libmoq.yml excerpt (lines 20-60) ==="
sed -n '20,60p' .github/workflows/libmoq.yml
echo
echo "=== libmoq.yml excerpt (lines 60-100) ==="
sed -n '60,100p' .github/workflows/libmoq.yml
echo
echo "=== Checkout steps + persist-credentials in workflow ==="
rg -n -C3 'uses:\s*actions/checkout@' .github/workflows/libmoq.yml || true
rg -n 'persist-credentials' .github/workflows/libmoq.yml || true
echo
echo "=== Scripts directory listing ==="
ls -la .github/scripts || true
echo
echo "=== Workflow: which scripts are invoked? ==="
rg -n -C2 '\.github/scripts/|bash\s+\.github/scripts|sh\s+\.github/scripts' .github/workflows/libmoq.yml || true
echo
echo "=== Any release.sh reference in workflow ==="
rg -n 'release\.sh' .github/workflows/libmoq.yml || true
echo
echo "=== release.sh (if exists): any git usage ==="
if [ -f .github/scripts/release.sh ]; then
rg -n '\bgit\b' .github/scripts/release.sh || true
rg -n -C2 'push|pull|fetch|remote|credential' .github/scripts/release.sh || true
else
echo "Missing: .github/scripts/release.sh"
fi
echo
echo "=== Any git usage in all .github/scripts/* ==="
rg -n '\bgit\b' .github/scripts || trueRepository: moq-dev/moq
Length of output: 4410
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== .github/scripts/release.sh (entire file with line numbers if possible) ==="
# Fallback: if cat -n exists, use it; otherwise use awk.
if command -v cat >/dev/null; then
if cat -n .github/scripts/release.sh >/dev/null 2>&1; then
cat -n .github/scripts/release.sh | sed -n '1,220p'
else
awk '{printf "%5d\t%s\n", NR, $0}' .github/scripts/release.sh | sed -n '1,220p'
fi
else
echo "cat missing"
fi
echo
echo "=== All git command lines in release.sh ==="
rg -n '^\s*git\s' .github/scripts/release.sh || true
echo
echo "=== All occurrences of word 'git' in release.sh ==="
rg -n '\bgit\b' .github/scripts/release.sh || trueRepository: moq-dev/moq
Length of output: 3992
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Find which scripts are executed by libmoq.yml ==="
rg -n '\b(run:|bash\s+-lc|sh\s+-c)\s*' .github/workflows/libmoq.yml
echo
echo "=== Inspect rs/libmoq/build.sh for git usage ==="
if [ -f rs/libmoq/build.sh ]; then
rg -n '\bgit\b' rs/libmoq/build.sh || true
rg -n 'push|pull|fetch|remote' rs/libmoq/build.sh || true
else
echo "Missing: rs/libmoq/build.sh"
fi
echo
echo "=== Inspect any referenced .sh files in workflow ==="
shs=$(rg -o '\.\/[^"\x27 ]+\.sh' .github/workflows/libmoq.yml | sort -u || true)
if [ -n "$shs" ]; then
echo "$shs"
while read -r sh; do
if [ -f "$sh" ]; then
echo "--- $sh (git lines) ---"
rg -n '\bgit\b' "$sh" || true
fi
done <<< "$shs"
else
echo "No other local .sh scripts referenced."
fiRepository: moq-dev/moq
Length of output: 623
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Check rs/libmoq/build.sh existence ==="
ls -la rs/libmoq/build.sh || true
echo
echo "=== Search for git usage in rs/libmoq/build.sh ==="
rg -n '\bgit\b' rs/libmoq/build.sh || true
echo
echo "=== Search for persist-credentials in workflow(s) ==="
rg -n 'persist-credentials' .github/workflows/libmoq.yml || true
echo
rg -n 'persist-credentials' .github/workflows || true
echo
echo "=== Search for git remote/auth operations in .github/scripts and rs/libmoq ==="
rg -n '\bgit\s+(push|pull|fetch|remote)\b' .github/scripts rs/libmoq || true
echo
echo "=== Extract release job step env around the create artifacts call ==="
# Print a slice that includes the create step (roughly near line 90-130 from earlier context)
sed -n '90,150p' .github/workflows/libmoq.ymlRepository: moq-dev/moq
Length of output: 1387
Disable persisted checkout credentials in libmoq.yml.
Add persist-credentials: false to both actions/checkout@de0fac... steps (build and release). ./.github/scripts/release.sh only lists local tags via git tag --list and performs GitHub release operations via gh using GH_TOKEN, so credentialed git remotes aren’t needed.
Suggested hardening
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
+ persist-credentials: false
...
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
+ persist-credentials: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 37-39: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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/libmoq.yml around lines 37 - 39, Update both
actions/checkout steps (the lines using
actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd) to explicitly disable
persisting credentials by adding persist-credentials: false under their with:
blocks so the build and release jobs do not keep Git credentials in the
workspace.
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/moq-gst.yml"
echo "== File existence =="
ls -la "$FILE"
echo
echo "== Relevant workflow context (lines ~1-140) =="
nl -ba "$FILE" | sed -n '1,160p'
echo
echo "== Extract checkout steps in this workflow =="
rg -n "uses:\s*actions/checkout@" -n "$FILE" -S
echo
echo "== Extract permissions and checkout configuration blocks =="
rg -n "permissions:|persist-credentials|fetch-depth:|checkout@" "$FILE" -n -S
echo
echo "== Find scripts invoked by this workflow release job =="
rg -n "\.github/scripts/" "$FILE" -S || true
echo
echo "== List repository scripts for release =="
find .github/scripts -maxdepth 2 -type f -print 2>/dev/null | sed 's|^\./||' || true
echo
echo "== Show .github/scripts/release.sh if present =="
if [ -f ".github/scripts/release.sh" ]; then
nl -ba .github/scripts/release.sh | sed -n '1,200p'
fi
echo
echo "== Search for git usage in scripts invoked by workflow =="
# If release.sh exists, scan it; also scan any other scripts referenced
if [ -f ".github/scripts/release.sh" ]; then
rg -n "git\s+(push|fetch|clone|config|credential|token|remote)" .github/scripts/release.sh -S || true
fi
# Additionally, scan any scripts referenced in moq-gst.yml
refs=$(rg -o "\.github/scripts/[^'\" )]+" "$FILE" -S || true)
if [ -n "$refs" ]; then
echo
echo "== Git usage in referenced scripts =="
echo "$refs" | sort -u | while read -r s; do
if [ -f "$s" ]; then
echo "--- $s ---"
rg -n "git\s+(push|fetch|clone|config|credential|token|remote)" "$s" -S || true
fi
done
fiRepository: moq-dev/moq
Length of output: 265
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/moq-gst.yml"
echo "== Workflow file (first 220 lines, with line numbers) =="
sed -n '1,220p' "$FILE" >/tmp/workflow_head.txt
# add line numbers without `nl`
awk '{printf "%6d\t%s\n", NR, $0}' /tmp/workflow_head.txt | sed -n '1,220p'
echo
echo "== checkout steps in moq-gst.yml =="
rg -n "uses:\s*actions/checkout@" "$FILE" -S || true
echo
echo "== permissions/persist-credentials/fetch-depth around checkout steps =="
rg -n "permissions:|persist-credentials|fetch-depth:|checkout@" "$FILE" -S || true
echo
echo "== scripts referenced by moq-gst.yml =="
# gather likely script invocations
rg -n "\.github/scripts/|scripts/|release\.sh|moq-gst" "$FILE" -S || true
echo
echo "== List .github/scripts directory =="
if [ -d ".github/scripts" ]; then
find .github/scripts -maxdepth 2 -type f -print 2>/dev/null | sed 's|^\./||' | sort || true
else
echo "No .github/scripts directory"
fi
echo
echo "== Show release.sh if present =="
if [ -f ".github/scripts/release.sh" ]; then
sed -n '1,240p' .github/scripts/release.sh | awk '{printf "%6d\t%s\n", NR, $0}'
else
echo "No .github/scripts/release.sh"
fi
echo
echo "== Search git usage in release.sh (if present) =="
if [ -f ".github/scripts/release.sh" ]; then
rg -n "git\s+(push|fetch|clone|config|credential|token|remote)" .github/scripts/release.sh -S || true
fi
echo
echo "== Search git usage in any script referenced by moq-gst.yml =="
# Extract referenced script paths (best-effort)
refs=$(rg -o "\.github/scripts/[^'\" )]+" "$FILE" -S || true)
if [ -n "$refs" ]; then
echo "$refs" | sort -u | while read -r s; do
if [ -f "$s" ]; then
echo "--- $s ---"
rg -n "git\s+(push|fetch|clone|config|credential|token|remote)" "$s" -S || true
fi
done
else
echo "No explicit .github/scripts/* references found in workflow text."
fiRepository: moq-dev/moq
Length of output: 8095
Disable credential persistence for the write-scoped release checkout.
The release job sets permissions: contents: write, but the actions/checkout step at lines 64-67 doesn’t set persist-credentials: false, so the GITHUB_TOKEN is persisted to the local git remote/config even though the workflow scripts only read tags (git tag --list) and use gh for release creation.
Proposed fix
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
+ persist-credentials: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 64-66: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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/moq-gst.yml around lines 64 - 67, The checkout step using
actions/checkout (currently pinned to de0fac2...) is missing
persist-credentials: false so the write-scoped GITHUB_TOKEN is being persisted;
update the actions/checkout step by adding persist-credentials: false under its
with: block (keep fetch-depth: 0 unchanged) so credentials are not stored in the
local git config while still allowing tag listing and gh-based release creation.
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 | ||
| id: generate-token | ||
| with: | ||
| app-id: ${{ secrets.APP_ID }} | ||
| private-key: ${{ secrets.APP_PRIVATE_KEY }} |
There was a problem hiding this comment.
Scope the minted GitHub App installation token to least privilege
In .github/workflows/release-rs.yml (lines 28-32), the actions/create-github-app-token step doesn’t set any permission-* inputs, so the generated installation token inherits the GitHub App installation’s full permissions (workflow permissions: only constrains GITHUB_TOKEN). Add permission-* inputs to restrict the minted token to the minimal permissions this job requires.
🧰 Tools
🪛 zizmor (1.25.2)
[error] 28-28: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 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/release-rs.yml around lines 28 - 32, The
create-github-app-token step (uses: actions/create-github-app-token, id:
generate-token) currently mints an installation token with full installation
permissions; add explicit permission-* inputs to this step to scope the token to
least privilege required by the job (for example: permission-actions,
permission-packages, permission-workflows, permission-contents, etc.) and remove
any broad access: specify only the exact permission names and levels the
downstream steps need so the generated token is restricted.
Resolves a conflict in .github/workflows/moq-relay.yml where main pinned GitHub Actions to commit SHAs (#1455) while this branch rewrote the workflow to build via Nix for all four target triples. Took the Nix-based build steps from this branch and pinned the actions to the same SHAs main uses elsewhere (actions/checkout, upload-artifact, download-artifact, DeterminateSystems/nix-installer-action, DeterminateSystems/magic-nix-cache-action). Also pinned the same actions in the four other workflows this branch adds (moq-cli.yml, moq-clock.yml, moq-token-cli.yml, release-brew.yml), plus actions/create-github-app-token, to satisfy the same convention. https://claude.ai/code/session_015J5tVAQ7ESjBhnzdeXfhgX
Summary
uses:line in.github/workflows/to a full commit SHA, with the original ref kept in a trailing comment (# v6,# main,# stable,# release/v1). 24 distinct refs across 12 workflows.cooldown: { default-days: 7 }to.github/dependabot.ymlso update PRs are deferred 7 days after each upstream release.Why
Mutable refs (
@main,@v6, etc.) let a compromised maintainer account re-point the ref under us. Recent examples: tj-actions/changed-files (March 2025), reviewdog. Pinning to SHA freezes the action code; the trailing comment lets Dependabot continue tracking the original branch/version and update both atomically. The 7-day cooldown gives time for compromises to be publicly flagged before changes land.How it works going forward
Dependabot already runs weekly on
package-ecosystem: github-actions. With cooldown enabled it will:# vN/# maincomment together, so the readable surface stays maintainable.Notes
DeterminateSystems/*@main,dtolnay/rust-toolchain@stable,pypa/gh-action-pypi-publish@release/v1) keep their branch name in the comment so Dependabot continues following the branch rather than switching to tag tracking.dtolnay/rust-toolchainpinning freezes the action code only; the Rust toolchain it installs is still resolved at runtime.Test plan
check.yml).git diffto confirm everyuses:line now has a 40-char SHA + trailing comment.https://claude.ai/code/session_011gyB6JvURSAi69iqu3yafw
Generated by Claude Code