From a0b3c4d01de3ca46a45b8daa537a6e7a728680c3 Mon Sep 17 00:00:00 2001 From: Leonidas Vrachnis Date: Thu, 29 Oct 2026 13:41:09 +0200 Subject: [PATCH] chore(ci): harden workflow checkouts, timeouts and concurrency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zizmor reported 10 artipacked findings: no checkout set persist-credentials: false. Seven jobs had no timeout, so a hung job ran for six hours. The builds group keyed on the sha. A release on main's HEAD then shared a group with the push build, and one cancelled the other. PR runs now group on the PR number. Push and release builds group on event and ref and do not cancel a running build. dependency-scan adds the event to its key, because a schedule run and a push share a sha. Verify: zizmor . shows no medium findings, actionlint passes, and the kind e2e job still passes without persisted credentials. Co-Authored-By: Claude Opus 5.5 🔒 Scanned for secrets using gitleaks 8.30.1 --- .github/workflows/builds.yml | 11 +++++++++-- .github/workflows/chart.yml | 4 +++- .github/workflows/cli.yml | 4 +++- .github/workflows/control-plane.yml | 7 ++++++- .github/workflows/dependency-scan.yml | 5 ++++- .github/workflows/docker-build-dockerhub.yml | 5 +++++ .github/workflows/harness.yml | 6 ++++++ .github/workflows/kubernetes.yml | 4 +++- 8 files changed, 39 insertions(+), 7 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index a6998fe..18e3e7e 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -18,9 +18,13 @@ on: - main pull_request: +# A release on main's HEAD has the same sha as the push build, so a sha key let +# one cancel the other. Publish runs key on event and ref and never cancel a +# running build. A newer push replaces only a pending one, so `main` gets the +# newest commit. concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event.pull_request.number || format('{0}-{1}', github.event_name, github.ref) }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} permissions: contents: read @@ -34,6 +38,7 @@ jobs: # no-ops outside a release. check-version: runs-on: ubuntu-latest + timeout-minutes: 5 permissions: contents: read steps: @@ -43,6 +48,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: The git tag must equal the chart's appVersion env: diff --git a/.github/workflows/chart.yml b/.github/workflows/chart.yml index 1ac2358..c1e5aee 100644 --- a/.github/workflows/chart.yml +++ b/.github/workflows/chart.yml @@ -16,7 +16,7 @@ on: - ".github/workflows/chart.yml" concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true permissions: {} @@ -37,6 +37,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index b64f7bc..cb658ee 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -15,7 +15,7 @@ on: - ".github/workflows/cli.yml" concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true permissions: {} @@ -37,6 +37,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Keep equal to MIN_BUN_VERSION in cli/interface/runtime.ts (a test checks it). - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 diff --git a/.github/workflows/control-plane.yml b/.github/workflows/control-plane.yml index edb32d0..3839b03 100644 --- a/.github/workflows/control-plane.yml +++ b/.github/workflows/control-plane.yml @@ -13,7 +13,7 @@ on: - ".github/workflows/control-plane.yml" concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true permissions: {} @@ -25,6 +25,7 @@ defaults: jobs: lint: runs-on: ubuntu-latest + timeout-minutes: 10 permissions: contents: read steps: @@ -34,6 +35,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: @@ -81,6 +84,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: diff --git a/.github/workflows/dependency-scan.yml b/.github/workflows/dependency-scan.yml index bf1d583..3d99999 100644 --- a/.github/workflows/dependency-scan.yml +++ b/.github/workflows/dependency-scan.yml @@ -12,8 +12,9 @@ on: schedule: - cron: "17 6 * * 1" +# The event is in the key: a scheduled run and a push share main's HEAD sha. concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || format('{0}-{1}', github.event_name, github.sha) }} cancel-in-progress: true permissions: {} @@ -37,6 +38,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Same gate as the image scan in docker-build-dockerhub.yml: a fixable # Critical or High fails the job. Trivy runs from its digest-pinned diff --git a/.github/workflows/docker-build-dockerhub.yml b/.github/workflows/docker-build-dockerhub.yml index 92d1e23..40d68f9 100644 --- a/.github/workflows/docker-build-dockerhub.yml +++ b/.github/workflows/docker-build-dockerhub.yml @@ -51,6 +51,7 @@ jobs: docker-meta: if: github.actor != 'dependabot[bot]' runs-on: ubuntu-latest + timeout-minutes: 5 outputs: tags: ${{ steps.meta.outputs.tags }} arm64_tags: ${{ steps.arm64_meta.outputs.tags }} @@ -124,6 +125,7 @@ jobs: labels: ${{ needs.docker-meta.outputs.amd64_labels }} platform: linux/amd64 runs-on: ${{ matrix.build-config.os }} + timeout-minutes: 30 steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2 @@ -131,6 +133,8 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Login to DockerHub if: inputs.push @@ -192,6 +196,7 @@ jobs: create-manifest: if: inputs.push runs-on: ubuntu-latest + timeout-minutes: 10 needs: [docker-build, docker-meta] steps: - name: Harden the runner (Audit all outbound calls) diff --git a/.github/workflows/harness.yml b/.github/workflows/harness.yml index 912626f..ec92009 100644 --- a/.github/workflows/harness.yml +++ b/.github/workflows/harness.yml @@ -27,6 +27,7 @@ jobs: lint: name: Lint and format runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2 @@ -35,6 +36,8 @@ jobs: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 @@ -56,6 +59,7 @@ jobs: test: name: Tests runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2 @@ -64,6 +68,8 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 diff --git a/.github/workflows/kubernetes.yml b/.github/workflows/kubernetes.yml index 894d234..b866e1c 100644 --- a/.github/workflows/kubernetes.yml +++ b/.github/workflows/kubernetes.yml @@ -8,7 +8,7 @@ on: paths: ["deploy/**", "control-plane/**", "harness/**", "cli/**", ".github/workflows/kubernetes.yml", "package.json", "**/bun.lock"] concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true permissions: {} @@ -35,6 +35,8 @@ jobs: df -h / - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: