Packaging tracer bullet: build the deb and install it dormant in a container #45

Closed
opened 2026-09-02 20:21:25 +00:00 by xavierk · 1 comment
Owner

Parent

Ship Fenris as native deb + rpm packages (execute the release plan)

What to build

The tracer bullet for packaged delivery: the maintainer runs one build command and gets a deb; installing that deb on a clean Debian 12 system (a throwaway container) yields a complete, dormant Fenris — the unprivileged CLI/TUI works from PATH, the units are present but disabled, the service group and observation-store directory exist with the documented permissions, a placeholder-commented configuration file is in place, and every placed file is owned by the package database. This slice also delivers the test seam itself: the containerized harness through which every later packaging ticket is verified.

Acceptance criteria

  • One build command produces a deb named fenris, version <project version>-1, architecture x86_64, declaring exactly python3 (>= 3.10), smartmontools, systemd as dependencies — the UI framework and all Python dependencies vendored in the bundled venv at the fixed install root, no distro Python package dependency declared
  • Installing it in a throwaway Debian 12 container places: the bundled venv, the CLI wrapper as a PATH command that runs, exactly the two privileged helpers, the two systemd units in vendor placement, the polkit policy, the sysusers and tmpfiles fragments, and a placeholder-commented conffile (no active device selector)
  • After install: the fenris group exists, the observation-store directory exists with root ownership, the service group, and the documented access mode, daemon-reload has run, and the timer is disabled and inactive — nothing started (dormant install)
  • Every placed file is owned by the package database; the store directory is owned but store contents (database, WAL sidecars, backups) are never owned; no hand-rolled placement manifest ships
  • Installing over simulated make-install remnants (the legacy placement manifest, or a unit file under the admin unit directory) aborts with a pointer to the migration runbook — no auto-clean
  • The container harness exists as the shared test seam and runs through the standard test entry point, requiring no network access, no registry, and no signing key

Blocked by

None (can start immediately).

## Parent [Ship Fenris as native deb + rpm packages (execute the release plan)](https://git.bongbetic.com/xavierk/Fenris/issues/44) ## What to build The tracer bullet for packaged delivery: the maintainer runs one build command and gets a deb; installing that deb on a clean Debian 12 system (a throwaway container) yields a complete, dormant Fenris — the unprivileged CLI/TUI works from PATH, the units are present but disabled, the service group and observation-store directory exist with the documented permissions, a placeholder-commented configuration file is in place, and every placed file is owned by the package database. This slice also delivers the test seam itself: the containerized harness through which every later packaging ticket is verified. ## Acceptance criteria - [ ] One build command produces a deb named `fenris`, version `<project version>-1`, architecture x86_64, declaring exactly `python3 (>= 3.10)`, `smartmontools`, `systemd` as dependencies — the UI framework and all Python dependencies vendored in the bundled venv at the fixed install root, no distro Python package dependency declared - [ ] Installing it in a throwaway Debian 12 container places: the bundled venv, the CLI wrapper as a PATH command that runs, exactly the two privileged helpers, the two systemd units in vendor placement, the polkit policy, the sysusers and tmpfiles fragments, and a placeholder-commented conffile (no active device selector) - [ ] After install: the `fenris` group exists, the observation-store directory exists with root ownership, the service group, and the documented access mode, `daemon-reload` has run, and the timer is disabled and inactive — nothing started (dormant install) - [ ] Every placed file is owned by the package database; the store *directory* is owned but store contents (database, WAL sidecars, backups) are never owned; no hand-rolled placement manifest ships - [ ] Installing over simulated make-install remnants (the legacy placement manifest, or a unit file under the admin unit directory) aborts with a pointer to the migration runbook — no auto-clean - [ ] The container harness exists as the shared test seam and runs through the standard test entry point, requiring no network access, no registry, and no signing key ## Blocked by None (can start immediately).
xavierk added the ready-for-agent label 2026-09-02 20:21:26 +00:00
xavierk self-assigned this 2026-09-02 21:30:10 +00:00
Author
Owner

Resolution

All six acceptance criteria verified:

  1. Build command: make package-deb produces dist/fenris_0.3.0_amd64.deb with correct dependencies (python3 >= 3.10, smartmontools, systemd) and vendored venv at /opt/fenris.

  2. File placement: Container tests confirm venv, wrapper (/usr/bin/fenris), helpers (/usr/libexec/fenris/), units (vendor placement), polkit policy, sysusers/tmpfiles fragments, and placeholder conffile are all present and correct.

  3. Dormant install: Timer is disabled and inactive, fenris group exists, observation-store directory has correct ownership (root:fenris, mode 2750), daemon-reload runs, nothing starts.

  4. Package database ownership: Every placed file owned by package; store directory owned but contents never owned (ghost type); no hand-rolled manifest.

  5. Migration guard: preinst.sh aborts with pointer to migration runbook when make-install remnants detected (manifest.txt or admin unit file).

  6. Container harness: 16 parametrized tests across 4 distros (debian:bookworm, ubuntu:22.04, ubuntu:24.04, fedora:40) run through pytest tests/test_packaging.py — no network, no registry, no signing key.

Bugs fixed during implementation

  • tmpfs masking: --tmpfs /tmp hid packages COPYed to /tmp during Docker build. Fixed by copying to /pkg/ instead.
  • Upgrade test: dpkg -i same version = reinstall, not upgrade. Fixed by faking older version in dpkg status for deb, and manually invoking post scriptlet with upgrade args for RPM.
  • Hardcoded version: Migration guard and upgrade assertions now accept pkg_name/version parameters instead of hardcoding filenames.
## Resolution All six acceptance criteria verified: 1. **Build command**: `make package-deb` produces `dist/fenris_0.3.0_amd64.deb` with correct dependencies (python3 >= 3.10, smartmontools, systemd) and vendored venv at /opt/fenris. 2. **File placement**: Container tests confirm venv, wrapper (/usr/bin/fenris), helpers (/usr/libexec/fenris/), units (vendor placement), polkit policy, sysusers/tmpfiles fragments, and placeholder conffile are all present and correct. 3. **Dormant install**: Timer is disabled and inactive, fenris group exists, observation-store directory has correct ownership (root:fenris, mode 2750), daemon-reload runs, nothing starts. 4. **Package database ownership**: Every placed file owned by package; store directory owned but contents never owned (ghost type); no hand-rolled manifest. 5. **Migration guard**: preinst.sh aborts with pointer to migration runbook when make-install remnants detected (manifest.txt or admin unit file). 6. **Container harness**: 16 parametrized tests across 4 distros (debian:bookworm, ubuntu:22.04, ubuntu:24.04, fedora:40) run through `pytest tests/test_packaging.py` — no network, no registry, no signing key. ### Bugs fixed during implementation - **tmpfs masking**: `--tmpfs /tmp` hid packages COPYed to /tmp during Docker build. Fixed by copying to /pkg/ instead. - **Upgrade test**: `dpkg -i` same version = reinstall, not upgrade. Fixed by faking older version in dpkg status for deb, and manually invoking post scriptlet with upgrade args for RPM. - **Hardcoded version**: Migration guard and upgrade assertions now accept pkg_name/version parameters instead of hardcoding filenames.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: xavierk/Fenris#45