Skip to content

Commit 6e12cf3

Browse files
committed
Add Build Pipeline
1 parent 5008649 commit 6e12cf3

File tree

4 files changed

+356
-0
lines changed

4 files changed

+356
-0
lines changed

.github/release/.gitkeep

Whitespace-only changes.

.github/workflows/build.yml

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
tags: [ "v*.*.*" ]
6+
branches: [ "main", "build-pipeline" ]
7+
pull_request:
8+
branches: [ "main" ]
9+
merge_group:
10+
schedule:
11+
- cron: '45 1 * * *'
12+
13+
# Declare default permissions as read-only.
14+
permissions: read-all
15+
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
18+
cancel-in-progress: true
19+
20+
env:
21+
BUILD_ID: build-${{ github.run_id }}
22+
REGISTRY: ghcr.io/${{ github.repository_owner }}/interpolar
23+
24+
jobs:
25+
build-image:
26+
runs-on: ubuntu-24.04
27+
permissions:
28+
packages: write
29+
strategy:
30+
matrix:
31+
image: [ r-env ]
32+
include:
33+
- image: r-env
34+
context: .
35+
file: Dockerfile_R
36+
steps:
37+
- name: Harden Runner
38+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
39+
with:
40+
egress-policy: audit
41+
42+
- name: Checkout
43+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
44+
45+
- name: Login to GHCR
46+
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
47+
with:
48+
registry: ghcr.io
49+
username: ${{ github.repository_owner }}
50+
password: ${{ secrets.GITHUB_TOKEN }}
51+
52+
- name: Collect Info
53+
id: info
54+
run: |
55+
date="$(git log -1 --date="iso-strict-local" --format="%cd")"
56+
echo "commit_date=${date}" >>"${GITHUB_OUTPUT}"
57+
58+
- name: Generate Container Image Metadata
59+
id: meta
60+
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
61+
with:
62+
images: ${{ env.REGISTRY }}/${{ matrix.image }}
63+
labels: |
64+
org.opencontainers.image.created=${{ steps.info.outputs.commit_date }}
65+
annotations: |
66+
org.opencontainers.image.created=${{ steps.info.outputs.commit_date }}
67+
68+
- name: Build and Push Container Image
69+
id: push
70+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
71+
with:
72+
context: ${{ matrix.context }}
73+
file: ${{ matrix.file }}
74+
platforms: linux/amd64
75+
push: true
76+
tags: ${{ env.REGISTRY }}/${{ matrix.image }}:${{ env.BUILD_ID }}
77+
labels: ${{ steps.meta.outputs.labels }}
78+
annotations: ${{ steps.meta.outputs.annotations }}
79+
80+
- name: Output Image Digest
81+
id: digest
82+
run: echo "${{ matrix.image }}-digest=${{ steps.push.outputs.digest }}" >>"${GITHUB_OUTPUT}"
83+
outputs:
84+
r-env-digest: ${{ steps.digest.outputs.r-env-digest }}
85+
86+
scan-image:
87+
needs: [ build-image ]
88+
runs-on: ubuntu-24.04
89+
strategy:
90+
matrix:
91+
image: [ r-env ]
92+
permissions:
93+
security-events: write
94+
steps:
95+
- name: Harden Runner
96+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
97+
with:
98+
egress-policy: audit
99+
100+
- name: Run Trivy Vulnerability Scanner
101+
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # 0.31.0
102+
with:
103+
image-ref: ${{ env.REGISTRY }}/${{ matrix.image }}:${{ env.BUILD_ID }}
104+
format: sarif
105+
output: trivy-results.sarif
106+
severity: 'CRITICAL,HIGH'
107+
timeout: '15m0s'
108+
109+
- name: Upload Trivy Scan Results to GitHub Security Tab
110+
uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
111+
with:
112+
sarif_file: trivy-results.sarif
113+
114+
- name: Generate SBOM
115+
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # 0.31.0
116+
with:
117+
image-ref: ${{ env.REGISTRY }}/${{ matrix.image }}:${{ env.BUILD_ID }}
118+
format: cyclonedx
119+
output: sbom-trivy.json
120+
scan-type: image
121+
122+
- name: Upload Trivy SBOM
123+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
124+
with:
125+
name: ${{ matrix.image }}-sbom-trivy
126+
path: sbom-trivy.json
127+
if-no-files-found: error
128+
retention-days: 7
129+
130+
tag-image:
131+
if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork
132+
# `test` must succeed before finally tagging (i.e., publishing) the image
133+
needs: [ build-image, scan-image ]
134+
runs-on: ubuntu-24.04
135+
permissions:
136+
packages: write
137+
strategy:
138+
matrix:
139+
image: [ r-env ]
140+
env:
141+
DIGEST: ${{ needs.build-image.outputs[format('{0}-digest', matrix.image )]}}
142+
143+
steps:
144+
- name: Harden Runner
145+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
146+
with:
147+
egress-policy: audit
148+
149+
- name: Install SLSA Verifier
150+
uses: slsa-framework/slsa-verifier/actions/installer@ea584f4502babc6f60d9bc799dbbb13c1caa9ee6 # v2.7.1
151+
152+
- name: Install crane
153+
uses: iarekylew00t/crane-installer@af22986e01a08365e8b29e45e5a336c7995c111b # v4.0.0
154+
155+
- name: Login to GHCR
156+
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
157+
with:
158+
registry: ghcr.io
159+
username: ${{ github.repository_owner }}
160+
password: ${{ secrets.GITHUB_TOKEN }}
161+
162+
- name: Generate Container Image Metadata
163+
id: meta
164+
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
165+
with:
166+
images: ghcr.io/${{ github.repository_owner }}/interpolar/${{ matrix.image }}
167+
tags: |
168+
type=schedule
169+
type=ref,event=branch
170+
type=ref,event=pr
171+
type=semver,pattern={{version}}
172+
type=semver,pattern={{major}}.{{minor}}
173+
type=raw,value=latest,enable={{is_default_branch}}
174+
175+
- name: Retag and Push Container Image
176+
run: |
177+
while read -r tag; do
178+
echo "${tag}" | cut -d: -f2 | xargs crane tag "${REGISTRY}/${{ matrix.image }}@${DIGEST}"
179+
done <<<"${{ steps.meta.outputs.tags }}"
180+
181+
sign-image:
182+
needs: [ build-image, scan-image ]
183+
runs-on: ubuntu-24.04
184+
permissions:
185+
packages: write
186+
id-token: write
187+
strategy:
188+
matrix:
189+
image: [ r-env ]
190+
env:
191+
DIGEST: ${{ needs.build-image.outputs[format('{0}-digest', matrix.image )]}}
192+
steps:
193+
- name: Harden Runner
194+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
195+
with:
196+
egress-policy: audit
197+
198+
- name: Install cosign
199+
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
200+
201+
- name: Download SBOM
202+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
203+
with:
204+
name: ${{ matrix.image }}-sbom-trivy
205+
path: .
206+
207+
- name: Login to GHCR
208+
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
209+
with:
210+
registry: ghcr.io
211+
username: ${{ github.repository_owner }}
212+
password: ${{ secrets.GITHUB_TOKEN }}
213+
214+
- name: Sign Image
215+
env:
216+
IMAGE_REF: ${{ env.REGISTRY }}/${{ matrix.image }}@${{ env.DIGEST }}
217+
run: cosign sign --yes "${IMAGE_REF}"
218+
219+
- name: Attest Image SBOM
220+
env:
221+
IMAGE_REF: ${{ env.REGISTRY }}/${{ matrix.image }}@${{ env.DIGEST }}
222+
run: cosign attest --yes --predicate "sbom-trivy.json" --type cyclonedx "${IMAGE_REF}"
223+
224+
attest-image:
225+
needs: [ build-image ]
226+
permissions:
227+
actions: read # for detecting the Github Actions environment.
228+
id-token: write
229+
packages: write # for uploading attestations.
230+
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
231+
with:
232+
image: ghcr.io/${{ github.repository_owner }}/interpolar/${{ matrix.image }}
233+
digest: ${{ needs.build-image.outputs[format('{0}-digest', matrix.image)] }}
234+
registry-username: ${{ github.repository_owner }}
235+
secrets:
236+
registry-password: ${{ secrets.GITHUB_TOKEN }}
237+
strategy:
238+
matrix:
239+
image: [ r-env ]
240+
241+
create-release:
242+
runs-on: ubuntu-24.04
243+
steps:
244+
- name: Harden Runner
245+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
246+
with:
247+
egress-policy: audit
248+
249+
- name: Checkout
250+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
251+
252+
- name: Insert Version
253+
env:
254+
COMMIT_TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
255+
REF_NAME: ${{ github.event_name == 'pull_request' && format('pr-{}', github.event.number) || github.ref_name }}
256+
run: |
257+
raw_tag="${COMMIT_TAG#v}"
258+
image_tag="${raw_tag:-${REF_NAME}}"
259+
echo "INTERPOLAR_VERSION=${tag}" >VERSION.env
260+
sed -i -E 's|(ghcr\.io/${{ github.repository_owner }}/interpolar/[[:alnum:]_.-]+):latest|\1:'"${image_tag}"'|g' docker-compose.yml
261+
262+
- name: Create Release Archives
263+
id: create
264+
run: |
265+
zip -r ".github/release/interpolar-${GITHUB_REF_NAME}.zip" -x@.releaseignore .
266+
sha256sum "interpolar-${GITHUB_REF_NAME}.zip" >"interpolar-${GITHUB_REF_NAME}.zip.sha256"
267+
tar -czf ".github/release/interpolar-${GITHUB_REF_NAME}.tar.gz" --exclude-from=.releaseignore .
268+
sha256sum "interpolar-${GITHUB_REF_NAME}.tar.gz" >"interpolar-${GITHUB_REF_NAME}.tar.gz.sha256"
269+
270+
- name: Collect Checksums
271+
id: checksums
272+
working-directory: .github/release
273+
run: |
274+
# shellcheck disable=SC2016
275+
checksums="$(cat ./interpolar-*.sha256 | xargs -L1 bash -c 'echo -n "{\"$(echo $1 | cut -d. -f1)\": \"$(echo "$0 $1" | base64 -w0)\"}"' | jq -sc 'add')"
276+
echo "checksums-b64=${checksums}" >>"${GITHUB_OUTPUT}"
277+
files="$(find . -name "*.sha256" -printf "%f\n" | cut -d. -f1 | jq -R | jq -sc)"
278+
echo "files=${files}" >>"${GITHUB_OUTPUT}"
279+
280+
- name: Upload Release Archives
281+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
282+
with:
283+
name: release-archives
284+
path: |
285+
.github/release/*.zip
286+
.github/release/*.tar.gz
287+
.github/release/*.sha256
288+
if-no-files-found: error
289+
retention-days: 7
290+
291+
outputs:
292+
checksums-b64: ${{ steps.checksums.outputs.checksums-b64 }}
293+
files: ${{ steps.checksums.outputs.files }}
294+
295+
attest-release:
296+
needs: [ create-release ]
297+
permissions:
298+
actions: read
299+
contents: write
300+
id-token: write
301+
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
302+
strategy:
303+
matrix:
304+
file: ${{ fromJson(needs.create-release.outputs.files) }}
305+
with:
306+
base64-subjects: ${{ fromJson(needs.create-release.outputs.checksums-b64)[matrix.file] }}
307+
upload-assets: false
308+
309+
publish-release:
310+
needs: [ attest-release, tag-image ]
311+
runs-on: ubuntu-24.04
312+
if: github.ref_type == 'tag'
313+
permissions:
314+
contents: write
315+
steps:
316+
- name: Harden Runner
317+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
318+
with:
319+
egress-policy: audit
320+
321+
- name: Recognize Prerelease
322+
id: prerelease
323+
# In SemVer 2.0, a prerelease version is always indicated by the presence of a hyphen
324+
run: |
325+
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
326+
echo "is-prerelease=true" >>"${GITHUB_OUTPUT}"
327+
fi
328+
329+
- name: Download Release Archives
330+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
331+
with:
332+
name: release-archives
333+
path: .
334+
335+
- name: Download Provenance
336+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
337+
with:
338+
pattern: "interpolar-*.intoto.jsonl"
339+
merge-multiple: true
340+
path: .
341+
342+
- name: Release
343+
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
344+
with:
345+
files: |
346+
interpolar-*.zip
347+
interpolar-*.tar.gz
348+
interpolar-*.sha256
349+
draft: true
350+
prerelease: ${{ steps.prerelease.outputs.is-prerelease }}

.releaseignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.git*
2+
.git/
3+
.github/
4+
.releaseignore
5+
renovate.json

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ services:
127127
# Handle the "deploy" section with care and configure it according to your setup and needs.
128128
# The "deploy" section should only be commented out if necessary.
129129
r-env:
130+
image: ghcr.io/medizininformatik-initiative/interpolar/r-env:latest
130131
build:
131132
context: ./
132133
dockerfile: Dockerfile_R

0 commit comments

Comments
 (0)