From d2a4b907709a1fe8c9937a47c0ef19bcfb6683bb Mon Sep 17 00:00:00 2001 From: yamadashy Date: Sat, 7 Mar 2026 20:38:34 +0900 Subject: [PATCH 1/2] ci(workflow): Add zizmor security linter and rename actionlint job - Rename lint-action to lint-actionlint for consistency - Add lint-zizmor job using zizmorcore/zizmor-action (SHA-pinned) - Add timeout-minutes to both jobs - zizmor provides security-focused static analysis for GitHub Actions workflows, detecting issues like pull_request_target misuse, expression injection, and overly permissive permissions Co-Authored-By: Claude Opus 4.6 --- .github/workflows/ci.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a4cec1e2..d90139808 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -147,15 +147,27 @@ jobs: working-directory: browser run: npm run lint - lint-action: - name: Lint GitHub Actions + lint-actionlint: + name: Lint GitHub Actions (actionlint) runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: rhysd/actionlint@393031adb9afb225ee52ae2ccd7a5af5525e03e8 # v1.7.11 with: args: "-color" + lint-zizmor: + name: Lint GitHub Actions (zizmor) + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0 + with: + advanced-security: "false" + annotations: "true" + check-typos: name: Check typos runs-on: ubuntu-latest From ba16033f24d005005065e60142da244569f3897b Mon Sep 17 00:00:00 2001 From: yamadashy Date: Sat, 7 Mar 2026 20:56:55 +0900 Subject: [PATCH 2/2] ci(workflow): Harden GitHub Actions security across all workflows Fix all findings from actionlint and zizmor security linters: - Add persist-credentials: false to all checkout steps across 14 workflows - Fix template injection in repomix action by using env vars instead of ${{ inputs.* }} - Pin Homebrew actions to SHA (50b8c2ab) instead of @main tag - Add zizmor config to ignore artipacked for schema-update.yml (needs credentials for push) - Add zizmor linter job and config path to ci.yml Co-Authored-By: Claude Opus 4.6 --- .github/actions/repomix/action.yml | 36 ++++++++++++++-------- .github/workflows/autofix.yml | 2 ++ .github/workflows/benchmark.yml | 4 +++ .github/workflows/ci.yml | 35 +++++++++++++++++++++ .github/workflows/claude-code-review.yml | 1 + .github/workflows/claude-issue-similar.yml | 1 + .github/workflows/claude-issue-triage.yml | 1 + .github/workflows/claude.yml | 1 + .github/workflows/codeql.yml | 2 ++ .github/workflows/docker.yml | 2 ++ .github/workflows/homebrew.yml | 6 ++-- .github/workflows/npm-publish.yml | 2 ++ .github/workflows/pack-repository.yml | 2 ++ .github/workflows/test-action.yml | 2 ++ .github/zizmor.yml | 5 +++ 15 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 .github/zizmor.yml diff --git a/.github/actions/repomix/action.yml b/.github/actions/repomix/action.yml index f792b4463..c8021e628 100644 --- a/.github/actions/repomix/action.yml +++ b/.github/actions/repomix/action.yml @@ -56,46 +56,56 @@ runs: fi - name: Install Repomix shell: bash + env: + REPOMIX_VERSION: ${{ inputs.repomix-version }} run: | - npm install --global repomix@${{ inputs.repomix-version }} + npm install --global "repomix@${REPOMIX_VERSION}" - name: Run Repomix id: build shell: bash + env: + INPUT_DIRECTORIES: ${{ inputs.directories }} + INPUT_INCLUDE: ${{ inputs.include }} + INPUT_IGNORE: ${{ inputs.ignore }} + INPUT_COMPRESS: ${{ inputs.compress }} + INPUT_STYLE: ${{ inputs.style }} + INPUT_OUTPUT: ${{ inputs.output }} + INPUT_ADDITIONAL_ARGS: ${{ inputs.additional-args }} run: | set -e # Using an array for safer command execution # Safely split directories input into an array, handling spaces correctly - IFS=' ' read -r -a ARGS <<< "${{ inputs.directories }}" + IFS=' ' read -r -a ARGS <<< "${INPUT_DIRECTORIES}" - if [ -n "${{ inputs.include }}" ]; then - ARGS+=(--include "${{ inputs.include }}") + if [ -n "${INPUT_INCLUDE}" ]; then + ARGS+=(--include "${INPUT_INCLUDE}") fi - if [ -n "${{ inputs.ignore }}" ]; then - ARGS+=(--ignore "${{ inputs.ignore }}") + if [ -n "${INPUT_IGNORE}" ]; then + ARGS+=(--ignore "${INPUT_IGNORE}") fi - if [ "${{ inputs.compress }}" = "true" ]; then + if [ "${INPUT_COMPRESS}" = "true" ]; then ARGS+=(--compress) fi - if [ -n "${{ inputs.style }}" ]; then - ARGS+=(--style "${{ inputs.style }}") + if [ -n "${INPUT_STYLE}" ]; then + ARGS+=(--style "${INPUT_STYLE}") fi - ARGS+=(--output "${{ inputs.output }}") + ARGS+=(--output "${INPUT_OUTPUT}") # Only add additional args if not empty - if [ -n "${{ inputs.additional-args }}" ]; then + if [ -n "${INPUT_ADDITIONAL_ARGS}" ]; then # Use safer parsing for additional arguments - IFS=' ' read -r -a ADDITIONAL_ARGS <<< "${{ inputs.additional-args }}" + IFS=' ' read -r -a ADDITIONAL_ARGS <<< "${INPUT_ADDITIONAL_ARGS}" ARGS+=("${ADDITIONAL_ARGS[@]}") fi echo "Running: repomix ${ARGS[*]}" repomix "${ARGS[@]}" - echo "output_file=${{ inputs.output }}" >> "$GITHUB_OUTPUT" + echo "output_file=${INPUT_OUTPUT}" >> "$GITHUB_OUTPUT" outputs: output_file: diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 29cf6d6f5..61f6584f0 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -13,6 +13,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Node.js uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 09c99e6be..02cfae57a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -29,6 +29,8 @@ jobs: working-directory: scripts/memory steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -83,6 +85,8 @@ jobs: working-directory: scripts/memory steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d90139808..3229e9b23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -30,6 +32,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -42,6 +46,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -55,6 +61,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -68,6 +76,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -85,6 +95,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -109,6 +121,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -133,6 +147,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -153,6 +169,8 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: rhysd/actionlint@393031adb9afb225ee52ae2ccd7a5af5525e03e8 # v1.7.11 with: args: "-color" @@ -163,16 +181,21 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0 with: advanced-security: "false" annotations: "true" + config: .github/zizmor.yml check-typos: name: Check typos runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: crate-ci/typos@06d010dfe4c84fdab1a25ea02b57b3585018ba80 # v1.42.3 test: @@ -184,6 +207,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: @@ -203,6 +228,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Bun ${{ matrix.bun-version }} uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 with: @@ -217,6 +244,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -242,6 +271,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version-file: .tool-versions @@ -265,6 +296,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: @@ -292,6 +325,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Bun ${{ matrix.bun-version }} uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 with: diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 348549a62..d3c10081d 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -33,6 +33,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 + persist-credentials: false - name: Run Claude Code Review id: claude-review diff --git a/.github/workflows/claude-issue-similar.yml b/.github/workflows/claude-issue-similar.yml index c6784bde6..8bb96504b 100644 --- a/.github/workflows/claude-issue-similar.yml +++ b/.github/workflows/claude-issue-similar.yml @@ -21,6 +21,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 + persist-credentials: false - name: Find Similar Issues uses: anthropics/claude-code-action@edd85d61533cbba7b57ed0ca4af1750b1fdfd3c4 # v1.0.55 diff --git a/.github/workflows/claude-issue-triage.yml b/.github/workflows/claude-issue-triage.yml index 87ceb234c..3bbb86615 100644 --- a/.github/workflows/claude-issue-triage.yml +++ b/.github/workflows/claude-issue-triage.yml @@ -21,6 +21,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 + persist-credentials: false - name: Run Claude Issue Triage uses: anthropics/claude-code-action@edd85d61533cbba7b57ed0ca4af1750b1fdfd3c4 # v1.0.55 diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 27866d8dd..c840defe6 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -35,6 +35,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 + persist-credentials: false - name: Run Claude Code id: claude diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 353eeb66c..ec4e1b882 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,6 +27,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index bd3b98437..19f0720c5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -28,6 +28,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Docker metadata id: meta diff --git a/.github/workflows/homebrew.yml b/.github/workflows/homebrew.yml index d5e4f2771..ff25faae2 100644 --- a/.github/workflows/homebrew.yml +++ b/.github/workflows/homebrew.yml @@ -13,15 +13,15 @@ jobs: runs-on: macos-latest steps: - name: Set up Homebrew - uses: Homebrew/actions/setup-homebrew@main + uses: Homebrew/actions/setup-homebrew@50b8c2ab4a835c38897ed2c56c293b07167c0b59 # main with: test-bot: false - name: Configure Git user - uses: Homebrew/actions/git-user-config@main + uses: Homebrew/actions/git-user-config@50b8c2ab4a835c38897ed2c56c293b07167c0b59 # main - name: Bump packages - uses: Homebrew/actions/bump-packages@main + uses: Homebrew/actions/bump-packages@50b8c2ab4a835c38897ed2c56c293b07167c0b59 # main with: token: ${{ secrets.COMMITTER_TOKEN }} formulae: repomix diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 12a325f04..c2e639d0a 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Node.js uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 diff --git a/.github/workflows/pack-repository.yml b/.github/workflows/pack-repository.yml index 3c3ebced3..7f3416cbf 100644 --- a/.github/workflows/pack-repository.yml +++ b/.github/workflows/pack-repository.yml @@ -16,6 +16,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Pack repository with Repomix uses: ./.github/actions/repomix diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml index 2ed351c1f..296a08d33 100644 --- a/.github/workflows/test-action.yml +++ b/.github/workflows/test-action.yml @@ -25,6 +25,8 @@ jobs: test-case: "full" steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Run Repomix Action (Minimal) if: matrix['test-case'] == 'minimal' diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 000000000..e85f6a39d --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,5 @@ +rules: + artipacked: + ignore: + # git-auto-commit-action requires persist-credentials for pushing + - schema-update.yml