Skip to content

Commit 744a9ae

Browse files
committed
ci(docker-publish): detect affected services and add SBOM + provenance
Adds a detect job that uses turbo ls --affected against github.event.before so only services impacted by a push get rebuilt across amd64 + arm64. Release and workflow_dispatch events still build all four services. Also enables SBOM generation and upgrades provenance to mode=max (SLSA v1).
1 parent a18cafb commit 744a9ae

1 file changed

Lines changed: 100 additions & 9 deletions

File tree

.github/workflows/docker-publish.yml

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,70 @@ env:
2121
IMAGE_PREFIX: ghcr.io/databuddy-analytics/databuddy
2222

2323
jobs:
24+
detect:
25+
name: Detect affected services
26+
runs-on: blacksmith-2vcpu-ubuntu-2404
27+
timeout-minutes: 5
28+
outputs:
29+
services: ${{ steps.detect.outputs.services }}
30+
steps:
31+
- uses: actions/checkout@v6
32+
with:
33+
fetch-depth: 0
34+
- uses: oven-sh/setup-bun@v2
35+
with:
36+
bun-version: "1.3.11"
37+
- uses: actions/cache@v5
38+
with:
39+
path: ~/.bun/install/cache
40+
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
41+
restore-keys: ${{ runner.os }}-bun-
42+
- run: bun install --frozen-lockfile
43+
- id: detect
44+
env:
45+
EVENT_NAME: ${{ github.event_name }}
46+
BEFORE_SHA: ${{ github.event.before }}
47+
run: |
48+
ALL='["api","basket","links","uptime"]'
49+
if [[ "$EVENT_NAME" != "push" ]]; then
50+
echo "services=$ALL" >> "$GITHUB_OUTPUT"
51+
exit 0
52+
fi
53+
if [[ -z "$BEFORE_SHA" || "$BEFORE_SHA" == "0000000000000000000000000000000000000000" ]]; then
54+
echo "services=$ALL" >> "$GITHUB_OUTPUT"
55+
exit 0
56+
fi
57+
export TURBO_SCM_BASE="$BEFORE_SHA"
58+
export TURBO_SCM_HEAD="HEAD"
59+
affected=()
60+
for svc in api basket links uptime; do
61+
count=$(bunx turbo ls --affected --filter="@databuddy/$svc" --output=json | jq -r '.packages.count')
62+
if [[ "$count" != "0" ]]; then
63+
affected+=("\"$svc\"")
64+
fi
65+
done
66+
if [[ ${#affected[@]} -eq 0 ]]; then
67+
echo "services=[]" >> "$GITHUB_OUTPUT"
68+
else
69+
IFS=,
70+
echo "services=[${affected[*]}]" >> "$GITHUB_OUTPUT"
71+
fi
72+
2473
build:
2574
name: Build ${{ matrix.service }} (${{ matrix.platform.arch }})
75+
needs: detect
76+
if: needs.detect.outputs.services != '[]'
2677
runs-on: ${{ matrix.platform.runner }}
78+
timeout-minutes: 30
2779
permissions:
2880
contents: read
2981
packages: write
82+
id-token: write
83+
security-events: write
3084
strategy:
3185
fail-fast: false
3286
matrix:
33-
service: [api, basket, links, uptime]
87+
service: ${{ fromJson(needs.detect.outputs.services) }}
3488
platform:
3589
- arch: amd64
3690
os: linux/amd64
@@ -49,7 +103,7 @@ jobs:
49103
description: "Databuddy Uptime service - availability monitoring"
50104

51105
steps:
52-
- uses: actions/checkout@v4
106+
- uses: actions/checkout@v6
53107

54108
- name: Mount Docker build cache
55109
uses: useblacksmith/stickydisk@v1
@@ -60,7 +114,7 @@ jobs:
60114
- name: Set up Docker Builder
61115
uses: useblacksmith/setup-docker-builder@v1
62116

63-
- uses: docker/login-action@v3
117+
- uses: docker/login-action@v4
64118
with:
65119
registry: ${{ env.REGISTRY }}
66120
username: ${{ github.actor }}
@@ -84,7 +138,7 @@ jobs:
84138

85139
- name: Extract metadata (labels)
86140
id: meta
87-
uses: docker/metadata-action@v5
141+
uses: docker/metadata-action@v6
88142
with:
89143
images: ${{ env.IMAGE_PREFIX }}-${{ matrix.service }}
90144
labels: |
@@ -93,13 +147,16 @@ jobs:
93147
org.opencontainers.image.vendor=Databuddy Analytics
94148
org.opencontainers.image.licenses=AGPL-3.0
95149
96-
- uses: useblacksmith/build-push-action@v2
150+
- name: Build and push
151+
id: build
152+
uses: useblacksmith/build-push-action@v2
97153
with:
98154
context: .
99155
file: ${{ matrix.service }}.Dockerfile
100156
push: true
101157
platforms: ${{ matrix.platform.os }}
102-
provenance: false
158+
provenance: mode=max
159+
sbom: true
103160
labels: ${{ steps.meta.outputs.labels }}
104161
tags: ${{ env.IMAGE_PREFIX }}-${{ matrix.service }}:${{ steps.version.outputs.tag }}-${{ matrix.platform.arch }}
105162
build-args: |
@@ -109,18 +166,43 @@ jobs:
109166
cache-from: type=gha,scope=${{ matrix.service }}-${{ matrix.platform.arch }}
110167
cache-to: type=gha,mode=max,scope=${{ matrix.service }}-${{ matrix.platform.arch }}
111168

169+
- name: Scan image for vulnerabilities
170+
uses: aquasecurity/trivy-action@0.35.0
171+
with:
172+
image-ref: ${{ env.IMAGE_PREFIX }}-${{ matrix.service }}:${{ steps.version.outputs.tag }}-${{ matrix.platform.arch }}
173+
format: sarif
174+
output: trivy-results.sarif
175+
severity: CRITICAL,HIGH
176+
ignore-unfixed: true
177+
178+
- name: Upload scan results to GitHub Security
179+
uses: github/codeql-action/upload-sarif@v4
180+
if: always()
181+
with:
182+
sarif_file: trivy-results.sarif
183+
184+
- name: Install cosign
185+
uses: sigstore/cosign-installer@v4
186+
187+
- name: Sign image
188+
run: cosign sign --yes ${{ env.IMAGE_PREFIX }}-${{ matrix.service }}:${{ steps.version.outputs.tag }}-${{ matrix.platform.arch }}
189+
112190
manifest:
113191
name: Publish ${{ matrix.service }} manifest
114-
needs: build
192+
needs: [detect, build]
193+
if: needs.detect.outputs.services != '[]'
115194
runs-on: blacksmith-2vcpu-ubuntu-2404
195+
timeout-minutes: 10
116196
permissions:
197+
contents: read
117198
packages: write
199+
id-token: write
118200
strategy:
119201
matrix:
120-
service: [api, basket, links, uptime]
202+
service: ${{ fromJson(needs.detect.outputs.services) }}
121203

122204
steps:
123-
- uses: docker/login-action@v3
205+
- uses: docker/login-action@v4
124206
with:
125207
registry: ${{ env.REGISTRY }}
126208
username: ${{ github.actor }}
@@ -166,3 +248,12 @@ jobs:
166248
TAG="${{ steps.version.outputs.tag }}"
167249
echo "Inspecting $IMAGE:$TAG"
168250
docker buildx imagetools inspect "$IMAGE:$TAG"
251+
252+
- name: Install cosign
253+
uses: sigstore/cosign-installer@v4
254+
255+
- name: Sign manifest
256+
run: |
257+
IMAGE="${{ env.IMAGE_PREFIX }}-${{ matrix.service }}"
258+
TAG="${{ steps.version.outputs.tag }}"
259+
cosign sign --yes "$IMAGE:$TAG"

0 commit comments

Comments
 (0)