OpenBSD ports overlay and build automation
  • Shell 35.4%
  • BitBake 20.7%
  • Ruby 20.3%
  • Makefile 18.2%
  • Python 5.4%
Find a file
2026-06-07 21:38:34 +01:00
.mise/tasks feat: add ports update-check task 2026-06-07 21:38:34 +01:00
ports feat: add ports update-check task 2026-06-07 21:38:34 +01:00
vm port: zoxide 0.9.9 2026-06-07 17:06:27 +01:00
.gitignore feat: openbsd ports build vm + overlay scaffold 2026-06-06 03:06:35 +01:00
mise.toml feat: openbsd ports build vm + overlay scaffold 2026-06-06 03:06:35 +01:00
README.md feat: add ports update-check task 2026-06-07 21:38:34 +01:00

ports

Local OpenBSD ports overlay + a throwaway build VM that turns them into installable .tgz packages. Runs on the dev box.

OpenBSD packages must be built on matching version+arch and can't be built on Linux, so a qemu VM running OpenBSD does the building. The VM is autoinstalled from scratch (rebuildable artifact, never committed).

Layout

ports/<cat>/<port>/   overlay tree; mounts to /usr/ports/mystuff/<cat>/<port> in the VM
vm/                   autoinstall inputs (committed) + image/cache (gitignored)
  install.conf        autoinstall response file
  disklabel           partition template (big /usr + /usr/obj)
  install.site        provisions the builder (pkg_add, ports tree, user.list)
  boot.conf           serial + boot bsd.rd
  feed-console.py     answers the one prompt autoinstall can't reach (see Notes)
  keys/openbsd-NN-base.pub   signify pubkey for verifying sets (committed)
dist/                 built .tgz output (gitignored)
.mise/tasks/          vm:{fetch,create,up,ssh,down}, build

Host prereqs (portage — not mise-providable)

app-emulation/qemu  net-misc/socat  app-crypt/signify

KVM: load kvm-intel/kvm-amd, add yourself to the kvm group, relogin.

Workflow

# one-time per OpenBSD release:
scp <obsd-host>:/etc/signify/openbsd-79-base.pub vm/keys/   # trust anchor for sets
mise run vm:fetch          # download + signify-verify the install sets
mise run vm:create         # autoinstall -> vm/openbsd.qcow2 (build-ready, hands-off)

# per package:
mise run build www/forgejo # boot VM, rsync port in, make package, -> dist/forgejo-*.tgz

mise run vm:{up,ssh,down}   # operate the VM directly

Install the result on the target box (locally-built, unsigned, so skip the signature check and give a path, not a bare name):

doas pkg_add -D unsigned ./forgejo-*.tgz

Publishing to a private mirror (a Forgejo release) is a separate step, TBD.

Updating ports

Check every port against its upstream's latest release (dev box, no VM):

mise run check                 # all ports; exits non-zero if any OUTDATED
mise run check sysutils/zoxide # one port

It reports ok / OUTDATED current -> latest / ERROR. Upstream source per port: GitHub ports resolve automatically from GH_ACCOUNT/GH_PROJECT; non-GitHub ports declare a directive comment in their Makefile:

# UPDATE: gitea https://codeberg.org forgejo/forgejo   # Forgejo/Gitea (Codeberg)
# UPDATE: github <owner>/<repo>                          # override, if needed

(Set GH_TOKEN/GITHUB_TOKEN to avoid GitHub's unauthenticated rate limit.)

To bump an outdated port:

  1. Edit the version in its Makefile — GH_TAGNAME (GitHub ports) or VERSION.
  2. Regenerate in the VM per the port's BUILDING.md (make makesum; Rust ports also make modcargo-gen-crates + any source-restore quirks; then make update-plist). Pull the regenerated crates.inc/distinfo/pkg/PLIST back into the repo.
  3. mise run build <cat>/<port> -> new dist/*.tgz.
  4. Install on the target with doas pkg_add -D unsigned ./<pkg>.tgz.

Notes — how the VM build is wired, and the OpenBSD-isms behind it

  • The response-file prompt. qemu user-net (slirp) serves DHCP/TFTP on the gateway 10.0.2.2, and autoinstall fetches install.conf from there — but qemu won't let a guestfwd http server bind the gateway, so our http lives at 10.0.2.1 instead. autoinstall can't find the file at .2, drops to Response file location?, and feed-console.py (watching the serial socket) types the .1 URL. Everything else (sets, disklabel, site) is served from .1.
  • Disklabel. The OpenBSD default carves a ~2.7G /usr, too small for the ports tree + build cache. vm/disklabel gives /usr and /usr/obj the bulk; install.site sets WRKOBJDIR=/usr/obj so Go's build cache stays off /usr.
  • X sets are mandatory. bsd.port.mk refuses to build any port without the X sets installed ("requires correctly installed X11"), even headless ones like forgejo — so install.conf keeps x* and only drops game*.
  • builder user. The build/ssh user is builder, not buildbuild is in the installer's reserved-loginname list and is silently rejected.
  • rsync--. pkg_add rsync is ambiguous (minimal vs full flavor); the build task needs rsync in the VM, so install.site pins rsync-- (the full flavor).
  • Unsigned site set. site79.tgz isn't in the release SHA256.sig, so the installer prompts twice (Checksum test for ... Continue anyway? and Continue without verification?); both are answered yes in install.conf.