From be1f6aef07771f318a854e09d53e31726e38e4bc Mon Sep 17 00:00:00 2001 From: Xavier Costa Date: Mon, 9 Nov 2026 10:46:25 +0000 Subject: [PATCH 1/2] Harden GitHub Actions workflows Pins every action to a commit SHA, scopes GITHUB_TOKEN per job, moves the Pages publish permissions to the deploy job only, stops persisting checkout credentials, installs with --ignore-scripts, and adds zizmor plus Dependabot with a 7-day release cooldown. --- .github/dependabot.yml | 18 ++++++++++++++++++ .github/workflows/ci.yml | 33 +++++++++++++++++++++++++++------ .github/workflows/pages.yml | 23 ++++++++++++++--------- 3 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..851561f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +# Keeps SHA-pinned actions and npm deps current; the cooldown skips releases +# younger than 7 days, the window in which most hijacked versions get pulled. +version: 2 + +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + cooldown: + default-days: 7 + + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + cooldown: + default-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a657e5f..09bdc1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,9 @@ on: push: branches: [master] +permissions: + contents: read + jobs: ci: runs-on: ubuntu-latest @@ -26,15 +29,17 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Set up Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ matrix.node-version }} - name: Install dependencies - run: npm ci + run: npm ci --ignore-scripts - name: All self-tests run: npm test @@ -86,10 +91,26 @@ jobs: if (!ok) process.exit(1); " + # Exact pin; its postinstall must run to fetch the native binary. + - name: Install Claude Code CLI + run: npm install -g @anthropic-ai/claude-code@2.1.226 # zizmor: ignore[adhoc-packages] exact pin, no secrets in job + # Static manifest validation via the official Claude Code CLI. # No auth needed — `plugin validate` is offline. --strict treats # warnings (e.g. a missing marketplace description) as errors. - name: Official plugin validation (strict) - run: | - npm install -g @anthropic-ai/claude-code@2.1.226 - claude plugin validate . --strict + run: claude plugin validate . --strict + + # Static audit of the workflows themselves (pinning, injection, permissions). + zizmor: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: zizmorcore/zizmor-action@45d7276c9ca790aabd705e31ca99c6185c3e76dd # v0.8.1 + with: + version: 1.32.0 + advanced-security: false + annotations: true diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 7a266d7..f0343e7 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -24,10 +24,7 @@ on: branches: [master] workflow_dispatch: -permissions: - contents: read - pages: write - id-token: write +permissions: {} concurrency: group: pages @@ -41,17 +38,21 @@ env: jobs: build: runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Set up Node.js 20 - uses: actions/setup-node@v4 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: 20 - name: Install dependencies - run: npm ci + run: npm ci --ignore-scripts - name: Fetch excalidraw at pinned SHA run: | @@ -117,17 +118,21 @@ jobs: fi - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: _site deploy: needs: build runs-on: ubuntu-latest + # Publish credentials live only here: this job runs no project code. + permissions: + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 From 4df0e5e645bc5c14c17ef15375c549953f85cd1f Mon Sep 17 00:00:00 2001 From: Xavier Costa Date: Mon, 9 Nov 2026 10:47:26 +0000 Subject: [PATCH 2/2] fixup! Harden GitHub Actions workflows --- .github/dependabot.yml | 18 ------------------ .github/workflows/ci.yml | 22 +++------------------- 2 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 851561f..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Keeps SHA-pinned actions and npm deps current; the cooldown skips releases -# younger than 7 days, the window in which most hijacked versions get pulled. -version: 2 - -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: weekly - cooldown: - default-days: 7 - - - package-ecosystem: npm - directory: / - schedule: - interval: weekly - cooldown: - default-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09bdc1f..553ecfc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,26 +91,10 @@ jobs: if (!ok) process.exit(1); " - # Exact pin; its postinstall must run to fetch the native binary. - - name: Install Claude Code CLI - run: npm install -g @anthropic-ai/claude-code@2.1.226 # zizmor: ignore[adhoc-packages] exact pin, no secrets in job - # Static manifest validation via the official Claude Code CLI. # No auth needed — `plugin validate` is offline. --strict treats # warnings (e.g. a missing marketplace description) as errors. - name: Official plugin validation (strict) - run: claude plugin validate . --strict - - # Static audit of the workflows themselves (pinning, injection, permissions). - zizmor: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - uses: zizmorcore/zizmor-action@45d7276c9ca790aabd705e31ca99c6185c3e76dd # v0.8.1 - with: - version: 1.32.0 - advanced-security: false - annotations: true + run: | + npm install -g @anthropic-ai/claude-code@2.1.226 + claude plugin validate . --strict