Skip to content

repo.yaml Is Intent; catalog.json Is Evidence

Why Barn separates human-authored image policy from generated metadata that must match the actual qcow2 artifacts.

This essay explains the Linux image repository contract in Barn 1.1.0 (macOS guests manage Apple .ipsw restore images and APFS base images separately via barn mac).

A static VM image repository needs two kinds of metadata: human policy decisions (which version is :stable, which old releases are deprecated, what aliases map to each family) and physical file facts (exact byte size, SHA-256 digest, qcow2 virtual disk size). Maintaining both in a single hand-edited JSON file invites copy-paste checksum errors and buries policy changes inside noisy diffs.

Barn splits those two concerns into two distinct files: repo.yaml for human intent and catalog.json for machine-verified evidence.

repo.yaml: human-authored policy

repo.yaml (schema: 1) is checked into version control and edited by maintainers. It declares:

  • Repository revision and global defaults (image, channel, arch, boot)
  • Distribution families and their short aliases
  • Movable release channels such as stable
  • Exact version keys and supported architectures (amd64, arm64)
  • Boot mode (uefi or bios), support status, source_user, and immutable upstream provenance URLs

Crucially, repo.yaml never contains hand-copied byte counts, SHA-256 digests, or virtual disk sizes:

repo.yaml
defaults: { image: d13, channel: stable, arch: native, boot: uefi }
images:
  d13:
    aliases: [debian13, debian, trixie]
    channels: { stable: "20260810.2566.0" }
    versions:
      "20260810.2566.0":
        status: supported
        variants:
          amd64: {}
          arm64: {}

Because repo.yaml stays compact and free of generated hashes, pull requests clearly show channel promotions, deprecations, and provenance updates (see Image Repositories for a complete walkthrough and Linux Images for the current 2026110502 catalog).

Note

Repository authoring and client verification are covered in Linux Images; offline candidate normalization is covered in Image Pipeline.

catalog.json: machine-verified artifact evidence

catalog.json (schema: 3) is generated by barn repo build from repo.yaml and the actual .qcow2 files on disk. For every (image, version, arch) variant, barn repo build:

  1. Validates repo.yaml policy declarations (boot mode, source_user, support status, and upstream provenance).
  2. Inspects the corresponding images/<image>-<version>-<arch>.qcow2 file via qemu-img, rejecting backing chains, external data files, encryption, or unknown incompatible qcow2 feature bits.
  3. Computes the exact file size, SHA-256 digest, and qcow2 virtual capacity, and atomically writes catalog.json.

Each artifact is identified by the immutable tuple (image, exact version, architecture) and stored under a human-readable filename:

images/d13-20260810.2566.0-arm64.qcow2

Predictable filenames make it easy to inspect, mirror, or rsync a repository with standard Unix tools, while catalog.json and its minisign signature provide cryptographic integrity verification.

Three repository commands, three distinct roles

Command Role
barn repo scan /srv/barn Read-only audit: reports tracked, missing, untracked, and unsafe files without modifying the repository
barn repo build /srv/barn Strictly validates repo.yaml and every declared .qcow2 file, then atomically writes catalog.json
barn repo verify /srv/barn Rebuilds the catalog in memory and verifies that it matches the published catalog.json byte-for-byte

barn repo build never modifies repo.yaml or .qcow2 files, and barn repo verify catches any drift between repo.yaml, the .qcow2 files on disk, and catalog.json. When publishing a repository update, always upload the immutable .qcow2 files first, then publish catalog.json and catalog.json.minisig together so clients never see a catalog entry whose image file is not yet available.

Movable selectors, immutable resolved identities

In barn.yml or CLI commands, selectors like d13:stable, el9@9, and el9@9.8 provide convenient moving targets (comparing dot-separated version components as integers so 9.10 sorts after 9.9).

Once barn plan or barn up resolves a selector for a node, Barn records the exact version, architecture, byte size, and SHA-256 digest in committed state. Updating a channel in a future catalog never mutates an already created VM behind your back.

Transport security and catalog signatures

Barn separates transport selection from catalog trust:

  • Official and HTTP repositories always require a valid detached signature (catalog.json.minisig) verified by one of Barn’s embedded production Ed25519 public keys.
  • Custom local directory and HTTPS repositories explicitly selected via --repo or BARN_REPO may use unsigned catalogs when you control the local filesystem or HTTPS endpoint.
  • Per-repository anti-rollback: Barn tracks the highest accepted catalog revision independently for each repository root, rejecting older revisions (unless --allow-downgrade is passed to barn image sync) and rejecting different catalog bytes at the same revision number.
  • Defense in depth on every pull: Even after a catalog is accepted, every downloaded or cached image is checked against its catalog byte size, SHA-256 digest, and qcow2 structural rules before being marked read-only (0444) and used as a backing image for copy-on-write node overlays.

Independent trust domains across releases, apps, and catalogs

Barn keeps its three distribution trust domains distinct:

  1. CLI release archives and Linux packages are published on GitHub Releases with checksums.txt SHA-256 manifests and SPDX SBOMs.
  2. Native macOS Barn.app bundles use Apple Developer ID code signing and notarization (or local ad-hoc signing when built from source).
  3. Linux image catalogs are authenticated via offline Ed25519 Minisign keys (catalog.json.minisig).

In Barn 1.1.0, the compiled default repository is https://repo.pigsty.io/barn, --mirror selects https://repo.pigsty.cc/barn, and --repo selects any custom root. The two official mirrors can fall back to each other when downloading .qcow2 artifacts—always verifying the exact same catalog byte size and SHA-256 digest—while catalog updates (barn update) and custom --repo repositories always read from their explicitly selected source.

Table reader