veilor-os/kickstart/install-ostreecontainer.ks

80 lines
3.3 KiB
Text
Raw Normal View History

v0.7 spike: BlueBuild recipe + ostreecontainer kickstart + cosign workflow Initial scaffold for the v0.7 hybrid path. Spike branch only — does NOT land in main until success criteria pass (see bluebuild/README.md). ## What this commits - bluebuild/recipe.yml — BlueBuild recipe extending ghcr.io/secureblue/securecore-kinoite-hardened-userns:latest with: * veilor branding overlay (overlay/, assets/, scripts/ at /usr/share/veilor-os) * sudo restored (revert secureblue's run0-only) * Xwayland restored (some apps still need it) * mullvad-browser layered alongside Trivalent (default browser kept) * tailscale + yggdrasil packages (mesh stack layers 1 + 2) * tailscaled.service pre-disabled (awaits first-boot prompt) * yggdrasil.service enabled (idle warm-fallback per STRATEGY.md) * veilor-firstboot.service + veilor-modules-lock.service enabled * cosign signing module configured - bluebuild/config/just/60-veilor.just — ujust recipes: * install-reticulum (RetiNet AGPL fork — mesh layer 3) * install-reticulum-rnode (LoRa hardware) * install-thorium (opt-in browser with explicit CVE-lag warning) * veilor-mesh-join (token paste / QR for tailscale onboarding) - bluebuild/README.md — spike doc + smoke-test commands + 5-item success criteria checklist - kickstart/install-ostreecontainer.ks — install kickstart template for the v0.7 path. No %packages block; uses `ostreecontainer --url=ghcr.io/veilor-org/veilor-os:43 --transport=registry` to populate / from the OCI image directly during anaconda's install pass. No first-boot rebase, no transition window. Keeps existing LUKS+btrfs partitioning verbatim. - .github/workflows/build-bluebuild.yml — GH Actions workflow: * Triggered on push to v0.7-bluebuild-spike, weekly cron, dispatch * Uses blue-build/github-action@v1 (TODO: pin to commit SHA per CI hardening agent 8 follow-up) * Builds + cosign-signs (keyless via Sigstore) + pushes to GHCR * Smoke-tests the OCI image (sudo, mullvad-browser, yggdrasil, tailscale all present) * Generates SBOM (SPDX) via anchore/sbom-action * Publishes SLSA build provenance attestation ## What this does NOT change - main branch is untouched. v0.5.x kickstart path keeps shipping. - kickstart/veilor-os.ks (the live-ISO ks) is untouched — the v0.7 hybrid uses the existing live-ISO build path; only the install-time ks (install-ostreecontainer.ks) is new. - overlay/, scripts/, assets/ are untouched on this branch — the recipe pulls them in via `type: files` modules at build time. ## Spike success criteria (reproduced from bluebuild/README.md) - [ ] `bluebuild build recipe.yml` exits 0 - [ ] `bootc container lint` exits 0 on resulting image - [ ] `podman run` smoke-test passes - [ ] CI workflow builds + cosign-signs + pushes to GHCR - [ ] Installer ISO using `ostreecontainer` against this OCI reaches SDDM with admin login on first boot If all 5 land, merge v0.7-bluebuild-spike → main as v0.7.0. ## Reference - docs/STRATEGY.md (full plan) - docs/ROADMAP.md v0.7 (schedule) - docs/THREAT-MODEL.md (publish before v0.7 ship) - secureblue: https://github.com/secureblue/secureblue - BlueBuild: https://blue-build.org - ostreecontainer: https://docs.fedoraproject.org/en-US/bootc/anaconda-install/
2026-05-05 15:30:04 +01:00
# veilor-os install kickstart — v0.7 spike (ostreecontainer path)
#
# This is the install-time kickstart for the v0.7 hybrid path. The live
# ISO boots; the gum TUI collects user answers (disk, LUKS pw, admin pw);
# this template gets the answers substituted in and is fed to anaconda.
#
# Anaconda partitions the disk + creates LUKS + btrfs subvols + mounts
# /boot/efi + /boot, then `ostreecontainer` populates `/` directly from
# the cosign-signed veilor-os OCI image at `ghcr.io/veilor-org/veilor-os:43`.
#
# No `%packages` block. No first-boot rebase. No
# `veilor-firstboot-rebase.service`. The ostreecontainer install pass is
# the entire transition from "Fedora live ISO" to "veilor-os on disk".
#
# Reference: pykickstart docs ostreecontainer command;
# https://docs.fedoraproject.org/en-US/bootc/anaconda-install/
# ── Locale / keyboard / time ──
keyboard --xlayouts='us'
lang en_US.UTF-8
timezone Europe/London --utc
# ── Install mode / behaviour ──
firstboot --disable
eula --agreed
# SELinux state inherited from the OCI image; --enforcing is implicit
# since secureblue's image ships /etc/selinux/config = enforcing.
selinux --enforcing
# ── Network / hostname ──
network --bootproto=dhcp --device=link --activate --hostname=__HOSTNAME__
firewall --enabled --service=ssh
# ── Identity (single LUKS prompt asked at install via gum TUI) ──
rootpw --lock
user --name=admin --groups=wheel --gecos="veilor admin" --password=__ADMIN_PW__ --plaintext
# ── Bootloader ──
# fbcon=nodefer for laptop KMS handoff (real-hardware audit, agent 9 of
# 2026-05-05 wave). rd.luks.options=tries=5,timeout=0 for UX.
# rd.luks.uuid is auto-injected by anaconda based on the encrypted
# part directive below.
#
# All other hardening kargs (lockdown=integrity, slab_nomerge, etc.)
# come from /usr/lib/bootc/kargs.d/ inside the OCI image — bootc
# applies them at install time. We only add what the OCI image can't
# know (laptop-specific KMS flag).
bootloader --append="fbcon=nodefer"
# ── Disk: LUKS2 (argon2id) + btrfs subvols ──
zerombr
clearpart --all --initlabel --drives=__DISK_BASENAME__
part /boot/efi --fstype=efi --size=600
part /boot --fstype=ext4 --size=1024
part btrfs.veilor --grow --encrypted --luks-version=luks2 --pbkdf=argon2id --passphrase=__LUKS_PW__
btrfs none --label=veilor btrfs.veilor
btrfs / --subvol --name=root LABEL=veilor
btrfs /home --subvol --name=home LABEL=veilor
# ── ostreecontainer: populate / from the veilor-os OCI image ──
# `--transport=registry` pulls from ghcr.io directly. Authentication
# token can be supplied via /etc/ostree/auth.json baked into the live
# rootfs OR via a kickstart `--remote-token` if the registry is private.
# At v0.7 spike the OCI image is public, so no auth needed.
#
# DO NOT migrate to the new `bootc` kickstart command until v1.0 — it
# blocks multi-disk and authenticated registries (per parent-operator
# handoff 2026-05-05).
ostreecontainer --url=ghcr.io/veilor-org/veilor-os:43 --transport=registry
# ── %post (chroot) — minimal; OCI image already has everything ──
# What we keep:
# - chage -d 0 admin so first SDDM login forces password change
# - hostname write (anaconda's --hostname doesn't always survive)
# - veilor-firstboot.service is enabled in the OCI image already
%post
set -uo pipefail
echo veilor > /etc/hostname
chage -d 0 admin || true
%end