-
Notifications
You must be signed in to change notification settings - Fork 0
151 lines (136 loc) · 6.09 KB
/
Copy pathimage.yml
File metadata and controls
151 lines (136 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
---
# Bouwt en publiceert het portaal-image, en verifieert dat de tag in
# deploy/kustomization.yaml overeenkomt met de projectversie.
#
# GEEN BOT-COMMITS NAAR MAIN (omgezet 2026-08-12).
#
# De vorige opzet was merge-is-deploy: de workflow bouwde op main en committe de
# nieuwe tag terug in kustomization.yaml. Dat werkte, maar het betekende dat een
# gecompromitteerde workflow-stap de gedeployde image-tag kon verleggen — en het
# maakte branch-bescherming op main onmogelijk zonder uitzondering voor de bot.
# Dat is sec-bevinding 3 van change `iso-portal`; een uitzondering mitigeert die,
# ze dicht hem niet.
#
# Nu staat de tag in git omdát een mens hem daar heeft gezet, in dezelfde PR als
# de wijziging. De workflow bouwt het image op de PR — dus vóór de merge bestaat
# het al, en Argo vindt het meteen — en controleert alleen of versie en tag
# kloppen. `contents: write` is hiermee verdwenen: deze workflow kan niets meer in
# de repo veranderen.
#
# Gevolg voor de release-flow: één nummer op twee plekken.
# 1. bump `version` in pyproject.toml
# 2. zet dezelfde waarde als `newTag` in deploy/kustomization.yaml
# Vergeet je één van de twee, dan faalt de check met een leesbare melding.
name: image
on:
pull_request:
paths-ignore:
- "docs/**"
- "openspec/**"
- "**.md"
push:
branches: [main]
paths-ignore:
- "docs/**"
- "openspec/**"
- "**.md"
workflow_dispatch:
permissions:
contents: read
packages: write
concurrency:
group: image-${{ github.ref }}
cancel-in-progress: false
jobs:
image:
runs-on: ubuntu-latest
# Fork-PR's mogen niet naar onze registry pushen. Zonder deze guard kan een
# externe PR een image onder ghcr.io/conductionnl publiceren.
if: >-
github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v4
with:
# Volledige historie: de bump-check hieronder vergelijkt met de vorige
# commit, en dat kan niet met de default depth van 1.
fetch-depth: 0
- name: Versie en tag uitlezen en vergelijken
id: meta
run: |
set -euo pipefail
versie="$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)"
tag="$(grep -m1 'newTag:' deploy/kustomization.yaml | cut -d'"' -f2)"
echo "versie=${versie}" >> "$GITHUB_OUTPUT"
echo "sha=sha-$(git rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT"
if [[ "$versie" != "$tag" ]]; then
echo "::error::pyproject version (${versie}) en deploy/kustomization.yaml newTag (${tag}) lopen uiteen." >&2
echo "Zet beide op dezelfde waarde in deze PR." >&2
exit 1
fi
echo "versie en tag kloppen: ${versie}"
# De check hierboven vangt alleen dat versie en tag ÚITEENLOPEN, niet dat de
# versie is blijven staan terwijl de inhoud van het image wijzigde. Dan
# herbouwt deze workflow dezelfde tag met andere inhoud: een mutable tag die
# onder je handen beweegt. Argo ziet geen manifest-wijziging, de node heeft de
# tag al gecacht, en de pod draait stil oude code. Precies dat gebeurde op
# 2026-08-14.
- name: Versie moet mee bewegen met de image-inhoud
run: |
set -euo pipefail
# Paden die daadwerkelijk in het image landen.
paden=(src Dockerfile uv.lock pyproject.toml examples)
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
basis="${{ github.event.pull_request.base.sha }}"
else
basis="${{ github.event.before }}"
fi
if [[ -z "$basis" || "$basis" =~ ^0+$ ]] || ! git cat-file -e "$basis^{commit}" 2>/dev/null; then
echo "geen bruikbare vergelijkingsbasis (${basis:-leeg}) — check overgeslagen"
exit 0
fi
gewijzigd="$(git diff --name-only "$basis" HEAD -- "${paden[@]}")"
if [[ -z "$gewijzigd" ]]; then
echo "image-inhoud ongewijzigd sinds ${basis:0:12} — versie hoeft niet te bewegen"
exit 0
fi
oude_versie="$(git show "${basis}:pyproject.toml" 2>/dev/null | grep -m1 '^version = ' | cut -d'"' -f2 || true)"
nieuwe_versie="${{ steps.meta.outputs.versie }}"
if [[ "$oude_versie" == "$nieuwe_versie" ]]; then
echo "::error::Image-inhoud wijzigde maar de versie bleef ${nieuwe_versie}." >&2
echo "Dat zou tag ${nieuwe_versie} herbouwen met andere inhoud — een mutable tag." >&2
echo "Bump 'version' in pyproject.toml EN 'newTag' in deploy/kustomization.yaml." >&2
echo "Gewijzigd:" >&2
echo "$gewijzigd" | sed 's/^/ /' >&2
exit 1
fi
echo "versie bewoog ${oude_versie:-onbekend} -> ${nieuwe_versie} bij gewijzigde image-inhoud"
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Twee tags: de versie is wat Argo pullt, `sha-<short>` is het immutabele
# spoor per commit. De versietag kan tijdens PR-iteratie bewegen; de sha-tag
# nooit, dus die blijft het bewijs van wat er precies gebouwd is.
- name: Build + push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
ghcr.io/conductionnl/iso-audit:${{ steps.meta.outputs.versie }}
ghcr.io/conductionnl/iso-audit:${{ steps.meta.outputs.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Verifieer dat de tag pullbaar is
run: |
set -euo pipefail
tag="ghcr.io/conductionnl/iso-audit:${{ steps.meta.outputs.versie }}"
if ! docker buildx imagetools inspect "$tag" >/dev/null 2>&1; then
echo "::error::${tag} is niet pullbaar. Staat de ghcr-package op public?" >&2
echo "Een 401 leest hier als 'nog private', niet als 'tag ontbreekt'." >&2
exit 1
fi
echo "pullbaar: ${tag}"