From ad3033f620d5f2ea830327bf887bbb27e79a0ca4 Mon Sep 17 00:00:00 2001 From: Gabriel Bianconi Date: Tue, 28 Apr 2026 16:46:59 -0400 Subject: [PATCH 1/5] Harden GHA --- .github/workflows/benchmark.yml | 18 +++++++++++------- .github/workflows/ci.yml | 15 ++++++++++++--- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 0c4ab71..61cda0a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -6,11 +6,10 @@ on: branches: - main -permissions: - # deployments permission to deploy GitHub pages website - deployments: write - # contents permission to update benchmark contents in gh-pages branch - contents: write +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +permissions: {} env: CARGO_TERM_COLOR: always @@ -20,6 +19,9 @@ jobs: benchmark: name: Performance regression check runs-on: ubuntu-latest + permissions: + deployments: write # deploy GitHub Pages website + contents: write # update benchmark results in gh-pages branch services: postgres: @@ -37,7 +39,9 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -46,7 +50,7 @@ jobs: run: cargo bench -- --output-format bencher | tee output.txt - name: Store benchmark result - uses: benchmark-action/github-action-benchmark@v1 + uses: benchmark-action/github-action-benchmark@a60cea5bc7b49e15c1f58f411161f99e0df48372 # v1.22.0 with: name: Criterion Benchmark tool: 'cargo' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b80da00..4c02566 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,22 +6,31 @@ on: merge_group: branches: [main] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} + env: CARGO_TERM_COLOR: always DATABASE_URL: postgres://postgres:postgres@localhost:5436/test jobs: ci: + name: CI runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Start Postgres run: docker compose up -d --wait - name: Install uv - uses: astral-sh/setup-uv@v4 + uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4.2.0 - name: Validate schema matches migrations run: ./scripts/validate-schema @@ -38,7 +47,7 @@ jobs: run: cargo clippy --all-targets --all-features -- -D warnings - name: Install nextest - uses: taiki-e/install-action@v2 + uses: taiki-e/install-action@1329c298aa20c3257846c9b2e0e55967df3e3c37 # v2.75.25 with: tool: cargo-nextest From 80d1a9cd922fe4da8e39ab3b4bedb2bf5eb70d67 Mon Sep 17 00:00:00 2001 From: Gabriel Bianconi Date: Tue, 28 Apr 2026 16:58:51 -0400 Subject: [PATCH 2/5] Harden GHA --- .github/workflows/benchmark.yml | 3 +- .github/workflows/ci.yml | 3 +- .github/workflows/security.yml | 65 +++++++++++++++++++++++++++++++++ .github/zizmor.yml | 30 +++++++++++++++ 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/security.yml create mode 100644 .github/zizmor.yml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 61cda0a..51581cb 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -9,7 +9,8 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} -permissions: {} +permissions: + contents: read # checkout env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c02566..a825f01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -permissions: {} +permissions: + contents: read # checkout env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..ba14316 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,65 @@ +name: security + +on: + pull_request: + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + pinact: + name: pinact + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: suzuki-shunsuke/pinact-action@cf51507d80d4d6522a07348e3d58790290eaf0b6 # v2.0.0 + with: + skip_push: "true" # validate only; fail CI on unpinned actions + + zizmor: + name: zizmor + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write # upload SARIF findings to Code Scanning + actions: read # required by zizmor-action for private/internal repos + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + with: + persona: pedantic + + security: + name: security + permissions: {} + if: always() + needs: + - pinact + - zizmor + runs-on: ubuntu-latest + steps: + - name: Print all job results + env: + NEEDS_JSON: ${{ toJson(needs) }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + run: | + echo "'needs': ${NEEDS_JSON}" + echo "github.event_name: ${GITHUB_EVENT_NAME}" + + # In the merge queue, any skipped job is a failure (everything must run). + # In PR CI, skips are allowed (e.g. fork PRs without OIDC). + - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || (github.event_name == 'merge_group' && contains(needs.*.result, 'skipped')) }} + run: exit 1 diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 0000000..5626e3a --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,30 @@ +rules: + dependabot-cooldown: + config: + days: 3 + + # pinact owns SHA-pinning enforcement; suppress here to avoid duplicate failures. + unpinned-uses: + ignore: + - ci.yml + - benchmark.yml + + # dtolnay/rust-toolchain is preferred over plain rustup for its caching and + # parallel component install behaviour — keeping it is an explicit choice. + superfluous-actions: + ignore: + - ci.yml + - benchmark.yml + + # dtolnay/rust-toolchain publishes only via `master`; no tags exist to pin to, + # so a SHA pointing at master is the best available reference. + stale-action-refs: + ignore: + - ci.yml + - benchmark.yml + + # The Postgres service container is for ephemeral test/bench use only; pinning + # to a SHA256 digest would add maintenance churn with no security benefit. + unpinned-images: + ignore: + - benchmark.yml From 3d65b2474c91221006a603f6c513c607cddd31ac Mon Sep 17 00:00:00 2001 From: Gabriel Bianconi Date: Tue, 28 Apr 2026 17:08:32 -0400 Subject: [PATCH 3/5] Harden GHA --- .github/workflows/benchmark.yml | 4 +++- .github/workflows/ci.yml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 51581cb..1ee481e 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -45,7 +45,9 @@ jobs: persist-credentials: false - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master + with: + toolchain: stable - name: Run benchmarks run: cargo bench -- --output-format bencher | tee output.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a825f01..4cab67e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,8 +37,9 @@ jobs: run: ./scripts/validate-schema - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master with: + toolchain: stable components: rustfmt, clippy - name: Check formatting From 03ad2f8ca2a37b703ca0bedaa51eb1cab673f671 Mon Sep 17 00:00:00 2001 From: Gabriel Bianconi Date: Tue, 28 Apr 2026 17:09:29 -0400 Subject: [PATCH 4/5] Harden GHA --- .github/workflows/benchmark.yml | 2 +- .github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 1ee481e..fa5dd5c 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -40,7 +40,7 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cab67e..8120b2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From 36b59fcfe6f9023d909fa8cfc14377ca943e0fe0 Mon Sep 17 00:00:00 2001 From: Gabriel Bianconi Date: Tue, 28 Apr 2026 17:20:37 -0400 Subject: [PATCH 5/5] Harden GHA --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8120b2f..3455d3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ env: jobs: ci: - name: CI + name: ci runs-on: ubuntu-latest steps: