From 7637aa45a69c84541d61b61feebee6d48a94793d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 16:52:32 +0000 Subject: [PATCH 1/7] build(deps): bump actions/checkout from 6 to 7 Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yaml | 8 ++++---- .github/workflows/e2e.yaml | 2 +- .github/workflows/publish.yaml | 2 +- .github/workflows/release.yaml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 421e22d..ebabc56 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-go@v6 with: @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: reviewdog/action-actionlint@v1 @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-go@v6 with: @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-go@v6 with: diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index d402abc..9280ba7 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -64,7 +64,7 @@ jobs: steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-go@v6 with: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index f31abac..b4fbd8a 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 fetch-tags: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 16b91a5..97a46f2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 fetch-tags: true From a4a63d42cd1a6b7157ef076b89aeb6ce4d8967aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 16:52:28 +0000 Subject: [PATCH 2/7] build(deps): bump golangci/golangci-lint-action from 9.2.1 to 9.3.0 Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 9.2.1 to 9.3.0. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/v9.2.1...v9.3.0) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-version: 9.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ebabc56..92c06e7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,7 +45,7 @@ jobs: go-version: 'stable' check-latest: true - - uses: golangci/golangci-lint-action@v9.2.1 + - uses: golangci/golangci-lint-action@v9.3.0 with: version: latest args: --verbose From 58b21bcdd4733265cd55669c982dad5c19fb1aeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 16:52:25 +0000 Subject: [PATCH 3/7] build(deps): bump ko-build/setup-ko from 0.9 to 0.10 Bumps [ko-build/setup-ko](https://github.com/ko-build/setup-ko) from 0.9 to 0.10. - [Release notes](https://github.com/ko-build/setup-ko/releases) - [Commits](https://github.com/ko-build/setup-ko/compare/v0.9...v0.10) --- updated-dependencies: - dependency-name: ko-build/setup-ko dependency-version: '0.10' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/publish.yaml | 2 +- .github/workflows/release.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index b4fbd8a..22f00af 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -30,7 +30,7 @@ jobs: uses: sigstore/cosign-installer@v4.1.2 - name: Prepare Ko - uses: ko-build/setup-ko@v0.9 + uses: ko-build/setup-ko@v0.10 - name: Compute build metadata env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 97a46f2..541b6de 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,7 +30,7 @@ jobs: uses: sigstore/cosign-installer@v4.1.2 - name: Prepare Ko - uses: ko-build/setup-ko@v0.9 + uses: ko-build/setup-ko@v0.10 - name: Compute build metadata env: From e3a51b7dd905a10a347b9f0228a5c0acb0817e82 Mon Sep 17 00:00:00 2001 From: Reto Gantenbein Date: Fri, 3 Jul 2026 11:44:10 +0200 Subject: [PATCH 4/7] github-workflows: Use hash instead of tag for GH action release --- .github/workflows/ci.yaml | 28 ++++++++++++++++++---------- .github/workflows/e2e.yaml | 6 ++++-- .github/workflows/publish.yaml | 9 +++++---- .github/workflows/release.yaml | 9 +++++---- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 92c06e7..6ee2940 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,35 +17,41 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version: 'stable' check-latest: true - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 actionlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false - - uses: reviewdog/action-actionlint@v1 + - uses: reviewdog/action-actionlint@6fb7acc99f4a1008869fa8a0f09cfca740837d9d # v1 golangci-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version: 'stable' check-latest: true - - uses: golangci/golangci-lint-action@v9.3.0 + - uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 with: version: latest args: --verbose @@ -54,9 +60,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version: 'stable' check-latest: true diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 9280ba7..0c6b918 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -64,9 +64,11 @@ jobs: steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version: 'stable' check-latest: true diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 22f00af..f7996bf 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -15,22 +15,23 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Setup Go - uses: actions/setup-go@v6 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version: 'stable' check-latest: true - name: Install Cosign - uses: sigstore/cosign-installer@v4.1.2 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: Prepare Ko - uses: ko-build/setup-ko@v0.10 + uses: ko-build/setup-ko@61b4d1d396f5b2e7d6bb6fefdce3dc38d1a13445 # v0.10 - name: Compute build metadata env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 541b6de..f5ce371 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,22 +15,23 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Setup Go - uses: actions/setup-go@v6 + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version: 'stable' check-latest: true - name: Install Cosign - uses: sigstore/cosign-installer@v4.1.2 + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - name: Prepare Ko - uses: ko-build/setup-ko@v0.10 + uses: ko-build/setup-ko@61b4d1d396f5b2e7d6bb6fefdce3dc38d1a13445 # v0.10 - name: Compute build metadata env: From 01c745aa068af6aba7cbfaadfe23e9e558ada551 Mon Sep 17 00:00:00 2001 From: Reto Gantenbein Date: Fri, 3 Jul 2026 11:46:46 +0200 Subject: [PATCH 5/7] github-workflows: Avoid script injection via env vars in e2e status step Pass github.repository and PR head SHA through env vars instead of direct template interpolation into the shell command. --- .github/workflows/e2e.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 0c6b918..2e6f81c 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -18,12 +18,14 @@ jobs: steps: - name: Set pending e2e status run: | - gh api "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ + gh api "repos/${REPO}/statuses/${HEAD_SHA}" \ -f state="pending" \ -f context="e2e" \ -f description="E2E tests must be triggered manually via workflow_dispatch" env: GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} e2e: if: github.event_name == 'workflow_dispatch' From 9171596f5260dedf6600b276780d6a15eea0aba6 Mon Sep 17 00:00:00 2001 From: Reto Gantenbein Date: Fri, 3 Jul 2026 11:52:27 +0200 Subject: [PATCH 6/7] github-workflows: Restrict GITHUB_TOKEN to least-privilege permissions Deny all permissions at the workflow level and grant each job only what it needs: - ci: contents:read per job; checks:write for the actionlint job so the reviewdog github-pr-check reporter can create check runs (the previous pull-requests:read grant didn't serve it) - e2e: statuses:write only for the status-reporting jobs; the job running checked-out test code keeps just contents:read (pull_request_target) - publish/release: deny at workflow level, existing job grants unchanged --- .github/workflows/ci.yaml | 13 ++++++++++--- .github/workflows/e2e.yaml | 10 +++++++--- .github/workflows/publish.yaml | 2 ++ .github/workflows/release.yaml | 2 ++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6ee2940..fd877af 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,14 +7,14 @@ on: pull_request: workflow_dispatch: -permissions: - contents: read - pull-requests: read # for golangci/golangci-lint-action to fetch pull requests +permissions: {} jobs: pre-commit: runs-on: ubuntu-latest + permissions: + contents: read # for actions/checkout to fetch code steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 @@ -30,6 +30,9 @@ jobs: actionlint: runs-on: ubuntu-latest + permissions: + contents: read # for actions/checkout to fetch code + checks: write # for reviewdog github-pr-check reporter to report findings steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 @@ -40,6 +43,8 @@ jobs: golangci-lint: runs-on: ubuntu-latest + permissions: + contents: read # for actions/checkout to fetch code steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 @@ -58,6 +63,8 @@ jobs: test: runs-on: ubuntu-latest + permissions: + contents: read # for actions/checkout to fetch code steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 2e6f81c..3066e3a 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -5,9 +5,7 @@ on: workflow_dispatch: pull_request_target: -permissions: - contents: read - statuses: write +permissions: {} jobs: @@ -15,6 +13,8 @@ jobs: if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest name: Set pending e2e status + permissions: + statuses: write # for gh api to set the commit status steps: - name: Set pending e2e status run: | @@ -30,6 +30,8 @@ jobs: e2e: if: github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest + permissions: + contents: read # for actions/checkout to fetch code timeout-minutes: ${{ matrix.timeout || 5 }} strategy: @@ -86,6 +88,8 @@ jobs: needs: [e2e] runs-on: ubuntu-latest name: Report e2e status + permissions: + statuses: write # for gh api to set the commit status steps: - name: Report e2e status run: | diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index f7996bf..fabd5b1 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -5,6 +5,8 @@ on: push: branches: ['main'] +permissions: {} + jobs: publish: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f5ce371..d3532fb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -5,6 +5,8 @@ on: push: tags: ['v*'] +permissions: {} + jobs: release: runs-on: ubuntu-latest From 7d810e5e956e267e92b43855e0dd9f1af7cd3827 Mon Sep 17 00:00:00 2001 From: Reto Gantenbein Date: Fri, 3 Jul 2026 23:17:21 +0200 Subject: [PATCH 7/7] github-workflows: Document e2e trigger design and security constraints Explain why e2e only runs via manual dispatch gated by commit status, and why the pull_request_target status-setting job must never execute PR code, so future changes don't "fix" this into an unsafe auto-run. --- .github/workflows/e2e.yaml | 14 ++++++++++++++ docs/testing.md | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 3066e3a..b13b6ae 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -1,6 +1,20 @@ --- name: E2E Tests +# Trigger design (intentional — do not "fix" by running e2e on PR events): +# +# The e2e matrix is slow, so it must not run on every push to a PR. It runs +# once per PR, via manual workflow_dispatch by a maintainer, when the PR is +# ready to merge. +# +# To gate merging on that manual run, every PR event sets the "e2e" commit +# status to pending (set-pending job), and the dispatched run reports the +# result back (report-status job) so the merge check can pass. +# +# pull_request_target is only used because posting a commit status requires +# a write-capable GITHUB_TOKEN, also for fork PRs. Since that token is +# privileged, the set-pending job must never check out or execute PR code. + on: workflow_dispatch: pull_request_target: diff --git a/docs/testing.md b/docs/testing.md index 9b73865..e0cbc74 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -10,6 +10,25 @@ Tests use `httptest.NewServer` for real local HTTP servers — no mocks for the - `newTestProxyWithRetries(t, mirrors, retries)` — same, but also sets `retryBaseDelay = 0` so retry tests run instantly. - `newTestApp(pp)` — builds an Echo app with the same middleware stack as production (`RequestID` → error handler → `Recover` → `Cache` → `ForwardProxy`). +## E2E Tests in CI + +E2e tests (`.github/workflows/e2e.yaml`) run a full distro container matrix and are +expensive, so they don't run on every push. They run once per pull request, triggered +manually by a maintainer before merging: + +```bash +gh workflow run e2e.yaml --ref +``` + +or via the Actions UI ("E2E Tests" → "Run workflow"). + +Merge gating: each PR event sets a pending `e2e` commit status, and the dispatched run +reports the result back as the `e2e` status used as a merge check. + +Security constraint of the implementation: the status-setting job runs under +`pull_request_target` with a privileged token and therefore never checks out or +executes PR code. + ## External Tests Tests in `proxy_test.go` that hit httpbin.org are skipped by default. Enable with: