Repository navigation
254 lines (237 loc) · 9.95 KB
/
Copy pathrelease.yaml
File metadata and controls
254 lines (237 loc) · 9.95 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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# Release workflow
#
# Prerequisites (configure in Settings > Secrets and variables > Actions):
# - GPG_PRIVATE_KEY: base64-encoded GPG private key for signing release artifacts
# - GPG_FINGERPRINT: Fingerprint of the GPG key
# - GPG_PASSPHRASE: Passphrase for the GPG private key
#
# Key management notes:
# - Use a key with no expiration or set a calendar reminder before expiry
# - To rotate: generate a new keypair, update all three secrets, and verify
# with a test release (see the provenance-smoke-test job)
name: Release
on:
push:
tags:
- '*'
branches:
- 'main'
- 'master'
pull_request:
branches:
- 'main'
- 'master'
workflow_dispatch:
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: echo "flags=--snapshot --skip=sign" >> $GITHUB_ENV
-
name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
-
name: Import GPG key
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
gpgconf --launch gpg-agent
printf '%s' "${{ secrets.GPG_PRIVATE_KEY }}" | base64 --decode | gpg --batch --import
-
name: Set GPG environment for signing
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
echo "GPG_FINGERPRINT=${{ secrets.GPG_FINGERPRINT }}" >> "$GITHUB_ENV"
echo "GPG_PASSPHRASE=${{ secrets.GPG_PASSPHRASE }}" >> "$GITHUB_ENV"
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: '~> v1'
args: release --clean ${{ env.flags }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
name: Verify archives bundle plugin files (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: |
set -e
missing=0
# Archives wrap their content in a "diff/" directory: the layout
# every released install/update hook expects (issues #1071, #1076).
# Each platform is published under two names (see .goreleaser.yml):
# the historical "helm-diff-<os>-<arch>.tgz" and the versioned
# "diff-<version>-<os>-<arch>.tgz" installable by helm 4 directly
# from a local tarball.
for f in dist/*.tgz; do
echo "== $f =="
tar tzf "$f"
for member in "diff/plugin.yaml" "diff/install-binary.sh" "diff/install-binary.ps1"; do
if ! tar tzf "$f" | grep -q "^${member}$"; then
echo "ERROR: ${member} missing from ${f}"
missing=1
fi
done
# the binary has a .exe suffix on windows archives
if ! tar tzf "$f" | grep -qE "^diff/bin/diff(\\.exe)?$"; then
echo "ERROR: diff/bin/diff missing from ${f}"
missing=1
fi
done
legacy_count="$(find dist -maxdepth 1 -name 'helm-diff-*.tgz' | wc -l)"
versioned_count="$(find dist -maxdepth 1 -name 'diff-*.tgz' | wc -l)"
if [ "$legacy_count" -eq 0 ] || [ "$legacy_count" -ne "$versioned_count" ]; then
echo "ERROR: expected an equal, non-zero number of legacy (helm-diff-*) and versioned (diff-*) archives"
missing=1
fi
if [ "$missing" -ne 0 ]; then
echo "Smoke test failed: required plugin files missing from one or more archives"
exit 1
fi
echo "Smoke test passed: all archives bundle plugin.yaml, install scripts, and binary in a diff/ directory"
-
name: Set up Helm
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: azure/setup-helm@v5
with:
version: v3.18.6
-
name: End-to-end archive install test (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: |
set -e
# Reproduce issue #504: extract a release archive and install from it.
mkdir -p /tmp/archive-test
tar xzf dist/helm-diff-linux-amd64.tgz -C /tmp/archive-test
echo "Extracted archive layout:"
find /tmp/archive-test/diff -maxdepth 2 -type f | sort
out="$(helm plugin install /tmp/archive-test/diff 2>&1)"
echo "$out"
# The install hook must find the bundled binary already staged in
# HELM_PLUGIN_DIR and skip the network download.
echo "$out" | grep -q "skipping download" || {
echo "ERROR: install hook did not skip the download."
echo "Archive install must not hit the network (binary is already bundled)."
exit 1
}
helm diff version
echo "End-to-end archive install test passed: installed from archive without downloading"
-
name: Set up Helm 4
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: azure/setup-helm@v5
with:
version: v4.3.0
-
# Regression test for issue #1076: `helm plugin update` runs the
# *already installed* copy of install-binary.sh, so release tarballs
# must keep the layout every previously released hook expects
# ("$HELM_TMP/diff/bin/diff" after extraction). Simulate updating a
# pre-3.15.14 install (v3.15.13 hook) and a 3.15.14 install by
# running their exact install scripts, in update mode, against the
# archives just built.
name: Legacy update hook regression test (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: |
set -e
archive="$PWD/dist/helm-diff-linux-amd64.tgz"
for hook_version in v3.15.13 v3.15.14; do
echo "== simulating 'helm plugin update' with the $hook_version install hook =="
plugin_dir="$(mktemp -d)/diff"
mkdir -p "$plugin_dir/bin"
git show "${hook_version}:install-binary.sh" > "$plugin_dir/install-binary.sh"
HELM_BIN=helm HELM_PLUGIN_DIR="$plugin_dir" \
HELM_DIFF_BIN_TGZ="$archive" \
sh "$plugin_dir/install-binary.sh" -u
test -x "$plugin_dir/bin/diff"
"$plugin_dir/bin/diff" version
echo "$hook_version hook updated the plugin successfully"
done
echo "Legacy update hook regression test passed"
-
# Regression test for issue #1071: helm 4 must be able to install
# directly from a local tarball (which it verifies by default). When
# installing from a local file, helm 4 derives the directory it
# expects inside the archive from the tarball file name
# ("diff-<version>-<os>-<arch>.tgz" -> "diff/"), hence the versioned
# archive names.
name: Helm 4 offline tarball install test (snapshot only)
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
env:
HELM_DATA_HOME: /tmp/helm4-data
run: |
set -e
archive="$(find dist -maxdepth 1 -name 'diff-*-linux-amd64.tgz')"
export GNUPGHOME="$(mktemp -d)"
chmod 700 "$GNUPGHOME"
gpg --batch --pinentry-mode loopback --passphrase '' \
--quick-generate-key "helm-diff-test" rsa3072 sign 0
GPG_FINGERPRINT=$(gpg --batch --with-colons --list-secret-keys "helm-diff-test" \
| grep '^fpr:' | head -1 | cut -d: -f10)
export GPG_FINGERPRINT GPG_PASSPHRASE=""
./scripts/sign-provenance.sh "$archive" "$archive.prov"
gpg --export --armor "helm-diff-test" > /tmp/keyring.gpg
out="$(helm plugin install "$archive" --keyring /tmp/keyring.gpg 2>&1)"
echo "$out"
echo "$out" | grep -q "Plugin Hash Verified" || {
echo "ERROR: helm 4 did not verify the signed archive."
exit 1
}
helm diff version
echo "Helm 4 offline tarball install test passed: installed and verified from a local tarball"
-
name: Export and upload public key
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
gpg --export --armor "${{ secrets.GPG_FINGERPRINT }}" > pubkey.asc
gh release upload ${{ github.ref_name }} pubkey.asc
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
provenance-smoke-test:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
steps:
-
name: Checkout
uses: actions/checkout@v7
-
name: Test provenance signing with disposable key
run: |
export GNUPGHOME="$(mktemp -d)"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$GNUPGHOME" "$tmpdir"' EXIT
chmod 700 "$GNUPGHOME"
gpg --batch --pinentry-mode loopback --passphrase '' \
--quick-generate-key "helm-diff-test" ed25519 sign 0
GPG_FINGERPRINT=$(gpg --batch --with-colons --list-secret-keys "helm-diff-test" \
| grep '^fpr:' | head -1 | cut -d: -f10)
export GPG_FINGERPRINT
export GPG_PASSPHRASE=""
echo "dummy binary" > "$tmpdir/bin"
tar czf "$tmpdir/helm-diff-linux-amd64.tgz" -C "$tmpdir" bin
./scripts/sign-provenance.sh "$tmpdir/helm-diff-linux-amd64.tgz" "$tmpdir/helm-diff-linux-amd64.tgz.prov"
if [ ! -f "$tmpdir/helm-diff-linux-amd64.tgz.prov" ]; then
echo "ERROR: provenance file was not created"
exit 1
fi
echo "=== gpg --verify ==="
gpg --verify "$tmpdir/helm-diff-linux-amd64.tgz.prov"
echo ""
echo "=== Signed .prov content ==="
cat "$tmpdir/helm-diff-linux-amd64.tgz.prov"
echo ""
echo "=== Parsed provenance block ==="
gpg --batch --output - "$tmpdir/helm-diff-linux-amd64.tgz.prov" 2>/dev/null
echo ""
echo "Provenance smoke test passed"