Fenris deb + rpm release plan #33

Closed
opened 2026-09-02 18:31:17 +00:00 by xavierk · 0 comments
Owner

Destination

A decision-complete release spec for shipping Fenris as native deb + rpm packages — distribution channel, signing, compatibility matrix, packaging toolchain, CI, and package-manager upgrade semantics — recorded as a spec doc plus an ADR amending ADR 0004 delivery. No packages get built on this map.

Notes

Domain: Fenris NVMe endurance monitor (Python, single runtime dep textual>=0.40, systemd timer + polkit + /var/lib/fenris observation store). Charting-session decisions already locked:

  • Destination = decision spec + ADRs; execution is a separate follow-up effort.
  • Dependency strategy = bundled venv inside both packages (distro python3-textual too old across the matrix).
  • Packages become primary delivery; make install demoted to dev fallback. ADR 0004 amended on delivery/ownership only; runtime semantics (dormant install, polkit-only elevation, DB snapshot + forward-only migration) inherited verbatim in maintainer scripts.
  • Candidate channel = Gitea Debian/RPM package registry (instance runs 1.27.1); OBS evaluated as alternative route; dedicated GPG packaging key; packages signed.
  • Compat matrix candidates: Debian 12, Ubuntu 22.04/24.04, Fedora 40+; x86_64 only; Python floor bumped to 3.10 (oldest supported distro interpreter).

Skills: grilling tickets load "grilling" + "domain-modeling" skills; research tickets use the "research" skill.

Decisions so far

  • Research: deb + rpm packaging toolchain for bundled-venv builds: nfpm wins — one nfpm.yaml (contents type: tree/config|noreplace/ghost + overrides:) builds deb+rpm from staged --copies venv at /opt/fenris; fpm active fallback but CLI-flag config drifts; dh-virtualenv deb-only + dormant since 1.2.2 (2020); hand rpm spec = duplicated file list. Debian 12 + Ubuntu 22.04/24.04 all ship textual 0.1.13 → vendoring confirmed (Fedora 40+ ships ≥0.48 but below pin 8.2.8). Findings: docs/research/deb-rpm-toolchain.md @ branch research/toolchain cca27d0, issue #34 commented + closed.

  • Research: Gitea 1.27 Debian + RPM package registry feasibility: Feasible — Gitea 1.27.1 at git.bongbetic.com serves deb+rpm natively: PUT …/debian/pool/{dist}/{component}/upload + …/rpm/{group}/upload (dups 409), apt via signed-by keyring + deb …/debian {dist} main, dnf via auto-generated .repo (gpgcheck=1); metadata signed by instance auto-PGP keys (InRelease + repomd.xml.asc, both gpg-verified); free-form multi-distro (tested bookworm+noble, el9 group); versions kept forever (cleanup rules web-UI only, no REST); no package↔release linkage — findings on branch research/gitea-registry in docs/research/gitea-package-registry.md, issue #35 commented + closed, test packages deleted.

  • Research: OBS as alternative build + distribution route: Reject OBS — offline sandbox forces same vendoring as Gitea route (textual 0.1.13 everywhere), signing is OBS's key not ours, extra account + shared-queue latency for reach we don't need; ship deb+rpm via self-hosted Gitea 1.27.1 registry (branch research/obs, docs/research/obs-route.md, commit 8bcb1fe, issue #36 closed, not pushed).

  • Task: Check Gitea Actions runner availability on git.bongbetic.com: Actions enabled repo+instance (has_actions:true, admin runners API 200) but zero runners registered → CI unusable, manual build fallback per #33; cheapest fix = single act_runner static binary in host-label mode on existing Gitea host.

  • Grilling: Lock channel + toolchain: Gitea 1.27.1 registry, single channel, OBS off the route; nfpm for both formats via one packaging/nfpm.yaml (version from pyproject.toml, file lists from staged --copies venv, entry make package); one deb → codename pools bookworm/jammy/noble, one rpm → group fenris; version <pyproject-version>-1, revision bump on rebuild; promotion = tag → make release (manual build + PUT + attach .deb/.rpm/SHA256SUMS) + dormant v*-triggered .gitea/workflows/release.yml.

  • Grilling: Signing + key policy: rpm payload signed with dedicated RSA-3072 key (single key, no subkeys; private key in password manager, import→sign→delete each release); .deb unsigned (apt trusts instance-signed InRelease); clearsigned SHA256SUMS; Fenris-owned packaging/fenris.repo + in-repo key (Gitea-served .repo is a gpgcheck trap — never in docs); instance-key fingerprint pinned in install docs; rotation = dual-key window, one release cycle.

  • Grilling: Package ownership + ADR 0004 amendment: units to /usr/lib/systemd/system (postinst daemon-reload only — dormant parity, no preset); sysusers.d + tmpfiles.d fragments with package owning /var/lib/fenris dir only (store never ghosted); /etc/fenris/fenris.conf ships as noreplace conffile (placeholder default); wrapper /usr/bin/fenris; deb remove/purge + rpm erase mapping with prerm sanctioned-disable guarded against upgrade; postinst inherits snapshot + inline-python forward-only migration (no new polkit binaries); no auto legacy import from packages. ADR 0004 amendment outline in issue.

  • Grilling: Migration path from make-install systems to packages: runbook-only remove-then-install (over-install forbidden — stale /etc units + /usr/local wrapper shadow package files); preinst/%pre aborts on make-install remnants (manifest.txt OR /etc/systemd/system/fenris-collect.timer), no auto-clean; no-move store/config continuity (group/sysusers + dir/tmpfiles no-ops, user fenris.conf survives as .dpkg-new/.rpmnew); reset-to-dormant, user runs fenris monitor resume; package + make install mutually exclusive per machine.

  • Grilling: Release cadence + stable/testing channel split: No split — single channel, split deferred until real users demand it (testing dist = permanent clutter: registry retains all versions forever, no cleanup API); on-demand releases (tag when user-visible changes/fixes accumulate, no calendar, no empty releases); plain semver (major = breaking CLI/config/unit, schema changes ride natural bump); downgrade unsupported — rollback = restore store snapshot + install old release, documented not built; fix-forward via revision bump, no RC ceremony; release = tag + registry upload + Gitea release entry with notes + SHA256SUMS, bare tags forbidden; no frequency SLA. CONTEXT.md gained Release + Rollback terms.

  • Task: Compose release spec + ADR amending 0004: docs/spec/release-packaging.md (decision-complete: compat matrix, channel, nfpm toolchain, signing, release mechanics, layout/ownership, maintainer scripts, migration runbook) + ADR 0007 amending 0004 on delivery/ownership; research docs merged to docs/research/; #40 open item resolved (device selector hand-edited, no new verb). Branch task/release-spec-adr, commit b005049 — map decision-complete.

Not yet specified

  • Dev-local make install mode (checkout venv + user-level units) for dev machines that also carry packages — deferred; only graduates if the mutual-exclusion rule bites in practice.

  • Stable/testing channel split — deferred until real users demand it; revisit criterion = external users asking to track pre-release builds.

  • COPR/PPA fallback if the chosen channel proves limiting.

  • GPG key rotation procedure details.

  • Instance auto-key lifecycle: what happens to apt clients (and our pinned fingerprint docs) if the Gitea instance is migrated/reinstalled and its metadata signing key regenerates? Revisit if/when instance migration is planned.

  • arm64 builds, only if real ARM hardware appears.

Out of scope

  • Snap, Flatpak, AppImage, Homebrew packaging (sandbox hostile to polkit + systemd timer + smartctl raw device access).
  • PyPI as an install path (wheel stays a build/dev artifact).
  • Building and publishing actual packages — execution follows this map as a fresh effort.
## Destination A decision-complete release spec for shipping Fenris as native deb + rpm packages — distribution channel, signing, compatibility matrix, packaging toolchain, CI, and package-manager upgrade semantics — recorded as a spec doc plus an ADR amending [ADR 0004](https://git.bongbetic.com/xavierk/Fenris/src/branch/main/docs/adr/0004-install-upgrade-removal-lifecycle.md) delivery. No packages get built on this map. ## Notes Domain: Fenris NVMe endurance monitor (Python, single runtime dep `textual>=0.40`, systemd timer + polkit + `/var/lib/fenris` observation store). Charting-session decisions already locked: - Destination = decision spec + ADRs; execution is a separate follow-up effort. - Dependency strategy = bundled venv inside both packages (distro `python3-textual` too old across the matrix). - Packages become primary delivery; `make install` demoted to dev fallback. ADR 0004 amended on delivery/ownership only; runtime semantics (dormant install, polkit-only elevation, DB snapshot + forward-only migration) inherited verbatim in maintainer scripts. - Candidate channel = Gitea Debian/RPM package registry (instance runs 1.27.1); OBS evaluated as alternative route; dedicated GPG packaging key; packages signed. - Compat matrix candidates: Debian 12, Ubuntu 22.04/24.04, Fedora 40+; x86_64 only; Python floor bumped to 3.10 (oldest supported distro interpreter). Skills: grilling tickets load "grilling" + "domain-modeling" skills; research tickets use the "research" skill. ## Decisions so far - [Research: deb + rpm packaging toolchain for bundled-venv builds](https://git.bongbetic.com/xavierk/Fenris/issues/34): nfpm wins — one `nfpm.yaml` (contents `type: tree/config|noreplace/ghost` + `overrides:`) builds deb+rpm from staged `--copies` venv at /opt/fenris; fpm active fallback but CLI-flag config drifts; dh-virtualenv deb-only + dormant since 1.2.2 (2020); hand rpm spec = duplicated file list. Debian 12 + Ubuntu 22.04/24.04 all ship textual 0.1.13 → vendoring confirmed (Fedora 40+ ships ≥0.48 but below pin 8.2.8). Findings: `docs/research/deb-rpm-toolchain.md` @ branch `research/toolchain` cca27d0, issue #34 commented + closed. - [Research: Gitea 1.27 Debian + RPM package registry feasibility](https://git.bongbetic.com/xavierk/Fenris/issues/35): Feasible — Gitea 1.27.1 at git.bongbetic.com serves deb+rpm natively: PUT `…/debian/pool/{dist}/{component}/upload` + `…/rpm/{group}/upload` (dups 409), apt via signed-by keyring + `deb …/debian {dist} main`, dnf via auto-generated `.repo` (gpgcheck=1); metadata signed by instance auto-PGP keys (InRelease + repomd.xml.asc, both gpg-verified); free-form multi-distro (tested bookworm+noble, el9 group); versions kept forever (cleanup rules web-UI only, no REST); no package↔release linkage — findings on branch `research/gitea-registry` in `docs/research/gitea-package-registry.md`, issue #35 commented + closed, test packages deleted. - [Research: OBS as alternative build + distribution route](https://git.bongbetic.com/xavierk/Fenris/issues/36): Reject OBS — offline sandbox forces same vendoring as Gitea route (textual 0.1.13 everywhere), signing is OBS's key not ours, extra account + shared-queue latency for reach we don't need; ship deb+rpm via self-hosted Gitea 1.27.1 registry (branch `research/obs`, `docs/research/obs-route.md`, commit 8bcb1fe, issue #36 closed, not pushed). - [Task: Check Gitea Actions runner availability on git.bongbetic.com](https://git.bongbetic.com/xavierk/Fenris/issues/37): Actions enabled repo+instance (`has_actions:true`, admin runners API 200) but zero runners registered → CI unusable, manual build fallback per #33; cheapest fix = single `act_runner` static binary in host-label mode on existing Gitea host. - [Grilling: Lock channel + toolchain](https://git.bongbetic.com/xavierk/Fenris/issues/38): Gitea 1.27.1 registry, single channel, OBS off the route; nfpm for both formats via one `packaging/nfpm.yaml` (version from `pyproject.toml`, file lists from staged `--copies` venv, entry `make package`); one deb → codename pools `bookworm`/`jammy`/`noble`, one rpm → group `fenris`; version `<pyproject-version>-1`, revision bump on rebuild; promotion = tag → `make release` (manual build + PUT + attach `.deb`/`.rpm`/`SHA256SUMS`) + dormant `v*`-triggered `.gitea/workflows/release.yml`. - [Grilling: Signing + key policy](https://git.bongbetic.com/xavierk/Fenris/issues/39): rpm payload signed with dedicated RSA-3072 key (single key, no subkeys; private key in password manager, import→sign→delete each release); .deb unsigned (apt trusts instance-signed InRelease); clearsigned SHA256SUMS; Fenris-owned `packaging/fenris.repo` + in-repo key (Gitea-served `.repo` is a gpgcheck trap — never in docs); instance-key fingerprint pinned in install docs; rotation = dual-key window, one release cycle. - [Grilling: Package ownership + ADR 0004 amendment](https://git.bongbetic.com/xavierk/Fenris/issues/40): units to /usr/lib/systemd/system (postinst daemon-reload only — dormant parity, no preset); sysusers.d + tmpfiles.d fragments with package owning /var/lib/fenris dir only (store never ghosted); /etc/fenris/fenris.conf ships as noreplace conffile (placeholder default); wrapper /usr/bin/fenris; deb remove/purge + rpm erase mapping with prerm sanctioned-disable guarded against upgrade; postinst inherits snapshot + inline-python forward-only migration (no new polkit binaries); no auto legacy import from packages. ADR 0004 amendment outline in issue. - [Grilling: Migration path from make-install systems to packages](https://git.bongbetic.com/xavierk/Fenris/issues/41): runbook-only remove-then-install (over-install forbidden — stale /etc units + /usr/local wrapper shadow package files); preinst/%pre aborts on make-install remnants (manifest.txt OR /etc/systemd/system/fenris-collect.timer), no auto-clean; no-move store/config continuity (group/sysusers + dir/tmpfiles no-ops, user fenris.conf survives as .dpkg-new/.rpmnew); reset-to-dormant, user runs fenris monitor resume; package + make install mutually exclusive per machine. - [Grilling: Release cadence + stable/testing channel split](https://git.bongbetic.com/xavierk/Fenris/issues/43): No split — single channel, split deferred until real users demand it (testing dist = permanent clutter: registry retains all versions forever, no cleanup API); on-demand releases (tag when user-visible changes/fixes accumulate, no calendar, no empty releases); plain semver (major = breaking CLI/config/unit, schema changes ride natural bump); downgrade unsupported — rollback = restore store snapshot + install old release, documented not built; fix-forward via revision bump, no RC ceremony; release = tag + registry upload + Gitea release entry with notes + SHA256SUMS, bare tags forbidden; no frequency SLA. CONTEXT.md gained Release + Rollback terms. - [Task: Compose release spec + ADR amending 0004](https://git.bongbetic.com/xavierk/Fenris/issues/42): `docs/spec/release-packaging.md` (decision-complete: compat matrix, channel, nfpm toolchain, signing, release mechanics, layout/ownership, maintainer scripts, migration runbook) + ADR 0007 amending 0004 on delivery/ownership; research docs merged to `docs/research/`; #40 open item resolved (device selector hand-edited, no new verb). Branch `task/release-spec-adr`, commit b005049 — map decision-complete. ## Not yet specified - Dev-local make install mode (checkout venv + user-level units) for dev machines that also carry packages — deferred; only graduates if the mutual-exclusion rule bites in practice. - Stable/testing channel split — deferred until real users demand it; revisit criterion = external users asking to track pre-release builds. - COPR/PPA fallback if the chosen channel proves limiting. - GPG key rotation procedure details. - Instance auto-key lifecycle: what happens to apt clients (and our pinned fingerprint docs) if the Gitea instance is migrated/reinstalled and its metadata signing key regenerates? Revisit if/when instance migration is planned. - arm64 builds, only if real ARM hardware appears. ## Out of scope - Snap, Flatpak, AppImage, Homebrew packaging (sandbox hostile to polkit + systemd timer + smartctl raw device access). - PyPI as an install path (wheel stays a build/dev artifact). - Building and publishing actual packages — execution follows this map as a fresh effort.
xavierk added this to the Wayfinder: Fenris deb + rpm release plan milestone 2026-09-02 18:31:17 +00:00
xavierk added the wayfinder:map label 2026-09-02 18:31:17 +00:00
xavierk self-assigned this 2026-09-02 18:31:18 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: xavierk/Fenris#33