signing: rpm payload signing, key publication, consumer repo setup for #51

Implement the signing and consumer-repo trust infrastructure:

- Makefile: add generate-test-key, sign-rpm, checksums, clearsign targets;
  make release now automates the full build→sign→checksum→clearsign flow
- Key ceremony: document the import→sign→delete lifecycle, key rotation
  outline, and private-key-in-password-manager policy
- Public key: update placeholder with raw URL, algorithm, and ceremony ref
- Consumer docs: README now covers apt signed-by keyring flow, dnf repo
  file setup, signature verification commands, and migration runbook link
- Release spec: updated to reference ceremony doc and rpmsign workflow
- Tests: 36 structural signing tests (nfpm config, Makefile targets,
  repo file, key publication, ceremony doc, consumer docs, spec refs)
  plus throwaway-key RPM signature and clearsign mechanics; no network
  or real key required

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
xavierk
2026-09-03 14:14:55 +05:30
co-authored by CommandCodeBot
parent c45b07003a
commit d8fa6df072
6 changed files with 809 additions and 48 deletions
+115 -22
View File
@@ -8,34 +8,109 @@ Fenris is a persistent TUI monitor backed by a short-lived privileged collector
## Requirements
- **Python ≥ 3.9** (verified at install time)
- **Python ≥ 3.9** (verified at install time; ≥ 3.10 for packages)
- **smartmontools** (`smartctl` — verified at install time)
- **systemd** with a polkit agent (the collector runs as root oneshot; elevation is exclusively polkit)
No other OS packages or Python dependencies beyond [Textual](https://textual.textualize.io/) (pinned in the lockfile).
## Install
## Install from package (recommended)
```bash
sudo make install
### Debian / Ubuntu (apt)
The Gitea instance Debian registry signs metadata with its own key. Verify the
instance key fingerprint (TOFU hardening):
```text
Fingerprint: <print after first release — paste beside the curl one-liner>
```
What it does:
1. Builds a wheel from the checkout and installs it — with pinned dependencies — into the dedicated venv at `/opt/fenris`.
2. Places the `fenris` wrapper in `/usr/local/bin`, helpers in `/usr/libexec/fenris`, systemd units in `/etc/systemd/system`, and the polkit policy in `/usr/share/polkit-1/actions/`.
3. Creates `/var/lib/fenris` (root-written, group-readable) — the observation store is created lazily by the first collection run.
4. Records every placed file in a manifest consumed by upgrade and uninstall.
5. Detects `./data/history.jsonl` beside the source checkout and runs the idempotent legacy import if present.
Add the instance key and repository:
**A fresh install is fully dormant.** Units are present but disabled; nothing runs. The only opt-in is the sanctioned toggle:
```bash
sudo mkdir -p /etc/apt/keyrings
sudo curl -fsSL -o /etc/apt/keyrings/gitea-xavierk.asc \
https://git.bongbetic.com/api/packages/xavierk/debian/repository.key
echo "deb [signed-by=/etc/apt/keyrings/gitea-xavierk.asc] \
https://git.bongbetic.com/api/packages/xavierk/debian bookworm main" \
| sudo tee /etc/apt/sources.list.d/fenris.list
sudo apt update && sudo apt install fenris
```
Replace `bookworm` with your distribution codename (`bookworm`, `jammy`, or
`noble`).
### Fedora (dnf)
Use the Fenris-owned repo file (not Gitea's auto-generated one):
```bash
sudo dnf config-manager --add-repo \
https://git.bongbetic.com/xavierk/Fenris/raw/branch/main/packaging/fenris.repo
sudo dnf install fenris
```
The repo file sets `gpgcheck=1` against the Fenris packaging key (downloaded
from the raw URL in `gpgkey`) and `repo_gpgcheck=0` (metadata check left to
TLS).
### Package signature verification
The RPM payload is signed with the Fenris packaging key (RSA 3072).
Verification happens automatically via dnf's `gpgcheck=1`. For manual
verification of downloaded assets:
```bash
rpm -Kv fenris-*.x86_64.rpm # RPM payload signature
gpg --verify SHA256SUMS.asc SHA256SUMS # Clearsigned checksum manifest
sha256sum -c SHA256SUMS # Checksum match
```
The packaging public key is published in-repo — no keyservers. See
`packaging/keys/fenris-packaging.asc` and
`docs/install/signing-key-ceremony.md` for key lifecycle details.
### Dormant install
A fresh package install is fully dormant. Units are present but disabled;
nothing runs. The only opt-in is the sanctioned toggle:
```bash
fenris monitor resume # enable timer + open first monitoring period
fenris monitor pause # close the period, disable timer
```
## Development install (make install)
For contributors building from source:
```bash
sudo make install
```
This builds a wheel, installs it into `/opt/fenris` with pinned dependencies,
and places helpers, units, and the polkit policy. Units are dormant by default.
```bash
sudo make upgrade # re-sync wheel, units, schema
make uninstall # removes artifacts, preserves config and store
make purge # also removes /etc/fenris and /var/lib/fenris
```
## Upgrade
### Package upgrade
```bash
sudo apt update && sudo apt upgrade fenris # Debian/Ubuntu
sudo dnf upgrade fenris # Fedora
```
### Development upgrade
```bash
sudo make upgrade
```
@@ -49,8 +124,26 @@ What it does:
Rollback: reinstall the previous version and restore `observations.db.bak`.
## Migration from make install
If Fenris was previously installed with `sudo make uninstall` first, then
installed from the package, existing config, store, and group survive by path
continuity. Over-installing the package over a `make install` is
**forbidden** — stale units shadow vendor placement. See
[docs/install/migrate-from-makeinstall.md](docs/install/migrate-from-makeinstall.md).
## Uninstall and purge
### Package removal
```bash
sudo apt remove fenris # preserves config and store
sudo apt purge fenris # also removes config and store
sudo dnf remove fenris # preserves config and store
```
### Development removal
```bash
make uninstall # removes artifacts, preserves config and observation history
make purge # also removes /etc/fenris and /var/lib/fenris
@@ -110,17 +203,17 @@ Use a stable `/dev/disk/by-id/` path. Raw `/dev/nvmeX` paths are warned against.
## Where's my stuff?
| Artifact | Location |
|---|---|
| Wrapper | `/usr/local/bin/fenris` |
| Helpers | `/usr/libexec/fenris/fenris-collect`, `fenris-monitor` |
| Units | `/etc/systemd/system/fenris-collect.{timer,service}` |
| Polkit policy | `/usr/share/polkit-1/actions/com.bongbetic.fenris.monitor.policy` |
| Configuration | `/etc/fenris/fenris.conf` |
| Observation store | `/var/lib/fenris/observations.db` |
| Venv | `/opt/fenris` |
| Manifest | `/var/lib/fenris/manifest.txt` |
| Legacy history | `./data/history.jsonl` (auto-imported on install if present) |
| Artifact | Package install | make install |
|---|---|---|
| Wrapper | `/usr/bin/fenris` | `/usr/local/bin/fenris` |
| Helpers | `/usr/libexec/fenris/` | `/usr/libexec/fenris/` |
| Units | `/usr/lib/systemd/system/` (vendor) | `/etc/systemd/system/` |
| Polkit policy | `/usr/share/polkit-1/actions/` | `/usr/share/polkit-1/actions/` |
| sysusers/tmpfiles | `/usr/lib/{sysusers,tmpfiles}.d/fenris.conf` | managed by Makefile |
| Configuration | `/etc/fenris/fenris.conf` | `/etc/fenris/fenris.conf` |
| Observation store | `/var/lib/fenris/observations.db` | `/var/lib/fenris/observations.db` |
| Venv | `/opt/fenris` | `/opt/fenris` |
| Legacy history | — | `./data/history.jsonl` (auto-imported) |
---