banger/docs/kernel-catalog.md
Thales Maciel 80ae4d6667
docs: resync package docs, AGENTS, and kernel-catalog with current code
Four drift fixes from a doc sweep.

internal/daemon/doc.go
  Replace the capability-hook description that still said "Hook
  methods take *Daemon; VMService reaches them through a
  capabilityHooks seam." Current reality: every capability is a
  plain struct carrying its own service pointers
  (workDiskCapability{vm,ws,store}, dnsCapability{net},
  natCapability{vm,net,logger}); wireServices builds the default
  list; no hook reaches *Daemon.

internal/daemon/ARCHITECTURE.md
  The VMService field list still claimed guestWaitForSSH and
  guestDial were "per-instance fields." Those were deleted as
  refactor residue. Update the note to say the seams live on
  *Daemon (reached by WorkspaceService via closures wired at
  construction) and document the vsockHostDevice field that
  replaced the old package-global vsockHostDevicePath.

AGENTS.md
  Drop the "experimental web UI" mention (removed) and the
  `session` subpackage (removed). Mention banger-vsock-agent as
  the third cmd/ binary while we're here — AGENTS hadn't listed
  it.

docs/kernel-catalog.md
  The trust-model section still read as if upstream kernel sources
  were fetched by HTTPS alone. Add a paragraph covering the PGP
  verification make-generic-kernel.sh now does against the
  detached .tar.sign and the three kernel.org release signing keys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 13:01:11 -03:00

5.7 KiB

Kernel catalog

The kernel catalog ships pre-built Firecracker-ready kernel bundles so users don't have to compile anything. The catalog is embedded into the banger binary and updated each release.

End-user flow:

banger kernel list --available       # browse the catalog
banger kernel pull generic-6.12      # download a bundle (no sudo, no make)
banger image register --name myimg --rootfs … --kernel-ref generic-6.12

Architecture

Two parts:

  1. internal/kernelcat/catalog.json — a JSON manifest embedded into the banger binary via go:embed. Each entry carries a name, distro, arch, kernel version, tarball URL, and tarball SHA256. Updating the catalog means editing this file in the repo and rebuilding banger.

  2. Tarballs at https://kernels.thaloco.com/ — Cloudflare R2 bucket banger-kernels, fronted by a public custom domain. Each tarball is <name>-<arch>.tar.zst and contains vmlinux, optional initrd.img, and an optional modules/ tree at the archive root.

The banger kernel pull flow streams the tarball, verifies its SHA256 against the embedded catalog entry, decompresses it (zstd), extracts it into ~/.local/state/banger/kernels/<name>/, and writes a manifest. Path traversal entries and unsafe symlinks are rejected.

Kernel types

generic-<version> — built from upstream kernel.org sources with Firecracker's official config. All essential drivers (virtio_blk, virtio_net, ext4, vsock) compiled in — no modules, no initramfs. This is the kernel the golden image pairs with and the recommended kernel for OCI-pulled images. Build with scripts/make-generic-kernel.sh.

Adding or updating an entry

The repo has no CI for kernel publishing yet. Catalog updates are manual and infrequent (kernel version bumps every few weeks at most).

# 1. Build the kernel locally.
scripts/make-generic-kernel.sh

# 2. Import it into the local catalog so the canonical layout exists.
banger kernel import generic-6.12 \
  --from build/manual/generic-kernel \
  --distro generic \
  --arch x86_64

# 3. Package, upload, patch catalog.json.
scripts/publish-kernel.sh generic-6.12 \
  --description "Generic Firecracker kernel 6.12 (all drivers built-in, no initrd)"

# 4. Review and commit the catalog change.
git diff -- internal/kernelcat/catalog.json
git add internal/kernelcat/catalog.json
git commit -m 'kernel catalog: add/update generic-6.12'

# 5. Rebuild so the new catalog is embedded.
make build

scripts/publish-kernel.sh reads the locally-imported entry under ~/.local/state/banger/kernels/<name>/, builds a tar+zstd archive, uploads it to R2 via rclone, HEAD-checks the public URL, and patches internal/kernelcat/catalog.json with the new URL, SHA256, and size.

Environment overrides if the defaults need to change: RCLONE_REMOTE, RCLONE_BUCKET, BASE_URL, BANGER_KERNELS_DIR.

Removing an entry

  1. Delete the line from internal/kernelcat/catalog.json and commit.
  2. Delete the tarball from R2: rclone delete r2:banger-kernels/<name>-<arch>.tar.zst.
  3. Rebuild banger.

Already-pulled local copies on user machines are not invalidated — they keep working until the user runs banger kernel rm <name>. That's intentional: pulling is idempotent, removing should not break anyone in the middle of a workflow.

Versioning conventions

  • Entry names: <family>-<major.minor> (e.g. generic-6.12). The major.minor is the kernel line. Patch-level bumps reuse the entry name and replace the tarball; minor bumps create a new entry (generic-6.13).
  • Architecture: only x86_64 is published today. The arch field in the catalog schema is additive — adding arm64 later is a config change, not a schema change.
  • Tarball layout: contents at the archive root (no top-level versioned directory). vmlinux is required; initrd.img and modules/ are optional. Symlinks inside modules/ are allowed but must resolve within the archive.

Trust model

The embedded catalog.json carries the SHA256 of each tarball. banger kernel pull rejects any download whose hash doesn't match. This protects against transport corruption and against an attacker swapping a tarball on R2 without also pushing a banger release.

It does not protect against a compromise of the banger source repo itself — an attacker who can land a commit can change both the catalog SHA256 and the tarball. GPG/sigstore signing of the published catalog tarballs is deferred until banger is public and the threat model justifies the operational overhead.

Upstream kernel sources are verified: scripts/make-generic-kernel.sh fetches the detached PGP signature alongside the tarball from kernel.org and rejects the build if gpg can't verify it against one of the three known release signing keys (Greg KH / Linus / Sasha Levin). So a compromised kernel.org mirror can't slip a backdoored tarball past a maintainer rebuilding the kernel locally.

Hosting

Tarballs live in Cloudflare R2 (bucket banger-kernels), served at the custom domain kernels.thaloco.com. The bucket is publicly readable; writes require the banger-kernels-publish API token (kept locally, never committed). R2's free tier covers the expected traffic comfortably (zero egress fees, generous storage).

If hosting ever moves, catalog entries can be migrated by reuploading the tarballs and editing the URLs in catalog.json — no other code changes required.

Tech debt

  • Kernel publishing is manual; there is no CI yet. scripts/make-generic-kernel.sh plus scripts/publish-kernel.sh is fine while refreshes are infrequent and maintainer-only. CI becomes relevant once banger goes public.
  • make lint-shell runs at --severity=error only. Tightening to --severity=warning is a nice-to-have but low priority.