The Distro workflow builds and tests every push to main on GitHub's
runners, so a local build is optional. It needs Linux; make check refuses
to run anywhere else and names what the host is missing.
On Debian or Ubuntu, the same set the Distro workflow installs
(HOST_PACKAGES in .github/workflows/distro.yml):
sudo apt install -y build-essential bison flex texinfo gawk m4 patch perl \
python3 python3-pip xz-utils bzip2 zstd cpio rsync bc curl git openssl \
libssl-dev libelf-dev e2fsprogs dosfstools mtools exfatprogs xorriso \
util-linux cryptsetup-bin sbsigntool libasound2-dev qemu-system-x86 ovmf \
musl-tools file
sudo dpkg-reconfigure dash # answer "No": /bin/sh must be bashThe Secure Boot suites also need virt-fw-vars (pip install virt-firmware), and the acceptance suites want KVM.
Build from a clone on the Linux filesystem, not /mnt/c: it is slow, and it
cannot represent the POSIX ownership the chroot stages depend on. GCC's
bootstrap wants about 8 GB of memory; if make check warns, raise the limit
in %UserProfile%\.wslconfig and run wsl --shutdown:
[wsl2]
memory=12GB
processors=8make check # what the host is missing
make lock # regenerate sources.lock; audit it (docs/supply-chain.md)
make sources # fetch and verify
make toolchain # stage 01 (unprivileged)
make temp-tools # stage 02 (unprivileged)
make system # stage 04, inside the chroot (root for the mounts)
make kernel # stage 05, inside the chroot
make images # the software images over stage 04: the toolkit, the browser (hours)
make media # stage 06: USB image, ISO, signed release payloaduntrusted, personal and work name the browser and toolkit images, and a
zone naming an image does not start unless its root has a signed list that
holds it, so a medium for use needs make images before make media. Firefox
alone takes some three hours on four cores; a rebuilt stage 04 rebuilds it
only when a step up to wlroots changed, or the headers and libraries a build
can find (software delivery).
make paths prints where everything goes; KRYPTIK_WORK moves the work tree.
Each step is stamped, so a rerun resumes where it stopped and a changed
recipe rebuilds from that step on.
make media KRYPTIK_CHANNEL=https://<host>/<channel>/ names where the
image's network zone asks for new releases
(update channel). Without it the image fetches
nothing, and updates come only from a payload on a disk.
A development image, the default, is signed with keys the build makes on
first use under <work>/keys (<work> is KRYPTIK_WORK, as make paths
prints it). A production image is signed only with keys it is handed, from
the key medium, and names its version as MAJOR.MINOR.PATCH:
make media KRYPTIK_ROLE=production KRYPTIK_KEYS=/media/<medium> KRYPTIK_VERSION=1.0.3The medium holds release-signers (the anchor the image will trust),
kryptik-release and kryptik-release.pub, kryptik-sb.key and
kryptik-sb.crt, and optionally kryptik-latest and kryptik-latest.pub
and kryptik-testctl and kryptik-testctl.pub, which the build reads only
to check they are the anchor's.
Its private keys must be readable by their owner alone, who is root or the
user running the build, and it must not be inside the work or output tree.
Stage 06 checks all of that before it signs anything. It makes no key and
copies none: the keys are read by the tools that sign with them, by path.
Making the keys, publishing with them, and replacing them are in
release keys.
The Distro workflow splits a production build so its keys never reach the
machine that ran the chroot. KRYPTIK_MEDIA_PHASE=bind, with KRYPTIK_KEYS
naming a directory that holds release-signers and kryptik-sb.crt and no
private key, builds the root and binds the kernels to it. Then
KRYPTIK_MEDIA_PHASE=sign, with the whole medium, on another machine given
the work tree and that release's stage 06 stamps, checks what was bound
against the medium, signs and assembles the media without touching the
sysroot or the chroot.
To publish a build, add its payload to the channel's directory, which any web server can then serve at that address:
tools/release-channel.sh publish --key <work>/keys/release/kryptik-latest \
--signers <work>/keys/release/release-signers \
--payload <work>/images/payload-<version> --out /srv/<channel>For a production image, the key and the signers file are the medium's
kryptik-latest and release-signers. When the medium carries no
kryptik-latest, stage 06 leaves publishing to the release host, which holds
that key. Re-sign the channel's statement daily, with reissue and the same
key and signers file, from a timer: a machine reports a statement older than
30 days.
The host suites need no build and no root:
make test # every tools/tests/* suite, then the compartment suites
make zone-tests # adversarial.sh (the primitives) and launcher.sh (kryptikd run)The compartment suites need a Rust toolchain and a kernel with user
namespaces, seccomp and Landlock. The privileged launch path and cgroup
limits run as root only on the installed system, in make zones-test.
Five kinds of test, one name each:
| name | where | what |
|---|---|---|
| tool suites | tools/tests/*.sh, *.py |
a tool's own offline suite, named after the tool it tests |
| compartment suites | compartments/tests/*.sh |
kryptikd's suites, as root or not |
| guest checks | build/guest-tests/*-check.sh |
run inside the booted image; print the pass and fail lines the image suite reads |
| image suites | tools/image/*-test.sh |
boot the image under OVMF, drive it, judge its guest checks and screenshots |
| acceptance | tools/acceptance.sh |
the verdict over all of them: make acceptance |
make acceptance runs every suite against the built media, as root under
KVM. The update suite installs the release before the newest and updates it
to the newest, so it needs two. The production suite does the same with a
production pair, signed with a throwaway key medium that exists only while
make production-pair builds the pair, and kept apart in
<work>/images-production. Build the pair first, since the suites take the
release built last as the one under test:
make production-pair
make media KRYPTIK_VERSION=0.1.1
make media KRYPTIK_VERSION=0.1.2
make acceptance EXPORT=/tmp/kryptik-exporttools/release-publish.sh /tmp/kryptik-export puts that export on the
repository's Releases page once tag v0.1.2 is pushed (releases).
The suites arm their unattended installs with a control disk the medium
under test checks against its anchor. A development medium honours the
build's own kryptik-testctl (under <work>/keys/release), the default; a
production release's media honour the release's own, so its acceptance names
it: make acceptance EXPORT=DIR KRYPTIK_TESTCTL_KEY=<copy>/kryptik-testctl
(release keys). The boot tests enrol the Secure Boot
certificate the medium under test carries, and the export publishes that
certificate: a production release is tested as a machine that enrolled its
certificate boots it.