-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsources
More file actions
386 lines (352 loc) · 16.5 KB
/
Copy pathsources
File metadata and controls
386 lines (352 loc) · 16.5 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
377
378
379
380
381
382
383
384
385
386
#!/bin/sh
# sources - where each BSD's userland comes from, and how it has to be handled.
#
# The defect this exists to catch is a matrix written once in a workflow, once
# in a test and once in a README, which drift the first time a release moves.
# Everything reads this file, so bumping a release is one edit.
#
# ⛔ EVERY FACT BELOW WAS MEASURED ON 2026-08-27, NOT READ FROM DOCUMENTATION.
# The three BSDs need two different acquisition methods and that is the whole
# reason this file is not a flat list:
#
# freebsd OCI upstream publishes real OCI layout archives. Verified
# by SHA-256 against the published CHECKSUM.SHA256, then
# loaded. ⭐ Nothing is rebuilt: rebuilding an image
# somebody already publishes correctly is the most
# expensive mistake available.
# netbsd SETS base.tar.xz is already a rootfs tar owned root/wheel,
# so it imports directly. Confirmed: the resulting image
# reports os=netbsd arch=amd64, 269 MB.
# openbsd SETS base79.tgz is the same shape, owned root/bin. 535 MB.
#
# ⛔ DRAGONFLY WAS HERE AND IS NOT ANY MORE. Ruled out by the operator on
# 2026-08-28: it is the least maintained of the four and the other three are
# what anybody actually targets. TODO/RULES.md decision 7. ⚠ What was learnt
# about reading its ISO is kept in HISTORY/dragonfly.md, not deleted, because
# the next person to ask "why not DragonFly" deserves the measurement rather
# than a shrug.
#
# ⚠ x86_64 ONLY, on purpose. This is a proof of concept and one architecture is
# enough to prove it. FreeBSD publishes aarch64 and riscv64 as well; the others
# vary. Adding an architecture means checking it exists first, per BSD.
#
# ⭐ IT ALSO PINS THE RUNNABLE IMAGE'S ARTEFACTS, and that is a second kind of
# fact rather than a fourth BSD. The three ids above are USERLANDS: a tar that
# becomes an image nobody can run without a BSD kernel. The runtime ids below
# are what makes one image BOOT: a guest kernel and a guest root filesystem
# that an emulator inside the image starts.
#
# ⛔ THEY ARE PINNED BY SHA-256 AND THE THREE ABOVE ARE NOT. That asymmetry is
# deliberate and it is about what the URL points at. An upstream release
# directory names its version, so the URL is the pin. Both runtime artefacts
# live behind a MOVING pointer: one is an unversioned asset path and the other
# is a release literally tagged `latest`. A build that took either without a
# digest would produce a different image every week and call it the same one.
#
# ⚠ THE CONSEQUENCE, STATED SO NOBODY IS SURPRISED: when upstream rotates one
# of those pointers the image build FAILS. That is the intended behaviour. The
# fix is to re-pin here, in one edit, after looking at what changed.
#
# Usage:
# sh scripts/sources --list every id
# sh scripts/sources --method ID oci | sets
# sh scripts/sources --version ID
# sh scripts/sources --urls ID one URL per line
# sh scripts/sources --json a GitHub Actions matrix
# sh scripts/sources --runtime-variants rescue | build
# sh scripts/sources --runtime-base the base image, by digest
# sh scripts/sources --runtime-kernel-url the guest kernel, shared
# sh scripts/sources --runtime-kernel-sha256
# sh scripts/sources --runtime-rootfs-url VARIANT
# sh scripts/sources --runtime-rootfs-sha256 VARIANT
# sh scripts/sources --runtime-root-label VARIANT
# sh scripts/sources --runtime-rootfs-size VARIANT empty means do not grow
# sh scripts/sources --runtime-packages VARIANT empty means install none
# sh scripts/sources --runtime-pkg-path the package repository
# sh scripts/sources --runtime-net VARIANT none | user
# sh scripts/sources --runtime-package-url VARIANT
# sh scripts/sources --runtime-package-sha256 VARIANT
# sh scripts/sources --runtime-bench-url VARIANT
# sh scripts/sources --runtime-bench-sha256 VARIANT
#
# Exit codes: 0 ok, 2 unknown id or argument.
set -eu
ARCH_OCI="amd64"
FREEBSD_VERSION="15.1-RELEASE"
NETBSD_VERSION="10.1"
OPENBSD_VERSION="7.9"
# ⚠ OpenBSD names its set after the version with the dot removed: 7.9 is
# base79.tgz. Derived rather than hardcoded so a bump does not need two edits.
OPENBSD_SETVER=$(printf '%s' "$OPENBSD_VERSION" | tr -d '.')
FREEBSD_BASE="https://download.freebsd.org/releases/OCI-IMAGES/${FREEBSD_VERSION}/${ARCH_OCI}/Latest"
NETBSD_BASE="https://cdn.netbsd.org/pub/NetBSD/NetBSD-${NETBSD_VERSION}/${ARCH_OCI}/binary/sets"
OPENBSD_BASE="https://cdn.openbsd.org/pub/OpenBSD/${OPENBSD_VERSION}/${ARCH_OCI}"
# ⚠ FreeBSD ships five variants. Ordered smallest first, so a matrix that is
# going to fail fails on the 559 KB one rather than the 215 MB one.
FREEBSD_VARIANTS="static dynamic runtime notoolchain toolchain"
# ── the runnable image's artefacts ─────────────────────────────────────────
#
# ⛔ THE BASE IS A DIGEST AND THE TAG BESIDE IT IS A COMMENT. The name is
# written so a reader can see which release the digest belongs to; only the
# digest is what a build resolves. alpine:3.22, read on 2026-08-27.
#
# ⚠ EVERY NAME BELOW CARRIES `PINNED` ON PURPOSE, and it is not decoration.
# check-no-secrets.sh flags any long hex string, because that is what a leaked
# credential looks like, and it excludes exactly the hex that is ASSIGNED TO A
# NAME DECLARING ITSELF A PIN. ⛔ Renaming one of these to something shorter
# re-arms that check against a value that is public by construction, and the
# fix then looks like widening a security rule. It is not.
RUNTIME_BASE_IMAGE="docker.io/library/alpine"
RUNTIME_BASE_PINNED_SHA256="14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce"
# ⚠ smolBSD publishes the kernel at an unversioned path and the root filesystem
# under a release tagged `latest`. Both move. The digests below were taken on
# 2026-08-27 and they are the pin.
SMOL_KERNEL_URL="https://smolbsd.org/assets/netbsd-SMOL"
SMOL_KERNEL_PINNED_SHA256="63935f0c30ea304b4fb61b942f6f93c0b29a77b913f94b6f2ec7ebd31570a914"
# ⭐ TWO VARIANTS OF ONE IMAGE, AND THEY DIFFER IN THREE VALUES. The rescue
# userland reaches a shell in seconds and cannot compile anything; the build
# userland carries a toolchain and pkgsrc and is much larger. ⛔ The root label
# is the GPT partition name the kernel is told to mount. It was read out of
# each image rather than guessed, and a wrong one boots a kernel that never
# finds its disk.
SMOL_RELEASE="https://github.com/NetBSDfr/smolBSD/releases/download/latest"
SMOL_RESCUE_URL="$SMOL_RELEASE/rescue-amd64.img.xz"
SMOL_RESCUE_PINNED_SHA256="2a5f3ccc4e0266bcbdb3404d55a803533cedba1c0b8c8cac20f52d1419456ea2"
SMOL_RESCUE_LABEL="rescueroot"
SMOL_BUILD_URL="$SMOL_RELEASE/build-amd64.img.xz"
SMOL_BUILD_PINNED_SHA256="04f85df4e5a9b7248bc481552cd6225157de546eba7e5f45f9dc128d1b2e7594"
SMOL_BUILD_LABEL="buildroot"
# ⛔ THE BUILD VARIANT IS GROWN AND PROVISIONED, AND THE TWO NUMBERS BELOW ARE
# WHY. Measured 2026-08-27: the published build userland has 201 MB free, and
# `pkg_add gcc14` fills it at 106 percent. A development environment that
# cannot hold a compiler is not one, so the root filesystem is grown at build
# time and the compiler goes in there rather than being a thing a consumer has
# to install, wait for, and lose on the next `--rm`.
#
# ⚠ 2G IS A CHOICE AND NOT A MEASUREMENT. gcc14 is 107 MB compressed and about
# a quarter of a gigabyte installed; the rest is room for whatever a consumer
# is building. A bigger number is a bigger image on every consumer's disk.
# ⚠ THE NETWORK IS A PER VARIANT DECISION AND NOT A PREFERENCE. A package
# manager with no network is a package manager that cannot do its one job, so
# the build variant ships with a user-mode stack. The rescue variant exists to
# reach a shell quickly and never installs anything, so it ships with none: the
# emulator attaches an interface unless told not to, and this repository has
# already published a wrong measurement over that.
#
# ⭐ It is user mode, so it needs no privilege and opens no port on the host,
# and `--network none` on the container still cuts it off completely.
# ⚠ The binary package repository the guest installs from. It is a MOVING
# collection by design, which is why the packages are installed once at build
# time and shipped, rather than fetched by each consumer at run time.
SMOL_PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/11.0/All"
SMOL_RESCUE_NET="none"
SMOL_BUILD_NET="user"
SMOL_RESCUE_SIZE=""
SMOL_RESCUE_PACKAGES=""
SMOL_RESCUE_PKG_URL=""
SMOL_RESCUE_PKG_PINNED_SHA256=""
SMOL_BUILD_SIZE="2G"
# ⛔ EMPTY, AND THAT IS A MEASURED RETREAT RATHER THAN AN OVERSIGHT. Installing
# this package by booting the guest DOES NOT COMPLETE. Measured 2026-08-28,
# twice: the guest echoes the command, prints nothing at all for fifty minutes
# with the emulator at full tilt, and the driver gives up at its timeout. It is
# not slow. It does not finish.
#
# ⛔ SO THE STEP IS OFF UNTIL INF-09 EXPLAINS IT. A build step that provably
# cannot pass is a red default branch that teaches everybody to ignore a red
# default branch, and nothing else in the variant depends on it.
#
# ⭐ EVERYTHING THE STEP NEEDED IS STILL THERE, which is the point of turning
# the step off rather than the variant. The package file is inside the guest at
# the path below, the root filesystem is grown to hold what it unpacks to, and
# the guest has a network. A session picking up INF-09 boots the image and runs
# `pkg_add -U /guest-package.tgz` by hand, with nothing to set up first.
#
# ⚠ The path it sits at in the guest is `/guest-package.tgz`, written here as a
# comment rather than a variable: a variable nothing reads is a variable a
# linter is right to object to, and this is a fact for a person.
SMOL_BUILD_PACKAGES=""
# ⭐ THE PACKAGE IS FETCHED BY LINUX AND WRITTEN INTO THE GUEST'S FILESYSTEM
# BEFORE IT BOOTS, and that is a measured decision rather than a tidy one.
# Fetching it from inside the guest, through the emulated network stack, took
# longer than every other step in the build put together and did not finish
# inside a runner's hour. The same file over the container's own network is a
# few seconds.
#
# ⭐ It also closes a hole: a version in the URL is a pin, and a digest beside
# it is a second one. `pkg_add gcc14` resolved a moving name over TLS and
# verified nothing.
#
# ⚠ ONE PACKAGE, NOT A LIST, and that is a real limit. gcc14 declares no
# dependencies at all, which is what makes a single file enough. A package that
# has some would need its whole closure resolved here, and nothing does that.
SMOL_BUILD_PKG_URL="$SMOL_PKG_PATH/gcc14-14.3.0nb1.tgz"
SMOL_BUILD_PKG_PINNED_SHA256="93c5e1aeda6227915c6a4d70af5b55888760f5015608085617d53459cd76503f"
# ⭐ THE BENCHMARK'S SOURCE SHIPS INSIDE THE GUEST, AND IT HAS TO. `-v` does not
# reach the guest yet, so there is no way to hand it a source tree at run time.
# ⛔ Without this the only compile anybody could time inside the guest is one
# typed at a serial console one character at a time.
#
# ⚠ SQLite's amalgamation is the choice because it is a REAL C project in one
# file: about a quarter of a million lines, no dependencies, no configure step,
# and the same bytes compile on both sides of the comparison. A synthetic file
# would measure whatever it was written to measure.
SMOL_BENCH_URL="https://sqlite.org/2025/sqlite-autoconf-3500400.tar.gz"
SMOL_BENCH_PINNED_SHA256="a3db587a1b92ee5ddac2f66b3edb41b26f9c867275782d46c3a088977d6a5b18"
ids() { printf 'freebsd\nnetbsd\nopenbsd\n'; }
runtime_variants() { printf 'rescue\nbuild\n'; }
rootfs_url() {
case "$1" in
rescue) printf '%s\n' "$SMOL_RESCUE_URL" ;;
build) printf '%s\n' "$SMOL_BUILD_URL" ;;
*) printf 'sources: unknown variant: %s\n' "$1" >&2; exit 2 ;;
esac
}
rootfs_sha256() {
case "$1" in
rescue) printf '%s\n' "$SMOL_RESCUE_PINNED_SHA256" ;;
build) printf '%s\n' "$SMOL_BUILD_PINNED_SHA256" ;;
*) printf 'sources: unknown variant: %s\n' "$1" >&2; exit 2 ;;
esac
}
rootfs_label() {
case "$1" in
rescue) printf '%s\n' "$SMOL_RESCUE_LABEL" ;;
build) printf '%s\n' "$SMOL_BUILD_LABEL" ;;
*) printf 'sources: unknown variant: %s\n' "$1" >&2; exit 2 ;;
esac
}
rootfs_size() {
case "$1" in
rescue) printf '%s\n' "$SMOL_RESCUE_SIZE" ;;
build) printf '%s\n' "$SMOL_BUILD_SIZE" ;;
*) printf 'sources: unknown variant: %s\n' "$1" >&2; exit 2 ;;
esac
}
bench_url() {
case "$1" in
rescue) printf '
' ;;
build) printf '%s
' "$SMOL_BENCH_URL" ;;
*) printf 'sources: unknown variant: %s
' "$1" >&2; exit 2 ;;
esac
}
bench_sha256() {
case "$1" in
rescue) printf '
' ;;
build) printf '%s
' "$SMOL_BENCH_PINNED_SHA256" ;;
*) printf 'sources: unknown variant: %s
' "$1" >&2; exit 2 ;;
esac
}
package_url() {
case "$1" in
rescue) printf '%s
' "$SMOL_RESCUE_PKG_URL" ;;
build) printf '%s
' "$SMOL_BUILD_PKG_URL" ;;
*) printf 'sources: unknown variant: %s
' "$1" >&2; exit 2 ;;
esac
}
package_sha256() {
case "$1" in
rescue) printf '%s
' "$SMOL_RESCUE_PKG_PINNED_SHA256" ;;
build) printf '%s
' "$SMOL_BUILD_PKG_PINNED_SHA256" ;;
*) printf 'sources: unknown variant: %s
' "$1" >&2; exit 2 ;;
esac
}
rootfs_net() {
case "$1" in
rescue) printf '%s
' "$SMOL_RESCUE_NET" ;;
build) printf '%s
' "$SMOL_BUILD_NET" ;;
*) printf 'sources: unknown variant: %s
' "$1" >&2; exit 2 ;;
esac
}
rootfs_packages() {
case "$1" in
rescue) printf '%s\n' "$SMOL_RESCUE_PACKAGES" ;;
build) printf '%s\n' "$SMOL_BUILD_PACKAGES" ;;
*) printf 'sources: unknown variant: %s\n' "$1" >&2; exit 2 ;;
esac
}
method() {
case "$1" in
freebsd) printf 'oci\n' ;;
netbsd) printf 'sets\n' ;;
openbsd) printf 'sets\n' ;;
*) printf 'sources: unknown id: %s\n' "$1" >&2; exit 2 ;;
esac
}
version() {
case "$1" in
freebsd) printf '%s\n' "$FREEBSD_VERSION" ;;
netbsd) printf '%s\n' "$NETBSD_VERSION" ;;
openbsd) printf '%s\n' "$OPENBSD_VERSION" ;;
*) printf 'sources: unknown id: %s\n' "$1" >&2; exit 2 ;;
esac
}
urls() {
case "$1" in
freebsd)
for v in $FREEBSD_VARIANTS; do
printf '%s/FreeBSD-%s-%s-container-image-%s.txz\n' \
"$FREEBSD_BASE" "$FREEBSD_VERSION" "$ARCH_OCI" "$v"
done ;;
netbsd)
printf '%s/base.tar.xz\n' "$NETBSD_BASE"
printf '%s/etc.tar.xz\n' "$NETBSD_BASE" ;;
openbsd)
printf '%s/base%s.tgz\n' "$OPENBSD_BASE" "$OPENBSD_SETVER" ;;
*) printf 'sources: unknown id: %s\n' "$1" >&2; exit 2 ;;
esac
}
json() {
printf '{"include":['
first=1
for id in $(ids); do
[ "$first" = "1" ] || printf ','
first=0
printf '{"bsd":"%s","method":"%s","version":"%s","arch":"%s"}' \
"$id" "$(method "$id")" "$(version "$id")" "$ARCH_OCI"
done
printf ']}\n'
}
case "${1:-}" in
--list) ids ;;
--arch) printf '%s\n' "$ARCH_OCI" ;;
--variants) printf '%s\n' "$FREEBSD_VARIANTS" ;;
--method) shift; method "${1:-}" ;;
--version) shift; version "${1:-}" ;;
--urls) shift; urls "${1:-}" ;;
--json) json ;;
--runtime-variants) runtime_variants ;;
--runtime-kernel-url) printf '%s
' "$SMOL_KERNEL_URL" ;;
--runtime-kernel-sha256) printf '%s
' "$SMOL_KERNEL_PINNED_SHA256" ;;
--runtime-rootfs-url) shift; rootfs_url "${1:-}" ;;
--runtime-rootfs-sha256) shift; rootfs_sha256 "${1:-}" ;;
--runtime-root-label) shift; rootfs_label "${1:-}" ;;
--runtime-rootfs-size) shift; rootfs_size "${1:-}" ;;
--runtime-packages) shift; rootfs_packages "${1:-}" ;;
--runtime-pkg-path) printf '%s\n' "$SMOL_PKG_PATH" ;;
--runtime-net) shift; rootfs_net "${1:-}" ;;
--runtime-package-url) shift; package_url "${1:-}" ;;
--runtime-package-sha256) shift; package_sha256 "${1:-}" ;;
--runtime-bench-url) shift; bench_url "${1:-}" ;;
--runtime-bench-sha256) shift; bench_sha256 "${1:-}" ;;
--runtime-base) printf '%s@sha256:%s\n' "$RUNTIME_BASE_IMAGE" "$RUNTIME_BASE_PINNED_SHA256" ;;
-h|--help) awk 'NR>1 { if (/^#/) { sub(/^# ?/, ""); print } else exit }' "$0" ;;
*) printf 'sources: expected --list --arch --variants --method --version --urls --json --runtime-variants --runtime-base --runtime-kernel-url --runtime-kernel-sha256 --runtime-rootfs-url --runtime-rootfs-sha256 --runtime-root-label --runtime-rootfs-size --runtime-packages --runtime-pkg-path --runtime-net --runtime-package-url --runtime-package-sha256 --runtime-bench-url or --runtime-bench-sha256\n' >&2; exit 2 ;;
esac