86 lines
3.9 KiB
Markdown
86 lines
3.9 KiB
Markdown
# Design
|
|||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
See proposal.md — Why. The `fingerprint-agent` repository and its releases are
|
||
|
|
private: an unauthenticated request to the forge's releases API answers `404`.
|
||
|
|
Releases already publish, per build, a generic bundle
|
||
|
|
(`fpagent-<version>-linux-x86_64.tar.gz`), per-Ubuntu offline bundles
|
||
|
|
(`fpagent-<version>-ubuntu-<codename>-x86_64.tar.gz`) with the libfprint `.deb`
|
||
|
|
closure vendored, and a `.sha256` beside each. Every bundle already contains
|
||
|
|
the fpagent binary, the udev rule, and its own `install.sh` that handles
|
||
|
|
libfprint, udev, `plugdev` and the systemd service. The tools app is an Express
|
||
|
|
server with a hardcoded-configuration policy whose only sanctioned environment
|
||
|
|
variables were the Image Cropper credentials.
|
||
|
|
|
||
|
|
## Goals / Non-Goals
|
||
|
|
|
||
|
|
**Goals:**
|
||
|
|
|
||
|
|
- A field laptop installs or updates fpagent with one public command.
|
||
|
|
- The forge credential never reaches the field laptop.
|
||
|
|
- Reuse the bundle's installer rather than reimplementing hardware setup.
|
||
|
|
|
||
|
|
**Non-Goals:**
|
||
|
|
|
||
|
|
- Replacing the bundle installer, or the forge's own release tooling.
|
||
|
|
- Authenticating the installer: it is intentionally public.
|
||
|
|
- Supporting architectures other than x86_64 (the bundle installer already
|
||
|
|
requires it).
|
||
|
|
|
||
|
|
## Decisions
|
||
|
|
|
||
|
|
1. **Proxy the release through the app; do not embed the key in the script.**
|
||
|
|
The credential lives in `GITEA_RELEASE_INSTALL_KEY` and the app fetches the
|
||
|
|
private release server-side. The alternative — rendering the key into the
|
||
|
|
served script so the client could call the forge directly — publishes a
|
||
|
|
repository credential to every installer and any `curl`; rejected.
|
||
|
|
|
||
|
|
2. **Two thin routes, no proxy framework.** `/fpagent/releases/latest` returns
|
||
|
|
a trimmed `{tag, assets:[{name,url}]}` with same-origin URLs, and
|
||
|
|
`/fpagent/releases/download/:tag/:name` streams one asset. Both are
|
||
|
|
registered before the session middleware so they stay public and do no
|
||
|
|
per-request PocketBase work. A single combined "give me the right tarball"
|
||
|
|
route was considered but needs the server to guess the client's OS; the
|
||
|
|
client knows its own codename, so selection happens in the script.
|
||
|
|
|
||
|
|
3. **The installer delegates to the bundle's own `install.sh`.** All hardware
|
||
|
|
and dependency logic already exists and is versioned with the binary;
|
||
|
|
reimplementing it in the hosted script would duplicate it and drift. The
|
||
|
|
hosted script only fetches, verifies, extracts, and forwards flags.
|
||
|
|
|
||
|
|
4. **Bundle selection prefers the codename offline bundle.** When the host's
|
||
|
|
`/etc/os-release` `VERSION_CODENAME` matches a published offline bundle, use
|
||
|
|
it (no network needed for the dependency closure); otherwise fall back to
|
||
|
|
the generic online bundle, whose installer apt-gets libfprint.
|
||
|
|
|
||
|
|
5. **Checksum verification, not signature verification.** The release publishes
|
||
|
|
sha256 only, so the installer verifies sha256 over TLS from the same origin
|
||
|
|
it trusts for the script itself. GPG would require release signing that does
|
||
|
|
not exist yet; deferred.
|
||
|
|
|
||
|
|
6. **Asset names are validated server-side** against a conservative pattern,
|
||
|
|
so a crafted tag or name cannot walk the forge path or reach another host.
|
||
|
|
|
||
|
|
## Risks / Trade-offs
|
||
|
|
|
||
|
|
- [A compromised tools app serves a malicious installer] → the app is already
|
||
|
|
trusted to serve the tools pages and holds the operator session; the
|
||
|
|
installer is not a new trust boundary. TLS to `tools.yrka.app` is the same
|
||
|
|
trust as the app.
|
||
|
|
- [The forge changes its bundle naming] → selection falls back to the generic
|
||
|
|
bundle, and a release with no matching asset fails loudly rather than
|
||
|
|
installing something wrong.
|
||
|
|
- [The app buffers an asset in memory] → bundles are tens of MB; acceptable,
|
||
|
|
and requests are rare. Streaming can replace it if that changes.
|
||
|
|
|
||
|
|
## Migration Plan
|
||
|
|
|
||
|
|
Add `GITEA_RELEASE_INSTALL_KEY` to `.env`/`.env.production` (already supplied)
|
||
|
|
and deploy the app; the installer and proxy are new routes and change no
|
||
|
|
existing behavior. Rollback = remove the routes; nothing else depends on them.
|
||
|
|
|
||
|
|
## Open Questions
|
||
|
|
|
||
|
|
None.
|