AgentSkillsCN

local-e2e-testing

适用于在本地构建 Egg OCI 镜像、端到端测试变更、验证镜像能否正常启动,或针对项目运行任意 BuildStream 命令时使用。

SKILL.md
--- frontmatter
name: local-e2e-testing
description: Use when building the egg OCI image locally, testing changes end-to-end, verifying the image boots, or running any BuildStream commands against the project

Local End-to-End Testing

Overview

This is the default development workflow. All build verification happens locally before pushing to the remote. CI is a safety net, not the primary build environment.

Build Bluefin from source and boot it in a VM using three composable just recipes. All BuildStream commands run inside the bst2 container via podman -- no native BuildStream installation required.

Hard gate: No code may be committed or pushed without a local build log showing affected elements build successfully. See verification-before-completion skill for the full gate function.

Prerequisites

RequirementInstall (Fedora)Install (Ubuntu)
podmanPre-installedsudo apt install podman
QEMU + KVMsudo dnf install qemu-system-x86-coresudo apt install qemu-system-x86
OVMF (UEFI firmware)sudo dnf install edk2-ovmfsudo apt install ovmf
KVM accesssudo usermod -aG kvm $USERsudo usermod -aG kvm $USER
Free disk space~50 GB for BuildStream CAS + build artifactsSame

Verify KVM: ls -la /dev/kvm -- if missing, enable virtualization in BIOS.

Commands

One command to rule them all

bash
just show-me-the-future

Builds the OCI image, installs it to a 30GB bootable disk, and launches QEMU. First run takes 1-2 hours (downloading/building ~2000 elements). Subsequent runs with warm cache take minutes.

Individual steps

CommandWhat it does
just buildBuild OCI image inside bst2 container, load into podman
just generate-bootable-imageInstall image to bootable.raw via bootc install to-disk
just boot-vmBoot bootable.raw in QEMU with UEFI + KVM
just bst <args>Run any BuildStream command inside the bst2 container

Ad-hoc BuildStream commands

bash
just bst show oci/bluefin.bst          # Show element details
just bst build bluefin/brew.bst        # Build a single element
just bst shell bluefin/brew.bst        # Interactive shell in build sandbox
just bst artifact log oci/bluefin.bst  # View build logs
just bst artifact delete <element.bst> # Delete cached artifact to reclaim disk

Cache Behavior

BuildStream uses a local Content Addressable Storage (CAS) cache. The first build downloads and builds ~2000 elements (~1-2 hours depending on network). Once cached, only changed elements rebuild — subsequent builds with a warm cache typically take minutes. The cache lives in ~/.cache/buildstream/ (inside the bst2 container, mapped to the host). If disk runs low, use just bst artifact delete <element> to selectively reclaim space or remove the entire cache directory.

Environment Variables

VariableDefaultPurpose
BST2_IMAGE(pinned SHA in Justfile)Override bst2 container image
BUILD_IMAGE_NAMEeggName for the loaded OCI image
BUILD_IMAGE_TAGlatestTag for the loaded OCI image
BUILD_BASE_DIR.Directory for bootable.raw
BUILD_FILESYSTEMbtrfsRoot filesystem type
VM_RAM4096VM memory in MB
VM_CPUS2VM CPU count

Common Failures

SymptomCauseFix
permission denied on /dev/fuseMissing FUSE devicesudo modprobe fuse
bst hangs pulling sourcesNetwork/firewall blocking GNOME CASCheck connectivity to gbm.gnome.org:11003
bootc install fails with device errorSELinux or missing privilegesEnsure --privileged and --security-opt label=type:unconfined_t (already in Justfile)
QEMU: Could not access KVM kernel moduleKVM not availableEnable virtualization in BIOS, sudo modprobe kvm_intel or kvm_amd
QEMU: OVMF firmware not foundMissing OVMF packageInstall edk2-ovmf (Fedora) or ovmf (Ubuntu)
Build runs out of disk spaceBuildStream CAS fills diskNeed ~50 GB free; bst artifact delete to reclaim
podman load fails with permission errorRootless podman can't load large imagesThe Justfile uses sudo podman load

What the Build Produces

  1. OCI image (egg:latest in podman) -- a bootc-compatible container image containing a full GNOME desktop OS with Bluefin customizations
  2. Disk image (bootable.raw) -- a 30GB GPT-partitioned disk with systemd-boot, btrfs root, and the deployed OS tree
  3. Running VM -- QEMU window showing the Bluefin desktop booting with Plymouth splash

Serial Debug Shell

The disk image includes systemd.debug_shell=ttyS1 as a kernel argument. In the QEMU console (stdio), you get access to this debug shell for troubleshooting boot issues without needing a graphical login.

Local OTA Updates via Registry

The local dev workflow extends beyond booting a VM -- you can push updates to a running VM via a local zot OCI registry. This enables a full build-publish-upgrade loop without leaving the network.

Plan: docs/plans/2026-02-15-local-ota-registry.md has the full design and implementation tasks.

Quick Reference

CommandWhat it does
just registry-startStart local zot registry on port 5000
just registry-stopStop the registry (data preserved in volume)
just registry-statusShow registry status and image catalog
just publishPush egg:latest from podman to the local registry
just vm-switch-localPrint the bootc switch command to run inside the VM

The OTA Dev Loop

code
1. just build                              # Build the image
2. just publish                            # Push to local registry
3. just generate-bootable-image && just boot-vm  # Boot VM (first time only)
4. [In VM] sudo bootc switch --transport registry 10.0.2.2:5000/egg:latest  # One-time
5. [In VM] sudo bootc upgrade              # Pull update from local registry

After step 4, the VM permanently tracks the local registry. The iterative loop is just: edit -> just build -> just publish -> bootc upgrade in VM.

How It Works

  • zot runs as a podman container on the host, listening on port 5000
  • 10.0.2.2 is QEMU's default gateway to the host -- the VM reaches the registry there
  • bootc switch rewrites the VM's tracked image ref (one-time, persists across reboots)
  • registries.conf.d drop-in in the image marks 10.0.2.2:5000 as insecure (HTTP, no TLS)
  • policy.json.d drop-in allows unsigned pulls from 10.0.2.2:5000

These configs only affect 10.0.2.2:5000 -- an IP that only exists inside QEMU VMs. Zero effect on production.

Related Skills

  • debugging-bst-build-failures -- When a build fails during local testing, use this skill for systematic diagnosis of BuildStream element failures
  • ci-pipeline-operations -- Understanding how the full CI pipeline works, including remote artifact caching and image publishing to GHCR. Note: the local registry is dev-only; CI continues to use GHCR
  • oci-layer-composition -- The bluefin/local-dev-registry.bst element adds container registry config files to the Bluefin layer