-
Notifications
You must be signed in to change notification settings - Fork 202
376 lines (340 loc) · 15 KB
/
Copy pathnightly.yml
File metadata and controls
376 lines (340 loc) · 15 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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
name: Nightly Build
on:
schedule:
# Weekdays at 02:00 UTC
- cron: "0 2 * * 1-5"
workflow_dispatch:
inputs:
build_only:
description: "Build and package every artifact without publishing it."
required: false
default: false
type: boolean
artifact_retention_days:
description: "Retention for build artifacts."
required: false
default: 7
type: number
permissions:
contents: read
concurrency:
# The release, tag, and GHCR image tags are repository-wide resources. Keep
# manual runs from other refs serialized with the scheduled main run.
group: nightly-${{ github.repository }}
cancel-in-progress: true
env:
NIGHTLY_TAG: nightly
jobs:
# ── Check if there are new commits since last nightly ──────────────
check-changes:
name: Check for Changes
runs-on: ubuntu-latest
outputs:
should_build: ${{ steps.check.outputs.should_build }}
nightly_version: ${{ steps.check.outputs.nightly_version }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check for recent changes
id: check
shell: bash
run: |
set -euo pipefail
BASE_VERSION="$(jq -r '.version' package.json)"
DATE_SUFFIX="$(date -u '+%Y%m%d')"
SHORT_SHA="$(git rev-parse --short HEAD)"
NIGHTLY_VERSION="${BASE_VERSION}-nightly.${DATE_SUFFIX}+${SHORT_SHA}"
echo "nightly_version=$NIGHTLY_VERSION" >> "$GITHUB_OUTPUT"
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "should_build=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# Check if any commits landed in the last 25 hours
LAST_COMMIT_TIME="$(git log -1 --format='%ct')"
NOW="$(date -u '+%s')"
HOURS_AGO=$(( (NOW - LAST_COMMIT_TIME) / 3600 ))
if [[ "$HOURS_AGO" -lt 25 ]]; then
echo "should_build=true" >> "$GITHUB_OUTPUT"
else
echo "No new commits in the last 25 hours, skipping nightly build."
echo "should_build=false" >> "$GITHUB_OUTPUT"
fi
# ── Build every Nightly artifact through the reusable CI contract ──
build-artifacts:
name: Build Nightly Artifacts
needs: check-changes
if: needs.check-changes.outputs.should_build == 'true'
uses: ./.github/workflows/nightly-artifacts.yml
permissions:
contents: read
secrets:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
TAURI_UPDATER_PUBKEY: ${{ secrets.TAURI_UPDATER_PUBKEY }}
with:
checkout_ref: ${{ github.sha }}
version: ${{ needs.check-changes.outputs.nightly_version }}
artifact_prefix: nightly
artifact_retention_days: ${{ fromJSON(inputs.artifact_retention_days || '7') }}
build_desktop_packages: true
desktop_platforms: '["linux-x64","linux-arm64","macos-arm64","macos-x64","windows-x64"]'
build_linux_binaries: true
build_relay_image: true
upload_artifacts: true
# Fork validation is intentionally cache-read-only. Only the upstream
# repository may seed long-lived Nightly caches.
cache_write: ${{ github.repository_owner == 'GCWing' }}
# ── Publish nightly pre-release ────────────────────────────────────
publish-nightly:
name: Publish Nightly
needs: [check-changes, build-artifacts]
if: >-
needs.check-changes.outputs.should_build == 'true' &&
inputs.build_only != true
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v5
- name: Download bundled artifacts
uses: actions/download-artifact@v7
with:
pattern: bitfun-nightly-*-bundle
path: release-assets
merge-multiple: true
- name: Download Linux binary artifacts
uses: actions/download-artifact@v7
with:
pattern: bitfun-linux-nightly-*
path: linux-release-assets
merge-multiple: true
- name: Verify Relay image inputs
shell: bash
run: |
set -euo pipefail
test -f linux-release-assets/bitfun-relay-server-x86_64-unknown-linux-gnu.tar.gz
test -f linux-release-assets/bitfun-relay-server-aarch64-unknown-linux-gnu.tar.gz
for archive in linux-release-assets/bitfun-relay-server-*.tar.gz; do
(cd linux-release-assets && sha256sum --check "$(basename "${archive}").sha256")
done
cp src/apps/relay-server/Dockerfile.release linux-release-assets/Dockerfile.release
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Resolve nightly image metadata
id: nightly-image-meta
shell: bash
env:
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
run: |
echo "asset_version=${NIGHTLY_VERSION%%+*}" >>"$GITHUB_OUTPUT"
echo "image=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/bitfun-relay-server" >>"$GITHUB_OUTPUT"
- name: Build and push multi-platform Relay image
id: relay-image
uses: docker/build-push-action@v7
with:
context: linux-release-assets
file: linux-release-assets/Dockerfile.release
platforms: linux/amd64,linux/arm64
push: true
provenance: false
sbom: false
build-args: |
VERSION=${{ needs.check-changes.outputs.nightly_version }}
REVISION=${{ github.sha }}
tags: |
${{ steps.nightly-image-meta.outputs.image }}:${{ env.NIGHTLY_TAG }}
${{ steps.nightly-image-meta.outputs.image }}:${{ steps.nightly-image-meta.outputs.asset_version }}
- name: Smoke-test published Relay image on both platforms
shell: bash
env:
IMAGE_DIGEST: ${{ steps.relay-image.outputs.digest }}
run: |
bash scripts/relay/smoke-image.sh \
"${{ steps.nightly-image-meta.outputs.image }}@${IMAGE_DIGEST}"
- name: Generate signed Relay image descriptor
shell: bash
env:
IMAGE_DIGEST: ${{ steps.relay-image.outputs.digest }}
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
BITFUN_SIGNING_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
BITFUN_SIGNING_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
BITFUN_SIGNING_PUBKEY: ${{ secrets.TAURI_UPDATER_PUBKEY }}
run: |
set -euo pipefail
asset_version="${NIGHTLY_VERSION%%+*}"
[[ "${IMAGE_DIGEST}" =~ ^sha256:[0-9a-f]{64}$ ]]
docker buildx imagetools inspect \
"${{ steps.nightly-image-meta.outputs.image }}@${IMAGE_DIGEST}" \
--raw >relay-image-manifest.json
jq -e '
[.manifests[].platform | .os + "/" + .architecture] as $platforms
| ($platforms | index("linux/amd64")) != null
and ($platforms | index("linux/arm64")) != null
' relay-image-manifest.json >/dev/null
jq -n \
--arg image "${{ steps.nightly-image-meta.outputs.image }}" \
--arg tag "${NIGHTLY_TAG}" \
--arg version "${asset_version}" \
--arg digest "${IMAGE_DIGEST}" \
'{
schema_version: 1,
image: $image,
tag: $tag,
version: $version,
digest: $digest,
platforms: ["linux/amd64", "linux/arm64"]
}' >relay-image.json
bash scripts/sign-release-assets.sh relay-image.json
test -s relay-image.json.sig
- name: Verify anonymous Relay image access
shell: bash
env:
IMAGE_DIGEST: ${{ steps.relay-image.outputs.digest }}
run: |
set -euo pipefail
docker logout ghcr.io >/dev/null 2>&1 || true
clean_config="$(mktemp -d)"
trap 'rm -rf "$clean_config"' EXIT
DOCKER_CONFIG="$clean_config" docker buildx imagetools inspect \
"${{ steps.nightly-image-meta.outputs.image }}@${IMAGE_DIGEST}" >/dev/null
- name: List release assets
run: |
echo "Nightly assets:"
find release-assets -type f | sort
echo "Nightly Linux CLI and Relay Server assets:"
find linux-release-assets -type f | sort
- name: Delete previous nightly release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release delete "${{ env.NIGHTLY_TAG }}" --yes --cleanup-tag 2>/dev/null || true
- name: Generate Linux binaries manifest
env:
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
run: |
set -euo pipefail
# Asset names drop the `+<sha>` build metadata (see linux-binaries.yml).
node scripts/generate-linux-binaries-manifest.mjs \
--assets-dir linux-release-assets \
--version "${NIGHTLY_VERSION%%+*}" \
--tag "${{ env.NIGHTLY_TAG }}" \
--repo "${{ github.repository }}" \
--out linux-release-assets/linux-binaries.json
- name: Prepare versioned Windows installer
env:
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
run: |
node scripts/prepare-windows-installer-asset.mjs \
--assets-dir release-assets \
--version "${NIGHTLY_VERSION%%+*}" \
--out-dir release-manual-assets
# The Tauri bundler signs the five updater artifacts during `tauri build`,
# but the installers people download by hand from the release page — dmg,
# deb, rpm, the Windows installer and the direct AppImages — shipped with
# no signature at all. Sign them with the same key so every published
# artifact is verifiable. (This is not OS-level code signing: Gatekeeper
# and SmartScreen still need Apple/Authenticode certificates.)
- name: Sign installer packages
shell: bash
env:
BITFUN_SIGNING_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
BITFUN_SIGNING_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
BITFUN_SIGNING_PUBKEY: ${{ secrets.TAURI_UPDATER_PUBKEY }}
run: |
set -euo pipefail
mapfile -t assets < <({
find release-assets -type f \
\( -name '*.AppImage' -o -name '*.deb' -o -name '*.rpm' \
-o -name '*.dmg' \)
find release-manual-assets -type f -name '*.exe'
} | sort)
if [[ "${#assets[@]}" -eq 0 ]]; then
echo "No installer packages found to sign."
exit 0
fi
bash scripts/sign-release-assets.sh "${assets[@]}"
# Publish the public key alongside the signatures: a signature nobody
# can fetch a key for is not verifiable.
node scripts/write-minisign-public-key.mjs \
--out release-assets/minisign.pub
- name: Create nightly release
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ env.NIGHTLY_TAG }}
name: "Nightly Build (${{ needs.check-changes.outputs.nightly_version }})"
body: |
Automated nightly build from `main` branch.
**Version**: `${{ needs.check-changes.outputs.nightly_version }}`
**Commit**: ${{ github.sha }}
**Date**: ${{ github.event.head_commit.timestamp || github.event.repository.updated_at }}
> **Warning**: Nightly builds are untested and may be unstable.
prerelease: true
files: |
release-assets/**/*.AppImage
release-assets/**/*.deb
release-assets/**/*.dmg
release-assets/**/*.rpm
release-assets/**/*.sig
release-manual-assets/*.exe
release-manual-assets/*.exe.sig
release-assets/minisign.pub
release-assets/**/bitfun-cli-*-apple-darwin.tar.gz
release-assets/**/bitfun-cli-*-apple-darwin.tar.gz.sha256
linux-release-assets/bitfun-cli-*.tar.gz
linux-release-assets/bitfun-cli-*.tar.gz.sha256
linux-release-assets/bitfun-relay-server-*.tar.gz
linux-release-assets/bitfun-relay-server-*.tar.gz.sha256
linux-release-assets/*.tar.gz.sig
linux-release-assets/*.tar.gz.sha256.sig
linux-release-assets/linux-binaries.json
relay-image.json
relay-image.json.sig
- name: Verify published Linux CLI signatures
shell: bash
run: |
set -euo pipefail
while IFS= read -r cli_url; do
curl -fsSL --retry 5 --retry-delay 3 "${cli_url}.sig" -o /dev/null
curl -fsSL --retry 5 --retry-delay 3 "${cli_url}.sha256.sig" -o /dev/null
done < <(jq -r '.platforms[].cli.url' linux-release-assets/linux-binaries.json)
- name: Verify published Relay image descriptor
shell: bash
env:
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
run: |
set -euo pipefail
curl -fsSL --retry 5 --retry-delay 3 \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${NIGHTLY_TAG}/relay-image.json" \
-o relay-image.published.json
test "$(jq -r '.tag' relay-image.published.json)" = "${NIGHTLY_TAG}"
test "$(jq -r '.version' relay-image.published.json)" = "${NIGHTLY_VERSION%%+*}"
test "$(jq -r '.image' relay-image.published.json)" = "${{ steps.nightly-image-meta.outputs.image }}"
jq -e '.digest | test("^sha256:[0-9a-f]{64}$")' relay-image.published.json >/dev/null
curl -fsSL --retry 5 --retry-delay 3 \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${NIGHTLY_TAG}/relay-image.json.sig" \
-o /dev/null
- name: Verify published macOS CLI assets
shell: bash
env:
NIGHTLY_VERSION: ${{ needs.check-changes.outputs.nightly_version }}
run: |
set -euo pipefail
ASSET_VERSION="${NIGHTLY_VERSION%%+*}"
RELEASE_ROOT="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${{ env.NIGHTLY_TAG }}"
for target in aarch64-apple-darwin x86_64-apple-darwin; do
archive="${RELEASE_ROOT}/bitfun-cli-${ASSET_VERSION}-${target}.tar.gz"
curl -fsSL --retry 5 --retry-delay 3 "$archive" -o /dev/null
curl -fsSL --retry 5 --retry-delay 3 "${archive}.sha256" -o /dev/null
curl -fsSL --retry 5 --retry-delay 3 "${archive}.sig" -o /dev/null
curl -fsSL --retry 5 --retry-delay 3 "${archive}.sha256.sig" -o /dev/null
done