From c1ce13758fd3232b4771f51d30f49cb1d48c33b6 Mon Sep 17 00:00:00 2001 From: Anso Date: Fri, 10 Apr 2026 13:41:49 -0400 Subject: [PATCH] ci: harden supply chain (SHA pin actions, least-privilege permissions) (#475) Pin three third-party actions to full commit SHAs with version comments so dependabot can update them in place without exposing the pipeline to upstream tag tampering: - aquasecurity/trivy-action@v0.35.0 - peter-evans/create-pull-request@v8.1.1 - googleapis/release-please-action@v4.4.0 Add a workflow-level permissions: contents: read default to ci.yml, with update-screenshots keeping its explicit contents: write + pull-requests: write override. Add the same default to docker-publish.yml (single job). Expand .dockerignore to explicitly exclude .env*, *.key, *.pem, .github/, docs/, website/, e2e/, tests/, test-results/, and playwright-report/ as defense in depth against accidental build-context leaks. None of these paths are read by any COPY step in Dockerfile. --- .dockerignore | 21 ++++++++++++++++++++- .github/workflows/ci.yml | 9 +++++++-- .github/workflows/docker-publish.yml | 2 ++ .github/workflows/release-please.yml | 2 +- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/.dockerignore b/.dockerignore index 750540e6..eb466d2a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,7 +2,26 @@ **/dist .git .gitignore +.DS_Store + +# Docs and non-runtime content. Not needed in the image, bloats build context. plans/ Product Requirements Document *.md -.DS_Store +docs/ +website/ + +# Tests and reports. Never shipped in the image. +e2e/ +tests/ +test-results/ +playwright-report/ + +# CI config runs on GitHub Actions, not inside the image. +.github/ + +# Secrets and key material. Defense in depth against accidental context leaks. +.env +.env.* +*.key +*.pem diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 140891bb..5eff45ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,11 @@ concurrency: group: ci-${{ github.ref }} cancel-in-progress: true +# Least-privilege default for every job. Individual jobs may override (e.g. +# update-screenshots needs contents: write + pull-requests: write to open a PR). +permissions: + contents: read + # --------------------------------------------------------------------------- # Build & Validation (PRs only, skipped for release-please PRs) # --------------------------------------------------------------------------- @@ -118,7 +123,7 @@ jobs: cache-to: type=gha,mode=max - name: Scan image for vulnerabilities (Trivy) - uses: aquasecurity/trivy-action@master + uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: image-ref: sencho:pr-test exit-code: '1' @@ -195,7 +200,7 @@ jobs: - name: Open / update screenshots PR id: create-pr - uses: peter-evans/create-pull-request@v8 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.DOCS_REPO_TOKEN }} branch: chore/refresh-screenshots diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 5821ee5f..917e6ac3 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -15,6 +15,8 @@ jobs: name: Push Docker image to Docker Hub runs-on: ubuntu-latest timeout-minutes: 30 + permissions: + contents: read steps: - name: Check out the repo uses: actions/checkout@v6 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 767e9372..7fb4f30f 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -13,7 +13,7 @@ jobs: release-please: runs-on: ubuntu-latest steps: - - uses: googleapis/release-please-action@v4 + - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0 with: # GITHUB_TOKEN cannot trigger other workflows (GitHub security restriction). # Using DOCS_REPO_TOKEN (PAT) ensures the tag push from release-please