Merge pull request #2213 from Molecule-AI/chore/pin-actions-to-shas

chore(security): pin Actions to SHAs + enable Dependabot auto-bumps
This commit is contained in:
Hongming Wang 2026-04-28 22:49:25 +00:00 committed by GitHub
commit 1867111d95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 139 additions and 59 deletions

80
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,80 @@
# Dependabot — auto-bump pinned dependencies.
#
# Why this exists:
#
# All `uses:` references in .github/workflows/*.yml are pinned to commit
# SHAs (with `# v<N>` comments for human readability) instead of mutable
# tags like `@v4`. Tag pinning is a known supply-chain risk: a maintainer
# (or compromised maintainer account) can repoint `@v4` to malicious code
# and our pipelines silently pull it. SHA pinning closes that risk.
#
# But SHA pinning has a maintenance cost: each upstream legitimate fix
# requires manually finding + bumping the SHA. Dependabot for Actions
# closes that gap by opening PRs to bump pinned SHAs whenever upstream
# tags a new version. Reviewer evaluates the bump like any other
# dependency PR.
#
# Combined: SHA pinning gives us security, Dependabot keeps us current.
version: 2
updates:
# GitHub Actions — every workflow file under .github/workflows/.
# Weekly cadence is enough for a CI surface this size; the supply-
# chain attack window is "minutes between repoint and pull," and
# weekly auto-bumps don't help with zero-days regardless. The point
# is to pull in non-zero-day fixes without operator effort, not to
# be real-time.
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- dependencies
- github-actions
commit-message:
prefix: chore(deps)
include: scope
# Go module — workspace-server. Bumps go.mod deps via PR weekly.
- package-ecosystem: gomod
directory: "/workspace-server"
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- dependencies
- go
commit-message:
prefix: chore(deps)
include: scope
# npm — canvas (Next.js bundle). Largest dep tree in this repo;
# weekly cadence keeps the security surface fresh without flooding
# the queue. open-pull-requests-limit: 10 because npm churns more
# than the others.
- package-ecosystem: npm
directory: "/canvas"
schedule:
interval: weekly
open-pull-requests-limit: 10
labels:
- dependencies
- npm
commit-message:
prefix: chore(deps)
include: scope
# Python — workspace runtime requirements. Pip/requirements.txt-
# backed rather than pyproject.toml; Dependabot supports both.
- package-ecosystem: pip
directory: "/workspace"
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- dependencies
- python
commit-message:
prefix: chore(deps)
include: scope

View File

@ -65,7 +65,7 @@ jobs:
echo "short=${FULL:0:7}" >> "$GITHUB_OUTPUT"
echo "full=${FULL}" >> "$GITHUB_OUTPUT"
- uses: imjasonh/setup-crane@v0.4
- uses: imjasonh/setup-crane@31b88efe9de28ae0ffa220711af4b60be9435f6e # v0.4
- name: GHCR login
run: |

View File

@ -152,7 +152,7 @@ jobs:
- name: Checkout main
if: ${{ vars.AUTO_PROMOTE_ENABLED == 'true' || github.event.inputs.force == 'true' }}
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: main
fetch-depth: 0

View File

@ -63,7 +63,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout staging
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
ref: staging

View File

@ -38,7 +38,7 @@ jobs:
tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0 # need full tag history for `git describe` / sort

View File

@ -26,7 +26,7 @@ jobs:
name: Block forbidden paths
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 2 # need previous commit to diff against on push events

View File

@ -66,7 +66,7 @@ jobs:
E2E_RUN_ID: "canary-${{ github.run_id }}"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify admin token present
run: |
@ -98,7 +98,7 @@ jobs:
# next deploy window.
- name: Open issue on failure
if: failure()
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
env:
# Inject the workflow path explicitly — context.workflow is
# the *name*, not the file path the actions API needs.
@ -165,7 +165,7 @@ jobs:
- name: Auto-close canary issue on success
if: success()
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const title = '🔴 Canary failing: staging SaaS smoke';

View File

@ -40,7 +40,7 @@ jobs:
smoke_ran: ${{ steps.smoke.outputs.ran }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Compute sha
id: compute
@ -143,7 +143,7 @@ jobs:
if: ${{ needs.canary-smoke.result == 'success' && needs.canary-smoke.outputs.smoke_ran == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: imjasonh/setup-crane@v0.4
- uses: imjasonh/setup-crane@31b88efe9de28ae0ffa220711af4b60be9435f6e # v0.4
- name: GHCR login
run: |

View File

@ -36,7 +36,7 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify merge_group trigger on required-check workflows
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -32,7 +32,7 @@ jobs:
python: ${{ steps.check.outputs.python }}
scripts: ${{ steps.check.outputs.scripts }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- id: check
@ -72,8 +72,8 @@ jobs:
run:
working-directory: workspace-server
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: 'stable'
- run: go mod download
@ -187,8 +187,8 @@ jobs:
run:
working-directory: canvas
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '22'
- run: rm -f package-lock.json && npm install
@ -210,7 +210,7 @@ jobs:
if: needs.changes.outputs.scripts == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Run shellcheck on tests/e2e/*.sh and infra/scripts/*.sh
# shellcheck is pre-installed on ubuntu-latest runners (via apt).
# infra/scripts/ is included because setup.sh + nuke.sh gate the
@ -276,8 +276,8 @@ jobs:
run:
working-directory: workspace
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.11'
cache: pip

View File

@ -53,14 +53,14 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Checkout sibling plugin repo
# Same reasoning as publish-workspace-server-image.yml — the Go
# module's replace directive needs the plugin source so
# CodeQL's "go build" phase can resolve.
if: matrix.language == 'go'
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: Molecule-AI/molecule-ai-plugin-github-app-auth
path: molecule-ai-plugin-github-app-auth
@ -69,7 +69,7 @@ jobs:
# jq is pre-installed on ubuntu-latest — no setup step needed.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a # v3
with:
languages: ${{ matrix.language }}
# security-extended widens past the default to include the
@ -77,11 +77,11 @@ jobs:
queries: security-extended
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a # v3
- name: Perform CodeQL Analysis
id: analyze
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a # v3
with:
category: "/language:${{ matrix.language }}"
# upload: never — GHAS isn't enabled on this repo, so the
@ -121,7 +121,7 @@ jobs:
# 14-day retention — longer than default 3, short enough not
# to bloat quota.
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: codeql-sarif-${{ matrix.language }}
path: sarif-results/${{ matrix.language }}/

View File

@ -36,8 +36,8 @@ jobs:
outputs:
api: ${{ steps.decide.outputs.api }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3
id: filter
with:
filters: |
@ -78,8 +78,8 @@ jobs:
PG_CONTAINER: molecule-ci-postgres
REDIS_CONTAINER: molecule-ci-redis
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: 'stable'
cache: true

View File

@ -46,8 +46,8 @@ jobs:
outputs:
canvas: ${{ steps.decide.outputs.canvas }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3
id: filter
with:
filters: |
@ -90,7 +90,7 @@ jobs:
working-directory: canvas
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify admin token present
run: |
@ -100,7 +100,7 @@ jobs:
fi
- name: Set up Node
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
cache: 'npm'
@ -117,7 +117,7 @@ jobs:
- name: Upload Playwright report on failure
if: failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: playwright-report-staging
path: canvas/playwright-report-staging/
@ -125,7 +125,7 @@ jobs:
- name: Upload screenshots on failure
if: failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: playwright-screenshots
path: canvas/test-results/

View File

@ -92,7 +92,7 @@ jobs:
E2E_KEEP_ORG: ${{ github.event.inputs.keep_org && '1' || '0' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify admin token present
run: |

View File

@ -50,7 +50,7 @@ jobs:
E2E_INTENTIONAL_FAILURE: "1"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify admin token present
run: |
@ -89,7 +89,7 @@ jobs:
- name: Open issue if safety net is broken
if: failure()
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const title = "🚨 E2E teardown safety net broken";

View File

@ -34,7 +34,7 @@ jobs:
promote:
runs-on: ubuntu-latest
steps:
- uses: imjasonh/setup-crane@v0.4
- uses: imjasonh/setup-crane@31b88efe9de28ae0ffa220711af4b60be9435f6e # v0.4
- name: GHCR login
run: |

View File

@ -42,17 +42,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Compute tags
id: tags
@ -85,7 +85,7 @@ jobs:
echo "ws_url=${WS_URL}" >> "$GITHUB_OUTPUT"
- name: Build & push canvas image to GHCR
uses: docker/build-push-action@v6
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: ./canvas
file: ./canvas/Dockerfile

View File

@ -81,9 +81,9 @@ jobs:
version: ${{ steps.version.outputs.version }}
wheel_sha256: ${{ steps.wheel_hash.outputs.wheel_sha256 }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@v5
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
cache: pip

View File

@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Checkout sibling plugin repo
# workspace-server/Dockerfile expects
@ -42,21 +42,21 @@ jobs:
# The PAT needs Contents:Read on Molecule-AI/molecule-ai-plugin-
# github-app-auth. Falls back to the default token for the (rare)
# case where an operator made the plugin repo public.
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: Molecule-AI/molecule-ai-plugin-github-app-auth
path: molecule-ai-plugin-github-app-auth
token: ${{ secrets.PLUGIN_REPO_PAT || secrets.GITHUB_TOKEN }}
- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Compute tags
id: tags
@ -87,7 +87,7 @@ jobs:
# applyRuntimeModelEnv and caused every E2E to route hermes+openai
# through openrouter → 401). See issue filed with this PR.
- name: Build & push platform image to GHCR (staging-<sha> + staging-latest)
uses: docker/build-push-action@v6
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
file: ./workspace-server/Dockerfile
@ -104,7 +104,7 @@ jobs:
org.opencontainers.image.description=Molecule AI platform (Go API server) — pending canary verify
- name: Build & push tenant image to GHCR (staging-<sha> + staging-latest)
uses: docker/build-push-action@v6
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
file: ./workspace-server/Dockerfile.tenant

View File

@ -60,8 +60,8 @@ jobs:
name: PyPI-latest install + import smoke
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.11'
cache: pip

View File

@ -61,8 +61,8 @@ jobs:
name: PR-built wheel + import smoke
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.11'
cache: pip

View File

@ -40,7 +40,7 @@ jobs:
name: Scan diff for credential-shaped strings
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 2 # need previous commit to diff against on push events

View File

@ -78,7 +78,7 @@ jobs:
MAX_DELETE_PCT: ${{ github.event.inputs.max_delete_pct || '50' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify required secrets present
id: verify

View File

@ -27,8 +27,8 @@ jobs:
name: Ops scripts (unittest)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.11'
- name: Run unittest