-
Notifications
You must be signed in to change notification settings - Fork 0
217 lines (196 loc) · 8.47 KB
/
release.yml
File metadata and controls
217 lines (196 loc) · 8.47 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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
name: "Build OCI Image"
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
env:
REPOS: "ghcr.io/babs/mcp-auth-proxy"
jobs:
build-image:
name: "Build OCI image"
runs-on: ${{ matrix.os }}
# Build job only reads source and pushes images — no release creation
# happens here, so contents:read is sufficient.
permissions:
contents: read
packages: write
id-token: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
os: ubuntu-latest
- platform: linux/arm64
os: ubuntu-24.04-arm
outputs:
RAW_IMG_TAGS: ${{ steps.define-targets.outputs.RAW_IMG_TAGS }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Define TARGETS
id: define-targets
run: |
PLATFORM=${{ matrix.platform }}
PLATFORM_PAIR=${PLATFORM//\//-}
echo "PLATFORM_PAIR=$PLATFORM_PAIR" | tee -a $GITHUB_OUTPUT >> $GITHUB_ENV
IMG_TAGS="latest"
if [ ${GITHUB_REF_TYPE:-} == 'tag' -a -n "$(echo $GITHUB_REF_NAME | grep -iE '^v[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.-]+)?$')" ]; then
TAG=${GITHUB_REF_NAME#v}
RELEASE=""
case "$TAG" in
*-*)
RELEASE="-${TAG#*-}"
;;
esac
SEMVER_CORE="${TAG%%-*}"
IMG_TAGS="${IMG_TAGS} $TAG ${SEMVER_CORE%.*}${RELEASE} ${SEMVER_CORE%%.*}${RELEASE}"
fi
echo RAW_IMG_TAGS="$IMG_TAGS" | tee -a $GITHUB_OUTPUT >> $GITHUB_ENV
echo "Targets:"
TARGETS=""
PLATFORM_TAGS=""
for REPO in $REPOS; do
for IMG_TAG in $IMG_TAGS; do
PLATFORM_TAGS="${PLATFORM_TAGS},${IMG_TAG}-$PLATFORM_PAIR"
TARGETS="${TARGETS},${REPO}:${IMG_TAG}-$PLATFORM_PAIR"
echo "- ${REPO}:${IMG_TAG}-$PLATFORM_PAIR"
done
done
echo PLATFORM_TAGS=${PLATFORM_TAGS#,} | tee -a $GITHUB_OUTPUT >> $GITHUB_ENV
echo TARGETS=${TARGETS#,} | tee -a $GITHUB_OUTPUT >>$GITHUB_ENV
MODULE=$(grep module go.mod | cut -d\ -f2)
BINBASE=${MODULE##*/}
VERSION=${VERSION:-$GITHUB_REF_NAME}
VERSION=${VERSION:-v0.0.0}
COMMIT_HASH="$(git rev-parse --short HEAD 2>/dev/null)"
COMMIT_HASH=${COMMIT_HASH:-00000000}
DIRTY=$(git diff --quiet 2>/dev/null || echo '-dirty')
BUILD_TIMESTAMP=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
echo "VERSION=${VERSION}" | tee -a $GITHUB_OUTPUT >>$GITHUB_ENV
echo "COMMIT_HASH=${COMMIT_HASH}${DIRTY}" | tee -a $GITHUB_OUTPUT >>$GITHUB_ENV
echo "BUILD_TIMESTAMP=${BUILD_TIMESTAMP}" | tee -a $GITHUB_OUTPUT >>$GITHUB_ENV
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Login to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: build-and-push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
build-args: |
BUILD_TIMESTAMP=${{ env.BUILD_TIMESTAMP }}
COMMIT_HASH=${{ env.COMMIT_HASH }}
PROJECT_URL=${{ github.event.repository.html_url }}
VERSION=${{ env.VERSION }}
BUILDER=github-actions/${{ runner.os }}-${{ runner.arch }}
# GHA cache scoped per-platform so amd64 and arm64 don't
# evict each other's layers in the shared cache backend.
cache-from: type=gha,scope=${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
push: true
tags: ${{ env.TARGETS }}
platforms: ${{ matrix.platform }}
# Enable supply-chain attestations: SLSA provenance + SBOM
# embedded in the OCI image index. Consumers can verify with
# `docker buildx imagetools inspect <image> --format '{{json
# .Provenance}}'` and `cosign download sbom`.
provenance: mode=max
sbom: true
- name: Install cosign
uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
- name: Sign published image (keyless, Fulcio+Rekor)
env:
# All tags in $TARGETS point at the same content digest from
# this build step, so one signature per digest covers every
# tag. Keyless: Fulcio mints a short-lived cert from the
# GitHub Actions OIDC token; Rekor records the signature in
# the public transparency log.
DIGEST: ${{ steps.build-and-push.outputs.digest }}
run: |
for REPO in $REPOS; do
cosign sign --yes "${REPO}@${DIGEST}"
done
- name: Summary
run: |
echo "✅ Docker image created:" | tee -a $GITHUB_STEP_SUMMARY
for TGT in ${TARGETS//,/\ }; do
echo " - $TGT" | tee -a $GITHUB_STEP_SUMMARY
done
merge-images:
name: "Merge platform images into one"
needs: build-image
runs-on: ubuntu-latest
# contents:write is required to create the GitHub Release below.
# packages:write lets docker manifest push into GHCR.
# id-token:write is required for cosign keyless signing of the
# merged multi-arch index (Fulcio needs the OIDC token).
permissions:
contents: write
packages: write
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Login to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Merge images
# docker buildx imagetools (vs the classic docker manifest CLI)
# is required because per-platform builds with provenance/sbom
# attestations push an OCI index (image + attestations) rather
# than a plain image. `docker manifest create` rejects indexes
# with "is a manifest list"; imagetools handles them and
# preserves the per-platform attestations in the merged index.
run: |
for IMG_TAG in ${{ needs.build-image.outputs.RAW_IMG_TAGS }}; do
for REPO in $REPOS; do
TGT=${REPO}:${IMG_TAG}
docker buildx imagetools create \
-t "$TGT" \
"$TGT-linux-amd64" \
"$TGT-linux-arm64"
echo "merged image $TGT" | tee -a $GITHUB_STEP_SUMMARY
done
done
- name: Install cosign
uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
- name: Sign merged multi-arch index
# build-image signs the per-platform digests; this step signs
# the multi-arch INDEX digest that consumers pull by tag. Without
# this, `cosign verify $REPO:$TAG` fails even though the children
# are signed, because cosign looks up signatures on the tag's
# manifest digest (the index) first.
run: |
for IMG_TAG in ${{ needs.build-image.outputs.RAW_IMG_TAGS }}; do
for REPO in $REPOS; do
TGT=${REPO}:${IMG_TAG}
# docker buildx imagetools reads the index digest straight
# from the registry; more robust than parsing `docker
# manifest push` stdout across CLI versions.
DIGEST=$(docker buildx imagetools inspect "$TGT" --format '{{.Manifest.Digest}}')
cosign sign --yes "${REPO}@${DIGEST}"
echo "signed index $TGT @ $DIGEST" | tee -a $GITHUB_STEP_SUMMARY
done
done
# Use the preinstalled gh CLI instead of a third-party release action.
# Only runs on tag pushes; skipped on workflow_dispatch against main.
- name: Create GitHub Release
if: github.ref_type == 'tag'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if ! gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
gh release create "${GITHUB_REF_NAME}" \
--title "${GITHUB_REF_NAME}" \
--generate-notes
else
echo "Release ${GITHUB_REF_NAME} already exists; skipping."
fi