From 74bae34ebb8f9297108f9bc2597e697d42fca14c Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 27 May 2026 11:30:35 -0700 Subject: [PATCH 1/2] ci: trigger publish-test-deps-image on PR Dockerfile changes Adds pull_request_target trigger so a Dockerfile change in a PR republishes :bookworm without waiting for merge to master. Uses the PR head SHA in checkout so the build sees the PR's Dockerfile. Concurrency now scoped per-PR/branch to keep parallel pushes from racing to overwrite the tag. --- .github/workflows/publish-test-deps-image.yml | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish-test-deps-image.yml b/.github/workflows/publish-test-deps-image.yml index 36f7c3b4..5ba4debf 100644 --- a/.github/workflows/publish-test-deps-image.yml +++ b/.github/workflows/publish-test-deps-image.yml @@ -3,10 +3,15 @@ name: Publish test-deps image # Builds docker/wolfprovider-test-deps/Dockerfile and pushes it to # ghcr.io/wolfssl/wolfprovider-test-deps:bookworm. # -# Fires when the Dockerfile (or this workflow file) changes on master. -# The pushed package stays private -- consumer workflows running on -# wolfSSL/wolfProvider use the canonical GITHUB_TOKEN, which has read -# access to the org's private packages. +# Triggers: +# - push to master/main when the Dockerfile changes -> rebuilds :bookworm +# - pull_request_target when the Dockerfile changes -> rebuilds :bookworm +# from the PR head SHA, so PR jobs that consume the image (sanitizers, +# static-analysis, multi-compiler, OSP) actually see the updated deps. +# pull_request_target runs from BASE with canonical secrets, so the +# ghcr push has the right scope; checkout pins to the PR head SHA so +# the build sees the PR's Dockerfile. +# - workflow_dispatch for manual rebuilds on: push: @@ -14,10 +19,15 @@ on: paths: - 'docker/wolfprovider-test-deps/**' - '.github/workflows/publish-test-deps-image.yml' + pull_request_target: + paths: + - 'docker/wolfprovider-test-deps/**' + - '.github/workflows/publish-test-deps-image.yml' workflow_dispatch: {} concurrency: - group: publish-test-deps-image + # Serialize per-PR/branch so two pushes don't race to overwrite :bookworm. + group: publish-test-deps-image-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: false permissions: @@ -26,14 +36,16 @@ permissions: jobs: publish: - # Only the canonical repo's runner has a token authorized to push - # to ghcr.io/wolfssl/*. Forks won't have that scope, so skip. + # Canonical repo only - forks lack the ghcr push scope. if: github.repository == 'wolfSSL/wolfProvider' runs-on: ubuntu-22.04 timeout-minutes: 45 steps: - uses: actions/checkout@v4 with: + # For pull_request_target, default checkout pulls BASE. We need + # the PR head SHA so the build sees the PR's Dockerfile. + ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 1 - name: Set up Docker Buildx From 09f6616593307141915048e75b6de5c338948141 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 27 May 2026 11:44:11 -0700 Subject: [PATCH 2/2] ci: lock publish to OWNER/MEMBER, single global concurrency, fix image SHA tag Addresses Copilot review on #403: - Author gate: pull_request_target only runs for OWNER/MEMBER. The prior 'github.repository == wolfSSL/wolfProvider' check did not exclude fork PRs since github.repository on pull_request_target is the BASE repo. Without the author gate a fork PR could smuggle a Dockerfile RUN that exfiltrates the canonical GITHUB_TOKEN (it has packages:write here). - Concurrency: drop the per-PR group and use a single global group. Per-PR serialization still let two PRs race to overwrite the shared :bookworm tag. - SHA tag: on pull_request_target github.sha is the BASE commit, not what we actually built. Resolve from the checked-out HEAD so the bookworm- tag matches the image contents. --- .github/workflows/publish-test-deps-image.yml | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-test-deps-image.yml b/.github/workflows/publish-test-deps-image.yml index 5ba4debf..693e739d 100644 --- a/.github/workflows/publish-test-deps-image.yml +++ b/.github/workflows/publish-test-deps-image.yml @@ -26,8 +26,10 @@ on: workflow_dispatch: {} concurrency: - # Serialize per-PR/branch so two pushes don't race to overwrite :bookworm. - group: publish-test-deps-image-${{ github.event.pull_request.number || github.ref }} + # Global single group: only one build at a time, since every run + # publishes to the shared :bookworm tag. Per-PR groups would still let + # two PRs race to overwrite the tag. + group: publish-test-deps-image cancel-in-progress: false permissions: @@ -37,7 +39,17 @@ permissions: jobs: publish: # Canonical repo only - forks lack the ghcr push scope. - if: github.repository == 'wolfSSL/wolfProvider' + # For pull_request_target, also require the author to be an OWNER or + # MEMBER of the org. Without this gate, any fork PR that edits the + # Dockerfile could smuggle arbitrary RUN steps that exfiltrate the + # canonical GITHUB_TOKEN (it has packages:write here). + if: | + github.repository == 'wolfSSL/wolfProvider' && + ( + github.event_name != 'pull_request_target' || + contains(fromJSON('["OWNER", "MEMBER"]'), + github.event.pull_request.author_association) + ) runs-on: ubuntu-22.04 timeout-minutes: 45 steps: @@ -48,6 +60,14 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 1 + - name: Resolve image SHA + id: sha + run: | + # On pull_request_target, github.sha is the BASE commit, not + # what we built. Use the checked-out HEAD so the SHA-suffixed + # tag matches the image's actual contents. + echo "image_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -66,6 +86,6 @@ jobs: push: true tags: | ghcr.io/wolfssl/wolfprovider-test-deps:bookworm - ghcr.io/wolfssl/wolfprovider-test-deps:bookworm-${{ github.sha }} + ghcr.io/wolfssl/wolfprovider-test-deps:bookworm-${{ steps.sha.outputs.image_sha }} cache-from: type=registry,ref=ghcr.io/wolfssl/wolfprovider-test-deps:bookworm cache-to: type=inline