# release Version tags (`v*`) build albedo for Linux x86_64 as one AppImage and as deb, rpm and Arch packages, smoke-test each on a clean distro, and upload them with `SHA256SUMS` to `https://albedo-artifacts.fsn1.your-objectstorage.com/releases//` (`.tangled/workflows/release.yml`). A manual run builds and tests the current commit and uploads nothing. ## what is built `release/build.sh [version]` runs `release/inside.sh` in an Ubuntu 22.04 container (podman or docker) and writes `build/release//`. The version is semver without the `v`; the default is `git describe`. Downloads and the compiled OTP are cached in `~/.cache/albedo-release` (`ALBEDO_RELEASE_CACHE`). Everything is bundled except glibc (2.35 or newer: Ubuntu 22.04, Debian 12, current Fedora and Arch; not RHEL 9 or Debian 11). One tree serves every format: ``` bin/albedo the CLI (static, CGO_ENABLED=0) bin/rg ripgrep (musl, static) bin/albedo-daemon release/albedo-daemon: bundled tools first on PATH, then the shipment lib/albedo/ the sealed daemon shipment (gleam export erlang-shipment) erlang/ OTP 29, built from source: only the apps the daemon calls, no wx, termcap or other GUI apps, OpenSSL linked into crypto, libstdc++/libgcc linked into the emulator python/ python-build-standalone 3.11, without tests, Tk, IDLE, crypt web/ the web client (ALBEDO_WEB_DIST) ``` `inside.sh` refuses to package a tree in which any ELF needs a host library other than glibc (or one the tree ships); NixOS hosts have none of the usual ones, so a missing library shows there first. The shipment is sealed (`albedo_daemon:seal_build/1`, see runtime.md) after Python is compiled, since sealing hashes the finished tree. - **packages** install the tree to `/usr/lib/albedo` and `release/packages/albedo` to `/usr/bin/albedo`, which sets `ALBEDO_DAEMON` and `ALBEDO_WEB_DIST`. `bin/albedo-daemon` beside `lib/albedo/albedo` is the layout the CLI finds a build seal in, so packaged installs use standbys. nfpm builds all three from `release/packages/nfpm.yaml`; the maintainer field defaults to `nekomimi.pet `; `PACKAGE_MAINTAINER` overrides it. - **AppImage** is the tree plus `release/appimage/AppRun`, assembled by hand (mksquashfs, then the pinned type2 runtime prepended), never by running appimagetool: a host that registers AppImages with binfmt_misc (NixOS) routes every AppImage, inside containers too, to its own launcher. AppRun runs the CLI with `ALBEDO_DAEMON=$APPIMAGE` and `ALBEDO_APPIMAGE_DAEMON=1`, so the CLI starts the daemon by running the image again: the daemon holds its own mount and keeps its files after the CLI exits. `ALBEDO_BUILD` names the version, because the image path stays the same across upgrades; replace an image by rename, never in place, since a running daemon reads the old file. The AppImage has no seal path the CLI finds, so it boots cold. Its runtime cannot start under an open-file limit below about 1024. ## testing `release/smoke.sh ` installs the artifact on a clean container the way a user would, then checks that the CLI runs, that `albedo daemon` starts a daemon that outlives it and answers `albedo sessions`, and that `albedo daemon --stop` ends it. The e2e suite runs against an AppImage daemon through a wrapper given as `ALBEDO_TEST_DAEMON` (`ALBEDO_APPIMAGE_DAEMON=1 exec "$@"`); tests that require the compiled test snapshot's layout fail there by design. ## storage The bucket lives in a Hetzner project; keys of a project reach every bucket in it. The CI key lives in a separate project with no buckets, so it has no access until the bucket policy grants it: `s3:PutObject` under `releases/` only. The same policy makes `releases/` publicly readable and listable (`s3:ListBucket` with an `s3:prefix` condition, which Hetzner enforces): `?list-type=2&prefix=releases/&delimiter=/` names one prefix per release. The key reaches CI as the spindle secrets `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY`; `release/upload.sh` signs with `curl --aws-sigv4` (awscli misreads Hetzner's error bodies) and passes the key on stdin.