Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d602fb0
A pin that is behind its upstream is held to a written review, and th…
DevomB Sep 19, 2026
b3e3fa3
The survey can read the sixteen hosts it could not, and four of those…
DevomB Sep 19, 2026
256c674
The pin reviews, and CI asks for them: 26 pins reviewed as fine, six …
DevomB Sep 19, 2026
9970703
The update channel's rules: which statement of what is current zone 0…
DevomB Sep 20, 2026
b17f278
The pin gate is sixty lines, not a hundred and fifty, and says the sa…
DevomB Sep 20, 2026
143b18f
kryptik-update checks a manifest and a pointer for the update channel…
DevomB Sep 20, 2026
bb1938f
What zone 0 keeps for the update channel, and what each of the three …
DevomB Sep 20, 2026
a2c38e5
The update channel's verbs on the broker, and `kryptik update` for th…
DevomB Sep 20, 2026
174995f
The net zone fetches for the update channel: a pipe with a Range head…
DevomB Sep 20, 2026
4001a01
Merge remote-tracking branch 'origin/main' into update-channel
DevomB Sep 20, 2026
603d35e
The update channel's design says what was built, and the roadmap says…
DevomB Sep 20, 2026
b529c30
The launch service's log line for an update verb names the verb and n…
DevomB Sep 20, 2026
43816d6
kryptik-update makes its own snapshot directory and never takes one f…
DevomB Sep 20, 2026
c82469d
Merge main into pin-currency-gate: the roadmap moved under it
DevomB Sep 20, 2026
80a241f
Merge remote-tracking branch 'origin/main' into update-channel
DevomB Sep 20, 2026
54aeda1
A pointer can be verified on a real image: the trust anchor enrols a …
DevomB Sep 20, 2026
da6113b
The release tool writes and signs the statement of what is current, a…
DevomB Sep 20, 2026
e0b2a5f
The update suite fetches a release over the network: the channel, end…
DevomB Sep 20, 2026
0e422ca
The update suite's network step, after review: a proven restart, a wa…
DevomB Sep 20, 2026
709d7db
Merge remote-tracking branch 'origin/main' into update-channel
DevomB Sep 20, 2026
bcea985
The broker's fuzz seeds gain the update channel's three verbs
DevomB Sep 20, 2026
b040194
Merge main into pin-currency-gate: the roadmap's pins entry moved und…
DevomB Sep 20, 2026
2176597
Three code scanning alerts fixed at the source: no shell in the EFI t…
DevomB Sep 20, 2026
9d54924
A password has its own way to the guest, so no path leads from one to…
DevomB Sep 20, 2026
a8ffcfb
The build checks that the device helper is executable, now that a too…
DevomB Sep 20, 2026
37203ee
util-linux 2.42.3 builds against glibc 2.40, and asks the kernel to b…
DevomB Sep 20, 2026
7dbd0a5
The suites' release host holds a requested name to its root before it…
DevomB Sep 20, 2026
6ac2a4f
Merge remote-tracking branch 'origin/main' into update-channel
DevomB Sep 20, 2026
c939eb0
Merge the util-linux-resolve-flag branch (#40): util-linux 2.42.3 bui…
DevomB Sep 20, 2026
cdb2471
Merge the code-scanning-round-two branch (#39): no shell in the EFI t…
DevomB Sep 20, 2026
fcffb04
Merge the pin-currency-gate branch (#26): a pin that is behind its up…
DevomB Sep 20, 2026
4d8f6e2
Merge the update-channel branch (#33): the net zone fetches, zone 0 b…
DevomB Sep 20, 2026
6fdccf8
The six installed-system suites share one copy of their helpers
DevomB Sep 20, 2026
1e17453
The state partition is LUKS2, asked for on the console at every boot
DevomB Sep 20, 2026
c281f2f
A kernel is judged before it gets its name on the ESP, and a read-bac…
DevomB Sep 20, 2026
904dd60
Netlink replies come from the kernel or not at all, and a zone's /tmp…
DevomB Sep 20, 2026
fa75223
The proxy tells every registry of a removed global, rests after a fai…
DevomB Sep 20, 2026
6eb7771
The acceptance verdict believes a suite's own count of failures, sees…
DevomB Sep 20, 2026
69813f0
The licence is whole, and the threat model says what a stolen disk gi…
DevomB Sep 20, 2026
2801119
A statement dated more than a day ahead of the clock is refused
DevomB Sep 20, 2026
a1b18ac
First-boot setup is done when a user and root can both authenticate, …
DevomB Sep 20, 2026
a8ac808
The installer and recovery take their source from the medium that boo…
DevomB Sep 20, 2026
259b3a7
The workflows run reviewed code: actions by commit, the compiler by v…
DevomB Sep 20, 2026
a60ebe2
Every suite runs and every shell script is linted, because both are f…
DevomB Sep 20, 2026
f352a86
The kernel's critical options may be modules, and CI asks the questio…
DevomB Sep 20, 2026
6694f3a
Merge the kernel-critical-list branch: the kernel's critical options …
DevomB Sep 20, 2026
31a5db5
A zone writes into a pipe, and the launcher is the only writer of its…
DevomB Sep 20, 2026
264b4a1
A refused manifest is not retried for an hour, a staging directory is…
DevomB Sep 20, 2026
2f4a9b3
A statement is written only about a manifest whose signature the imag…
DevomB Sep 20, 2026
e6b35a9
The updater writes the file it hashed, sees a dotfile, and lists befo…
DevomB Sep 20, 2026
9599273
The status page names the last run that passed, and says what no run …
DevomB Sep 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 31 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
name: Commit identity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
# The whole history, because the check is over the whole history.
fetch-depth: 0
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
name: Shell lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

- name: Install shellcheck
run: sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck
Expand Down Expand Up @@ -82,7 +82,7 @@ jobs:
# nothing here reports more than it has established.
fail=0
skipped=""
for t in tools/test-*.sh; do
for t in tools/test-*.sh tools/test-*.py; do
echo "=== $t"
# The step's shell is `bash -e`: a bare non-zero exit ends the
# step before rc is read, so the first suite that answered 77 took
Expand All @@ -104,13 +104,14 @@ jobs:
exit $fail

- name: Shellcheck
# tools/vm/ and the launcher suite were outside this list until now,
# which left the two largest scripts in the tree ungated - including the
# one that decides whether a boot passed. Three real warnings came out
# of adding them.
# Every tracked file that begins with a shell's name, not a list of
# places. The list left out the boot services, the installer, the
# updater, the net zone and every installed-system suite.
run: |
shellcheck -S warning -x build/lib/common.sh build/stages/*.sh \
tools/*.sh tools/vm/*.sh compartments/tests/*.sh
mapfile -t scripts < <(git ls-files | xargs awk 'FNR==1 { if ($0 ~ /^#! ?\/(usr\/)?bin\/(env +)?(ba|da)?sh/) print FILENAME; nextfile }')
echo "${#scripts[@]} shell scripts"
[ "${#scripts[@]}" -ge 100 ] || { echo "the search for scripts found too few: it is broken"; exit 1; }
shellcheck -S warning -x "${scripts[@]}"

- name: Executable bits are recorded
run: |
Expand All @@ -121,7 +122,8 @@ jobs:
# was committed 100644 - so git skipped it silently on every commit
# and the hook has never once run.
fail=0
for f in build/stages/*.sh tools/*.sh tools/vm/*.sh \
for f in build/stages/*.sh tools/*.sh tools/test-*.py tools/vm/*.sh \
tools/image/*.sh tools/image/*.py \
compartments/tests/*.sh tools/git-hooks/*; do
mode=$(git ls-files -s "$f" | awk '{print $1}')
if [ "$mode" != "100755" ]; then
Expand All @@ -143,7 +145,7 @@ jobs:
name: Source manifest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

- name: Manifest resolves
run: ./tools/fetch-sources.sh --list
Expand All @@ -164,7 +166,7 @@ jobs:
# is missing, and the prune drops what the manifest no longer names.
- name: Upstream sources (cached by sources.lock)
id: sources
uses: actions/cache@v5
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: sources
key: sources-${{ hashFiles('sources.lock') }}
Expand Down Expand Up @@ -271,7 +273,7 @@ jobs:
name: Compartment layer
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

- name: kryptikd unit tests
run: cd compartments/kryptikd && cargo test
Expand Down Expand Up @@ -451,14 +453,29 @@ jobs:
name: Kernel currency
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

# Every pinned series with a published support window must still be
# inside it. OpenSSL 3.3 went out of support on 2026-04-09 and Kryptik
# shipped 3.3.1 for five months after; the tool knew and nothing ran it.
- name: Pinned series are supported upstream
run: ./tools/check-support-status.sh --strict

# Survey (network) then gate (no network). On a pull request the verdict
# is printed and does not fail the check: an upstream that released this
# morning is not the pull request's fault. The weekly run is the alarm.
- name: Pins behind upstream are reviewed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./tools/check-source-currency.sh --tsv > pin-survey.tsv
echo "survey: $(wc -l < pin-survey.tsv) sources"
if [ "${{ github.event_name }}" = "pull_request" ]; then
./tools/check-pin-reviews.sh --survey pin-survey.tsv || echo "pull request: informational"
else
./tools/check-pin-reviews.sh --survey pin-survey.tsv
fi

- name: Pinned kernel is longterm and not EOL
run: ./tools/check-kernel-eol.sh

Expand Down
49 changes: 28 additions & 21 deletions .github/workflows/distro.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ env:
# the cache below may hold a sysroot from an earlier version of a stage.
KRYPTIK_STALE: rebuild
NO_COLOR: "1"
RUST_TOOLCHAIN: "1.98.1"
# What 00-host-check and the stages need on the host, every job alike.
HOST_PACKAGES: >-
build-essential bison flex texinfo gawk m4 patch perl python3 python3-pip
Expand All @@ -58,7 +59,7 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 360
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

- name: Working directories on the large disk
run: |
Expand All @@ -85,7 +86,7 @@ jobs:

- name: Upstream sources (cached by sources.lock)
id: sources
uses: actions/cache@v5
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: /mnt/kryptik/sources
key: sources-${{ hashFiles('sources.lock') }}
Expand All @@ -105,7 +106,7 @@ jobs:
# own fingerprints); a partial hit on the prefix resumes where an
# earlier run stopped, which is what makes a six-hour limit survivable.
- name: Stage 01-02 sysroot (cached)
uses: actions/cache@v5
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: |
/mnt/kryptik/work/sysroot
Expand Down Expand Up @@ -135,7 +136,7 @@ jobs:
tar --zstd -cf work-after-02.tar.zst -C work "${members[@]}"
ls -la work-after-02.tar.zst

- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: work-after-02
path: /mnt/kryptik/work-after-02.tar.zst
Expand All @@ -144,7 +145,7 @@ jobs:

- name: Stage logs
if: always()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: logs-toolchain
path: /mnt/kryptik/work/logs
Expand All @@ -157,7 +158,7 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 360
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

- name: Working directories on the large disk
run: |
Expand All @@ -183,7 +184,7 @@ jobs:

- name: Upstream sources (cached by sources.lock)
id: sources
uses: actions/cache@v5
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: /mnt/kryptik/sources
key: sources-${{ hashFiles('sources.lock') }}
Expand All @@ -198,7 +199,7 @@ jobs:
make sources
./tools/prune-sources.sh

- uses: actions/download-artifact@v7
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: work-after-02
path: /mnt/kryptik
Expand Down Expand Up @@ -226,7 +227,7 @@ jobs:
# producing the same sysroot as the run before them.
- name: Stage 04-05 sysroot and kernel (cached)
id: work05
uses: actions/cache/restore@v5
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: /mnt/kryptik/work-after-05.tar.zst
key: work05-${{ hashFiles('build/stages/00-host-check.sh', 'build/stages/01-toolchain.sh', 'build/stages/02-temp-tools.sh', 'build/lib/**', 'build/patches/**', 'build/config/**', 'sources.lock') }}-${{ hashFiles('build/**', 'tools/**', 'compartments/**', 'compositor/**', 'sources.lock', 'Makefile') }}
Expand All @@ -245,12 +246,18 @@ jobs:

# The two static binaries stage 04 installs are built outside the
# chroot, for musl, exactly as the build host did.
- uses: dtolnay/rust-toolchain@stable
# The compiler of the two binaries that ship is named, not 'stable', and
# the build step below refuses any other. rustup checks what it downloads
# against the channel's own manifest; a hash pinned in this repository,
# as cmake's is, is what the roadmap still asks for.
- uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # the stable branch, 2026-09-20
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
targets: x86_64-unknown-linux-musl

- name: kryptikd and kryptik-wlproxy, static
run: |
rustc --version | grep -qF "rustc ${RUST_TOOLCHAIN} " || { echo "refusing to build what ships with $(rustc --version); the pin is ${RUST_TOOLCHAIN}"; exit 1; }
(cd compartments/kryptikd && cargo build --locked --release --target x86_64-unknown-linux-musl)
(cd compositor && cargo build --locked --release --target x86_64-unknown-linux-musl -p wlproxy --bin kryptik-wlproxy)
cp /mnt/kryptik/cargo/x86_64-unknown-linux-musl/release/kryptikd /mnt/kryptik/kryptikd-musl
Expand Down Expand Up @@ -285,7 +292,7 @@ jobs:
# A cache that could not be saved (the repository's 10 GB is full, or
# the service is having a day) costs the next run an hour, not this one
# its verdict.
- uses: actions/cache/save@v5
- uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
if: steps.work05.outputs.cache-hit != 'true'
continue-on-error: true
with:
Expand Down Expand Up @@ -316,12 +323,12 @@ jobs:
# Never the private halves of the keys: the acceptance job needs the
# certificate, its DER form and the variable stores, nothing that
# signs. An artifact of a public repository is public.
sudo tar --zstd -cf work-after-media.tar.zst -C work --exclude='images/kryptik-root.img' --exclude='images/esp-*.img' --exclude='keys/sb/kryptik-sb.key' --exclude='keys/release/kryptik-release' .
if sudo tar --zstd -tf work-after-media.tar.zst | grep -E 'kryptik-sb\.key$|keys/release/kryptik-release$'; then echo "a private key is in the artifact"; exit 1; fi
sudo tar --zstd -cf work-after-media.tar.zst -C work --exclude='images/kryptik-root.img' --exclude='images/esp-*.img' --exclude='keys/sb/kryptik-sb.key' --exclude='keys/release/kryptik-release' --exclude='keys/release/kryptik-latest' .
if sudo tar --zstd -tf work-after-media.tar.zst | grep -E 'kryptik-sb\.key$|keys/release/kryptik-(release|latest)$'; then echo "a private key is in the artifact"; exit 1; fi
sudo chown "$(id -u):$(id -g)" work-after-media.tar.zst
ls -la work-after-media.tar.zst; df -h /mnt | tail -1

- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: work-after-media
path: /mnt/kryptik/work-after-media.tar.zst
Expand All @@ -330,7 +337,7 @@ jobs:

- name: Stage logs
if: always()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: logs-system
path: /mnt/kryptik/work/logs
Expand All @@ -343,7 +350,7 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 360
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0

- name: Working directories on the large disk
run: |
Expand All @@ -366,7 +373,7 @@ jobs:
sudo apt-get update -qq && sudo apt-get install -y -qq $HOST_PACKAGES
sudo ln -sf /usr/bin/bash /bin/sh
# virt-fw-vars, for the disposable Secure Boot variable stores.
sudo pip install --break-system-packages virt-firmware
sudo pip install --break-system-packages virt-firmware==26.9
virt-fw-vars --help > /dev/null

# KVM on a hosted runner: the device exists; it is the permissions that
Expand All @@ -380,12 +387,12 @@ jobs:
ls -la /dev/kvm

- name: Upstream sources (cached by sources.lock)
uses: actions/cache@v5
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: /mnt/kryptik/sources
key: sources-${{ hashFiles('sources.lock') }}

- uses: actions/download-artifact@v7
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: work-after-media
path: /mnt/kryptik
Expand Down Expand Up @@ -413,7 +420,7 @@ jobs:

- name: Acceptance report and per-item logs
if: always()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: acceptance-report
path: |
Expand All @@ -427,7 +434,7 @@ jobs:
# the first version of this job uploaded that under the release name.
- name: Tested images
if: steps.acceptance.outcome == 'success'
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: kryptik-release
path: /mnt/kryptik/export
Expand Down
Loading
Loading