Repository navigation
212 lines (201 loc) · 9.3 KB
/
Copy pathpublished.yml
File metadata and controls
212 lines (201 loc) · 9.3 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
name: published
# Everything in ci.yml asks whether the tree works. This asks whether what
# is on the registry works, which is a different question with a different
# failure mode: it can go red without anyone having committed anything, so
# putting it in ci.yml would turn a registry hiccup into a red mark on
# somebody's pull request and teach people to ignore red.
#
# Everything here installs an image kuma published rather than one it
# just built, which is what makes `kuma-home-subvol` verifiable: that
# converger only does anything on a btrfs root, only `kuma install`
# writes one, and until this existed nothing ever booted a disk it had
# written.
on:
# publish.yml calls this once its staging tag holds the digest, and
# pins the input by digest so the laps judge exact bytes. The real
# tags (the moving and the pinned one) move only when every lap here
# is green — the promote job. Until then the tags people pull still
# name the last image that booted, which is the promotion gate's
# whole point: a red lap is a red run and no published change.
#
# It reads "every job" rather than "three of four" because the fourth
# never belonged: `fix-verification` installed an image built from the
# tree, not from the registry, and lived here only because this is
# where the KVM-and-install steps were. That made the one job covering
# install-time and first-boot regressions run *after* a tag was public.
# It is `install` in ci.yml now, on the harness both share.
workflow_call:
inputs:
image:
description: "Image reference to install and boot, and to upgrade to"
required: false
type: string
default: "ghcr.io/letdown2491/kuma:niri"
from_image:
description: >-
Override the cross-version fixture. Empty derives the release
before this one from the registry.
required: false
type: string
default: ""
workflow_dispatch:
inputs:
image:
description: "Image reference to install and boot, and to upgrade to"
required: false
default: "ghcr.io/letdown2491/kuma:niri"
from_image:
description: >-
Override the cross-version fixture. Empty derives the release
before this one from the registry.
required: false
default: ""
# No schedule. There was a weekly one, on the reasoning that a published
# tag sits still and could rot underneath. What it actually watched was
# ghcr, sigstore and the runner image, and it re-tested the same
# unchanged artifact every Monday to do it. The answer here can only
# change when the registry changes, and publish.yml now says when that
# happens, so the trigger is the event rather than the calendar. Anyone
# who wants the old behaviour has the dispatch above.
env:
CARGO_TERM_COLOR: always
# Declared rather than inherited, same reason as ci.yml. publish.yml
# calls this with `packages: write` in scope; these jobs only check out
# and boot, so they say so.
permissions:
contents: read
jobs:
install-and-boot:
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: install the published image and boot the disk it wrote
uses: ./.github/actions/install-boot
with:
smoke_args: --published ${{ inputs.image || 'ghcr.io/letdown2491/kuma:niri' }}
- name: guest console
if: failure() || cancelled()
run: tail -200 vm-smoke/console-published.log || true
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
if: failure() || cancelled()
with:
name: console-published
path: vm-smoke/console-published.log
if-no-files-found: warn
# 0.8's headline feature, booted for the first time.
#
# Encrypted installs were verified thoroughly and entirely offline: the
# LUKS header, the passphrase, the kargs and the account file all read
# through a loop device. What that cannot answer is the only question a
# person has, which is whether the machine comes up when you type the
# passphrase. Nothing had ever booted one, which made the headline
# feature of 0.8 the one shipped thing with no boot coverage at all.
#
# Runs against the published image rather than a build: encryption is a
# property of the install, not of the image, so this needs no compose
# and adds no build time.
encrypted-boot:
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: install an encrypted disk, then unlock it at the console
uses: ./.github/actions/install-boot
with:
smoke_args: >-
--encrypted
--published ${{ inputs.image || 'ghcr.io/letdown2491/kuma:niri' }}
- name: guest console
if: failure() || cancelled()
run: |
tail -200 vm-smoke/console-published.log || true
echo "=== what the unlocker saw ==="
cat vm-smoke/published/unlock.log || true
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
if: failure() || cancelled()
with:
name: console-encrypted
path: |
vm-smoke/console-published.log
vm-smoke/published/unlock.log
if-no-files-found: warn
# Can a machine installed at one version reach a later one? Nothing has
# ever asked. Every other check builds and boots a single image, so
# "an existing machine survives moving forward" has been a promise
# rather than a result, and it is the promise 44.0 rests on.
#
# Installs an older published tag while pointing its update origin at
# the rolling one, so `bootc upgrade` inside the guest has somewhere
# newer to go. Not `kuma update`: that is the builder's verb, which
# pulls a base and rebuilds, and kuma's own update_check says a machine
# running a published image asks bootc instead.
#
# **The fixture is derived, not written down.** It used to be a
# hardcoded `:niri-0.7.0`, which was the right answer once and then
# aged six releases into testing a jump nobody makes, while the path
# almost every machine actually takes (the release before this one) was
# covered by nothing. A hardcoded newer tag would only move the rot:
# it goes stale the next time you tag, and it goes stale *quietly*,
# because the job keeps passing while answering a question about an
# older release than the one being published.
#
# So it asks the registry. Every pinned tag kuma has ever published is
# still there, which is why the rule about never deleting them matters:
# they are the only fixtures for this and they cannot be recreated.
#
# Oldest-to-current is deliberately NOT covered any more, and it was a
# different question: a file that did not exist when a machine was
# installed and can now only arrive through the /etc merge, which is
# the `policy.json` case. If that needs testing again, dispatch this
# with from_image set rather than adding a second job.
cross-version:
runs-on: ubuntu-24.04
timeout-minutes: 90
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: the release before this one
id: fixture
env:
# Env, not interpolation: the input is a caller's string, and
# this run block is where it would otherwise become code.
FROM_IMAGE: ${{ inputs.from_image }}
run: |
set -euo pipefail
repo="ghcr.io/letdown2491/kuma"
if [ -n "$FROM_IMAGE" ]; then
echo "from=$FROM_IMAGE" >> "$GITHUB_OUTPUT"
echo "caller named the fixture: $FROM_IMAGE"
exit 0
fi
command -v skopeo >/dev/null || sudo apt-get install -y -qq skopeo
# The version being published already has its pinned tag by the
# time this runs, so "previous" is the highest one that is not
# it. Excluded by name rather than by comparison: a rebuilt tag
# would otherwise pick itself.
version=$(grep -m1 '^version = ' Cargo.toml | cut -d'"' -f2)
previous=$(skopeo list-tags "docker://$repo" \
| jq -r '.Tags[] | select(startswith("niri-"))' \
| sed 's/^niri-//' \
| grep -vx "$version" \
| sort -V | tail -1)
# Loud, because a silent fallback here is the whole failure mode
# this derivation exists to avoid.
[ -n "$previous" ] || { echo "::error::no pinned niri-* tag older than $version"; exit 1; }
echo "upgrading from $previous to $version"
echo "from=$repo:niri-$previous" >> "$GITHUB_OUTPUT"
- name: install an old version, upgrade it, and boot what it became
uses: ./.github/actions/install-boot
with:
smoke_args: >-
--published ${{ steps.fixture.outputs.from }}
--upgrade-to ${{ inputs.image || 'ghcr.io/letdown2491/kuma:niri' }}
- name: guest console
if: failure() || cancelled()
run: tail -200 vm-smoke/console-published.log || true
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
if: failure() || cancelled()
with:
name: console-cross-version
path: vm-smoke/console-published.log
if-no-files-found: warn