From 40c75f5f7418f1fc336d7ba98008662ae7ff36c7 Mon Sep 17 00:00:00 2001 From: wu21-web Date: Tue, 18 Aug 2026 16:32:02 +0900 Subject: [PATCH 1/3] Partially Revert "fix(action): pin nested action references to full commit SHAs (#836)" This reverts commit 7e52a4fd55c75fd896b8eda4ffb3e07b30c4a782. --- .github/workflows/ci.yml | 3 --- scripts/verify-action-pins.sh | 46 ----------------------------------- 2 files changed, 49 deletions(-) delete mode 100755 scripts/verify-action-pins.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 159a3f977..49588c52b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,9 +37,6 @@ jobs: - name: Verify license headers run: bash scripts/verify-license.sh - - name: Verify action pins - run: bash scripts/verify-action-pins.sh - - name: Verify sources contain no unapproved non-English text run: go run scripts/verify-english-only.go diff --git a/scripts/verify-action-pins.sh b/scripts/verify-action-pins.sh deleted file mode 100755 index 2ffc61804..000000000 --- a/scripts/verify-action-pins.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -# SPDX-License-Identifier: Apache-2.0 -# Copyright 2026 alibaba/open-code-review Contributors - -# Verify that every external action referenced by the published composite -# action (action.yml) is pinned to a full 40-hex commit SHA with a trailing -# "# vX.Y.Z" version comment. A floating tag inside action.yml silently -# undermines consumers who SHA-pin alibaba/open-code-review itself: the -# outer pin freezes this repository, but a moved inner tag still changes -# what actually runs (see issue #816). -set -euo pipefail - -cd "$(dirname "$0")/.." - -files=("action.yml") -pinned='uses:[[:space:]]*[A-Za-z0-9_.-]+/[A-Za-z0-9_./-]+@[0-9a-f]{40}[[:space:]]+#[[:space:]]*v[0-9]' -local_ref='uses:[[:space:]]*\./' - -bad="" -for file in "${files[@]}"; do - if [ ! -f "$file" ]; then - echo "ERROR: $file not found; the pin check cannot run." >&2 - exit 1 - fi - hits="$(grep -nE 'uses:' "$file" || true)" - [ -n "$hits" ] || continue - while IFS= read -r line; do - if printf '%s' "$line" | grep -qE "$local_ref"; then - continue - fi - if ! printf '%s' "$line" | grep -qE "$pinned"; then - bad="${bad}${file}:${line}"$'\n' - fi - done <<< "$hits" -done - -if [ -n "$bad" ]; then - echo "The following action references are not pinned to a full commit SHA" - echo "with a '# vX.Y.Z' comment:" - printf '%s' "$bad" - echo "Pin them like: uses: owner/repo@<40-hex-sha> # vX.Y.Z" - exit 1 -fi - -echo "All external action references in ${files[*]} are SHA-pinned." From d79beb6bd6324a59425e590d63f7604023fd7d7c Mon Sep 17 00:00:00 2001 From: wu21-web Date: Tue, 18 Aug 2026 20:35:42 +0900 Subject: [PATCH 2/3] chore: pin action vers --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql.yml | 6 +++--- .github/workflows/deploy-pages.yml | 6 +++--- .github/workflows/ocr-review.yml | 2 +- .github/workflows/pages-ci.yml | 2 +- .github/workflows/release.yml | 16 ++++++++-------- .github/workflows/translation-sync.yml | 2 +- .github/workflows/vscode-ext.yml | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49588c52b..d4d6bb7fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: image: golang:1.26.6 options: --cpus=2 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' @@ -118,9 +118,9 @@ jobs: runs-on: windows-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-go@v7 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: '1.26.5' cache: true @@ -174,7 +174,7 @@ jobs: - {goos: windows, goarch: amd64} - {goos: windows, goarch: arm64} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b2dc6045b..09278b6fb 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -63,7 +63,7 @@ jobs: # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` @@ -73,7 +73,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -102,6 +102,6 @@ jobs: exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 4c3b3c152..865baf1ea 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -27,7 +27,7 @@ jobs: container: image: node:24 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' @@ -56,7 +56,7 @@ jobs: cmp install.sh _site/install.sh cmp install.ps1 _site/install.ps1 - - uses: actions/upload-pages-artifact@v5 + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: _site @@ -73,4 +73,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 diff --git a/.github/workflows/ocr-review.yml b/.github/workflows/ocr-review.yml index 4a6c55e28..dfaaaa3ef 100644 --- a/.github/workflows/ocr-review.yml +++ b/.github/workflows/ocr-review.yml @@ -45,7 +45,7 @@ jobs: # pull_request_target this checks out the trusted base branch; the # composite action performs its own full checkout (fetch-depth: 0) later. - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' diff --git a/.github/workflows/pages-ci.yml b/.github/workflows/pages-ci.yml index 6fadba23f..cbbe17912 100644 --- a/.github/workflows/pages-ci.yml +++ b/.github/workflows/pages-ci.yml @@ -20,7 +20,7 @@ jobs: container: image: node:24.18.0 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 29a0deff0..adba83c53 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: - goos: windows goarch: arm64 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' @@ -52,7 +52,7 @@ jobs: go build -ldflags "${LD_FLAGS}" -o "${BIN_NAME}" ./cmd/opencodereview echo "bin_name=${BIN_NAME}" >> $GITHUB_ENV - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: binary-${{ matrix.goos }}-${{ matrix.goarch }} path: ${{ env.bin_name }} @@ -71,7 +71,7 @@ jobs: - name: Install git run: apt-get update && apt-get install -y git - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 @@ -136,7 +136,7 @@ jobs: echo "RELEASE_NOTES_EOF" } >> "$GITHUB_OUTPUT" - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: binary-* merge-multiple: true @@ -145,7 +145,7 @@ jobs: run: sha256sum opencodereview-* | sort > sha256sum.txt - name: Create GitHub Release - uses: softprops/action-gh-release@v3 + uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: body: ${{ steps.notes.outputs.body }} files: | @@ -153,7 +153,7 @@ jobs: sha256sum.txt - name: Attest release artifacts - uses: actions/attest-build-provenance@v4 + uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 with: subject-path: | opencodereview-* @@ -168,7 +168,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' @@ -176,7 +176,7 @@ jobs: - name: Install jq run: apt-get update && apt-get install -y jq - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: pattern: binary-* merge-multiple: true diff --git a/.github/workflows/translation-sync.yml b/.github/workflows/translation-sync.yml index 3a9da5d16..63c6e29f1 100644 --- a/.github/workflows/translation-sync.yml +++ b/.github/workflows/translation-sync.yml @@ -26,7 +26,7 @@ jobs: image: node:24.18.0 steps: # fetch-depth: 0 so the non-blocking docs check can diff base...head. - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 with: fetch-depth: 0 diff --git a/.github/workflows/vscode-ext.yml b/.github/workflows/vscode-ext.yml index 4533a4f0d..af0ecf481 100644 --- a/.github/workflows/vscode-ext.yml +++ b/.github/workflows/vscode-ext.yml @@ -23,14 +23,14 @@ jobs: run: working-directory: extensions/vscode steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Trust workspace run: git config --global --replace-all safe.directory '*' working-directory: . - name: Cache Yarn packages - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.cache/yarn key: ${{ runner.os }}-yarn-${{ hashFiles('extensions/vscode/yarn.lock') }} From e4e571f86f590bd60111a57139dd517f677b09ab Mon Sep 17 00:00:00 2001 From: wu21-web Date: Tue, 18 Aug 2026 20:44:48 +0900 Subject: [PATCH 3/3] fixes --- AGENTS.md | 4 ++++ examples/github_actions/README.md | 2 +- internal/config/rules/rule_docs/github_workflows.md | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 359983c43..1b04ef566 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,6 +15,10 @@ open-code-review (`ocr`) is an AI-powered code review CLI tool written in Go (mo - Commit messages must be written in English. - Verify line endings. Line endings must be LF, not CRLF. Run `git add --renormalize .` to correct line endings and commit them. New binary files must have their extensions added to .gitattributes. +## CI Invariants + +- **GitHub Actions refs must be pinned to full commit SHAs.** Every external `uses:` in `.github/workflows/*.yml` and in `action.yml` must be a full 40-hex commit SHA (e.g. `uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1`), never a floating tag. The repository's "Require actions to be pinned to a full-length commit SHA" setting (Settings → Actions → General) enforces this at the runner level, including for nested references in composite actions. Keep it enabled: it is a repo setting, invisible in the tree and easy to flip off silently, so it is a required invariant rather than something CI proves. The trailing `# vX.Y.Z` comment is a convention for update tooling (Dependabot, Renovate) and is optional. + ## License Headers - Every source file (`.go`, `.sh`, `.js`, `.mjs`, `.ts`, `.tsx`) must have an SPDX license header. diff --git a/examples/github_actions/README.md b/examples/github_actions/README.md index 82660586f..fac5af1c0 100644 --- a/examples/github_actions/README.md +++ b/examples/github_actions/README.md @@ -38,7 +38,7 @@ The Action is an orchestrator: it installs the OCR CLI from npm at run time (`oc llm_use_anthropic: ${{ vars.OCR_LLM_USE_ANTHROPIC }} ``` -Take the commit SHA from the [releases page](https://github.com/alibaba/open-code-review/releases) and keep the `# vX.Y.Z` comment next to it so update tooling (Dependabot, Renovate) can track it. Every action referenced *inside* [`action.yml`](../../action.yml) is itself pinned to a full commit SHA (enforced by `scripts/verify-action-pins.sh` in CI), so the outer SHA transitively freezes the whole workflow — only the two coordinates above are yours to choose. +Take the commit SHA from the [releases page](https://github.com/alibaba/open-code-review/releases) and keep the `# vX.Y.Z` comment next to it so update tooling (Dependabot, Renovate) can track it. The nested `uses:` references *inside* [`action.yml`](../../action.yml) are pinned to full commit SHAs, and this repository requires the GitHub "Require actions to be pinned to a full-length commit SHA" setting to stay enabled (see [`AGENTS.md`](../../AGENTS.md)) — the runner rejects any unpinned reference, including nested ones. So the outer SHA transitively freezes the whole workflow — only the two coordinates above are yours to choose. ## Running on a self-hosted runner diff --git a/internal/config/rules/rule_docs/github_workflows.md b/internal/config/rules/rule_docs/github_workflows.md index 22104aca2..60dd25e0f 100644 --- a/internal/config/rules/rule_docs/github_workflows.md +++ b/internal/config/rules/rule_docs/github_workflows.md @@ -2,7 +2,7 @@ - **pull_request_target misuse**: Using `pull_request_target` with `actions/checkout` referencing PR head code is dangerous — it runs untrusted code with write permissions. Flag if checkout ref points to PR head without isolation - **Secrets exposure**: Secrets must not be printed to logs (e.g., `echo ${{ secrets.X }}`). Verify secrets are only passed via `env:` blocks to steps that need them - **Excessive permissions**: Check if `permissions` is set to least-privilege. Flag `permissions: write-all` or missing `permissions` key (defaults to broad access). Each job should declare only the permissions it needs -- **Unpinned action versions**: Third-party actions should be pinned to a full commit SHA (e.g., `uses: actions/checkout@`), not just a tag. Tags are mutable and can be hijacked. First-party (`actions/*`) pinned to `v4` is acceptable +- **Unpinned action versions**: Third-party actions should be pinned to a full commit SHA (e.g., `uses: actions/checkout@`), not just a tag. Tags are mutable and can be hijacked. First-party (`actions/*`) pinned to `v4` is acceptable. (The leniency above is for reviewing third-party repos; this repository applies full-SHA pinning to its own `.github/workflows/*.yml` and `action.yml`, enforced by the "Require actions to be pinned to a full-length commit SHA" setting.) - **Script injection**: Expressions like `${{ github.event.issue.title }}` used directly in `run:` blocks enable code injection. These must be passed through environment variables instead - **Hardcoded credentials**: Tokens, passwords, or API keys directly in the workflow file (not via secrets)