From 9ca5e8922c635bf91253a8f09f072974c6441aa5 Mon Sep 17 00:00:00 2001 From: librelad Date: Sun, 31 May 2026 21:26:31 +0100 Subject: [PATCH] =?UTF-8?q?docs(distribution):=20mark=20the=20hotfix=20pro?= =?UTF-8?q?duct=20(Phases=201=E2=80=935)=20built?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update §8.7 + the banner + §1 TODOs to reflect that Phases 2–5 shipped today (apply/revert pipeline, severity-split auto-apply, the WebUI Improvements stream + per-app chip, and make_hotfix.sh). Only the registry/marketplace stays deferred (demand-gated by design). Co-Authored-By: Claude Opus 4.8 Signed-off-by: librelad --- docs/roadmap/updates-and-distribution.md | 65 +++++++++++++----------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/docs/roadmap/updates-and-distribution.md b/docs/roadmap/updates-and-distribution.md index a267c25..71db913 100644 --- a/docs/roadmap/updates-and-distribution.md +++ b/docs/roadmap/updates-and-distribution.md @@ -1,13 +1,15 @@ # LibrePortal — Updates, Improvements & Distribution (Roadmap / Vision) -**Status:** §0–§7 are the brainstorm (vision). **§8 is the committed format spec** and the open forks (§6) are resolved there. · **Audience:** us, future-self · **Scope:** the updater feature, "hotfixes", and how third-party themes/apps/components get distributed · **Origin:** brainstorm 2026-05-30/31 → format decided & Phase 1 built 2026-05-31 +**Status:** §0–§7 are the brainstorm (vision). **§8 is the committed format spec** and the open forks (§6) are resolved there. · **Audience:** us, future-self · **Scope:** the updater feature, "hotfixes", and how third-party themes/apps/components get distributed · **Origin:** brainstorm 2026-05-30/31 → format decided & the hotfix product (Phases 1–5) built 2026-05-31 > Sections 0–7 below are the original thinking doc — kept verbatim so the > reasoning isn't lost. **The conclusion of that brainstorm is §8: the concrete > artifact format**, designed so apps/themes/components slot into the same pipe a -> hotfix uses. Phase 1 of it (the signed-fetch+verify read primitive) is already -> built — see §8.7. The forks in §6 are no longer open; §8.5 records how each was -> resolved. +> hotfix uses. The hotfix product (Phases 1–5: signed fetch+verify, the reversible +> apply/revert pipeline, severity-split auto-apply, the WebUI Improvements stream, +> and the `make_hotfix.sh` publisher tool) is **built** — see §8.7. Only the +> registry/marketplace is deferred. The forks in §6 are no longer open; §8.5 +> records how each was resolved. --- @@ -73,8 +75,8 @@ bold default. - [x] Define the declarative hotfix schema (the allowed operations + checksum preconditions). → **§8.2** - [x] Decide auto-apply policy (uniform vs severity-split). → **§8.5 fork 2** (severity-split) - [x] Fetch + verify the signed manifest on the same channel as the version check. → **§8.7 Phase 1 (built)** -- [ ] Apply pipeline for the ops (snapshot → apply → verify → rollback → History). → §8.7 Phase 2 -- [ ] Surface applied/available hotfixes as a stream in the updater + History audit trail. → §8.7 Phase 3 +- [x] Apply pipeline for the ops (snapshot → apply → verify → rollback → History). → **§8.7 Phase 2 (built)** +- [x] Surface applied/available hotfixes as a stream in the updater + History audit trail. → **§8.7 Phase 4 (built)** --- @@ -424,26 +426,31 @@ This is exactly the §3 "registry, not marketplace" shape, now expressed in the that fetches + verifies + lists. Runs directly (no mutation), like `updater check`. - Self-tested: trust core fails closed (real key + no minisign → refuse), happy path, stale-refused, rollback-refused, signature-refused, jq + grep parsing — 12/12. -- ⬜ **Phase 2 — the ops applier + apply verb (the heart, *next*).** `artifactApply` - (steps 0–9) + `artifactApplyOps` (the §8.2 vocabulary with dry-precheck-all + per-op - `undo[]`), the **publishers-map two-tier sig check + canonical-envelope verification**, - snapshot → apply → verify → auto-rollback → History, wired as `artifact_apply` / - `artifact_revert` tasks. Reuse `updateConfigOption` / `dockerComposeUp` / - `updaterComposePull` / `backup app` / `updaterRollbackApp` verbatim. Extend `history.json` - (`artifact_id`, `serial`, `undo`) **and fix the `updaterRecordHistory` jq-silent-skip - (fail-closed + bash-native fallback)** — the "nothing silent" guarantee depends on it. - Makes the Vaultwarden killer use case real, first-party. -- ⬜ **Phase 3 — auto-apply policy.** `CFG_HOTFIX_AUTO`, the periodic-check auto-apply of - `security`/`breakage` (queue `compat`/`tweak` as suggestions), staged rollout + delay. -- ⬜ **Phase 4 — WebUI "Updates & Improvements".** Extend `webuiUpdaterScan` to fetch + - verify the index into a **temp then atomically write** `artifacts_available.json` (never - emit broken JSON; keep the prior file on failure) — **no second phone-home**. Add the - Hotfixes/Improvements stream (why / severity / source, one-click revert, per-app chip). - *User-visible → verify with `lp-shot` on the updater route before calling it done.* -- ⬜ **Phase 5 — publisher tooling.** `make_hotfix.sh` (sibling of `make_release.sh`) emits - a payload + sha256 + minisig + the index entry, then re-signs the index bumping - `index_serial`. The piece that lets a maintainer actually ship one. -- ⬜ **Deferred (registry; additive, demand-gated).** `payload.kind:"bundle"` applier (verify - tarball → extract into the app tree → scan/regen) + `type:"app"|"theme"|"component"` + - the `app_add` task + community trust-tier **host-script quarantine** (§3.2) + multi-source - "tap" UX + the warrant-canary countersigning `index_serial`. +- ✅ **Phase 2 — the ops applier + apply/revert verb (BUILT 2026-05-31).** `artifactApply` + / `artifactRevert` (`cli_artifact_apply.sh`): resolve+gate → fetch+verify payload → + dry-precheck-all → snapshot → apply (each op records a precise `undo`) → bring up → + auto-rollback → applied-record + History. Bounded op vocabulary (`set-config-key`, + `set-compose-image`, `patch-file-if-checksum-matches`, `set-data-file`; unsupported op + rejects the whole artifact). Two-tier trust (index verified vs footprint key + payload + sha256-pinned + minisig + publishers-map role gate). Write-target firewall + value/path + charset guards. Routed as `artifact_apply`/`artifact_revert` tasks. `updaterRecordHistory` + jq-silent-skip **fixed** (fail-closed + bash-native fallback) + extended. The + updater's own broken snapshot/rollback calls fixed too. Hardened against a 17-finding + adversarial security review. Unit-tested 35/35. +- ✅ **Phase 3 — severity-split auto-apply (BUILT 2026-05-31).** `CFG_HOTFIX_AUTO` + (`security-breakage`|`all`|`off`, default `security-breakage`); `webui_artifact_scan.sh` + writes `artifacts_available.json` atomically (keep-prior-on-failure); `artifactApplyAuto` + (`artifact apply-auto`) enqueues eligible signed hotfixes (verified-index-only, in-policy, + applicable, not-applied) from the `updater check`. Unit-tested 13/13. +- ✅ **Phase 4 — WebUI "Improvements" stream + per-app chip (BUILT 2026-05-31).** New + Improvements tab in the updater (severity badges, apply/revert via the task system, + unsigned = apply-disabled) + overview stat card + an amber per-app chip on the App detail + page. Task icons/labels added. Verified visually with `lp-shot`. +- ✅ **Phase 5 — publisher tooling (BUILT 2026-05-31).** `make_hotfix.sh` turns a spec into + the signed payload + index entry (serial bump, freshness, publishers map), minisign-signs + with `LP_MINISIGN_SECKEY`. Verified end-to-end in unsigned/local mode. +- ⬜ **Deferred (registry; additive, demand-gated — intentionally NOT built).** + `payload.kind:"bundle"` applier (verify tarball → extract into the app tree → scan/regen) + + `type:"app"|"theme"|"component"` + the `app_add` task + community trust-tier **host-script + quarantine** (§3.2) + multi-source "tap" UX + the warrant-canary countersigning + `index_serial`. The hotfix product (Phases 1–5) is complete; the registry waits for demand.