Merge claude/2
This commit is contained in:
commit
9b5a4d276d
@ -85,6 +85,33 @@ builds. Same tooling, different `<channel>`. To promote an edge build to stable,
|
|||||||
rebuild with `make_release.sh stable` at that ref (or copy its artifacts into the
|
rebuild with `make_release.sh stable` at that ref (or copy its artifacts into the
|
||||||
`stable/` path and update `stable/latest.json`).
|
`stable/` path and update `stable/latest.json`).
|
||||||
|
|
||||||
|
## Publish an app to the marketplace catalog
|
||||||
|
|
||||||
|
The registry/marketplace rides the same signed channel as releases and hotfixes
|
||||||
|
(`docs/roadmap/updates-and-distribution.md` §8): one `index.json`, one signing
|
||||||
|
key, one static tree. An app in the catalog is just the drop-in definition
|
||||||
|
folder, packed and signed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scripts/release/make_app.sh <slug> [channel] [spec.json] # e.g. make_app.sh speedtest
|
||||||
|
```
|
||||||
|
|
||||||
|
Produces, under `dist/<channel>/`: `payloads/app-<slug>.tar.gz(.minisig)`, a
|
||||||
|
pinned catalog icon under `payloads/icons/`, and the upserted + re-signed
|
||||||
|
`index.json`. Title/category/descriptions come from the app's own `.config` —
|
||||||
|
no second source of truth; the optional `spec.json` overlays envelope fields
|
||||||
|
(`id`, `version`, `why`, `applies_when.min_lp`, …). Re-publishing an unchanged
|
||||||
|
app is byte-identical and keeps its version; changed bytes auto-bump it.
|
||||||
|
|
||||||
|
Boxes surface catalog apps in the App Center as **"Available — Add"** cards
|
||||||
|
(`updater check` refreshes `registry_catalog.json`), and `libreportal app add
|
||||||
|
<slug>` verifies + quarantine-validates the bundle and drops the definition
|
||||||
|
into the install tree — from there it's a normal app with a normal Install
|
||||||
|
button. Local definitions always win over the catalog; installed apps are
|
||||||
|
never touched. Test the whole loop against a local server exactly like a
|
||||||
|
release (`python3 -m http.server` + `LP_RELEASE_BASE_URL`), starting with
|
||||||
|
`libreportal artifact index`.
|
||||||
|
|
||||||
## Test a release locally before publishing
|
## Test a release locally before publishing
|
||||||
|
|
||||||
No hosting needed — serve `dist/` and point an install at it:
|
No hosting needed — serve `dist/` and point an install at it:
|
||||||
|
|||||||
@ -358,6 +358,36 @@ components is **purely additive**:
|
|||||||
|
|
||||||
This is exactly the §3 "registry, not marketplace" shape, now expressed in the format.
|
This is exactly the §3 "registry, not marketplace" shape, now expressed in the format.
|
||||||
|
|
||||||
|
### 8.4b App bundles — the registry payload (spec addendum, built 2026-07-03)
|
||||||
|
|
||||||
|
The first non-hotfix type through the pipe. **Envelope**: byte-for-byte §8.1 with
|
||||||
|
`type:"app"`, `payload.kind:"bundle"` (a `.tar.gz`), the app slug in
|
||||||
|
`applies_when.app` (fork 3's field doing double duty — for `type:"app"` the
|
||||||
|
resolver skips the "must be installed" gate; presence is the collision policy's
|
||||||
|
call), and one **optional additive object** for the browse UI:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"meta": { "category": "media", "description": "…", "long_description": "…",
|
||||||
|
"icon": "stable/payloads/icons/<slug>.svg", "icon_sha256": "…" }
|
||||||
|
```
|
||||||
|
|
||||||
|
Old boxes ignore `meta` (parsers select known fields). Icons are mirrored locally
|
||||||
|
by the scan **only when their bytes match the pin** — the browser is never pointed
|
||||||
|
at a remote host.
|
||||||
|
|
||||||
|
**Tarball contract** (enforced fail-closed by the box-side quarantine validator
|
||||||
|
*before* anything lands in the live-sourced definition tree — placing a definition
|
||||||
|
is deferred code execution, so trust gates → quarantine → placement, in that
|
||||||
|
order): gzip; exactly one top-level dir `== slug`; slug `^[a-z0-9][a-z0-9_]{0,31}$`
|
||||||
|
(shell-identifier-safe; `template`/`libreportal`/`tools`/`scripts`/`resources`
|
||||||
|
reserved); regular files + dirs only (no links/devices); no `..`/absolute paths;
|
||||||
|
path charset `[A-Za-z0-9._/@:+-]`; caps 5 MB tarball / 20 MB declared extracted /
|
||||||
|
400 entries; set-id bits stripped; must contain `<slug>.config` (TITLE+CATEGORY,
|
||||||
|
parsed line-wise, never sourced) + `docker-compose.yml`; every `*.sh` must pass
|
||||||
|
`bash -n`. **Collision policy:** an installed app refuses (updating live apps is
|
||||||
|
the updater's job); a local non-registry definition always wins; a registry-owned
|
||||||
|
definition updates reversibly (prior tree packed into the undo array).
|
||||||
|
|
||||||
### 8.5 Fork resolutions (was §6)
|
### 8.5 Fork resolutions (was §6)
|
||||||
|
|
||||||
1. **Hotfix scope** → **config/compose ops + checksum-pinned file patches; NO code
|
1. **Hotfix scope** → **config/compose ops + checksum-pinned file patches; NO code
|
||||||
@ -449,8 +479,29 @@ This is exactly the §3 "registry, not marketplace" shape, now expressed in the
|
|||||||
- ✅ **Phase 5 — publisher tooling (BUILT 2026-05-31).** `make_hotfix.sh` turns a spec into
|
- ✅ **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
|
the signed payload + index entry (serial bump, freshness, publishers map), minisign-signs
|
||||||
with `LP_MINISIGN_SECKEY`. Verified end-to-end in unsigned/local mode.
|
with `LP_MINISIGN_SECKEY`. Verified end-to-end in unsigned/local mode.
|
||||||
- ⬜ **Deferred (registry; additive, demand-gated — intentionally NOT built).**
|
- ✅ **Phase 6 — the registry slice: app bundles + Browse-&-Add (BUILT 2026-07-03).**
|
||||||
`payload.kind:"bundle"` applier (verify tarball → extract into the app tree → scan/regen) +
|
- `make_app.sh <slug>` packs `containers/<slug>/` (the unchanged drop-in contract)
|
||||||
`type:"app"|"theme"|"component"` + the `app_add` task + community trust-tier **host-script
|
into a deterministic signed tarball + a `type:"app"` / `payload.kind:"bundle"`
|
||||||
quarantine** (§3.2) + multi-source "tap" UX + the warrant-canary countersigning
|
envelope (metadata derived from the app's own `.config`; `auto:false` forced —
|
||||||
`index_serial`. The hotfix product (Phases 1–5) is complete; the registry waits for demand.
|
apps never auto-apply). Shared index logic factored into `lib/release_index.sh`.
|
||||||
|
- Box side: the two designed seams opened (`_artifactResolve` accepts `app`;
|
||||||
|
`_artifactApplyBundleFlow` handles `bundle`) — fetch → sha256-pin → minisig →
|
||||||
|
**quarantine validation** (§8.8) → place in the definition tree → regen →
|
||||||
|
verify-in-apps.json → applied-record with precise undo → History. Collision
|
||||||
|
policy: installed-live refused, local definitions win, registry-owned re-add =
|
||||||
|
reversible definition update. Revert removes/restores the definition.
|
||||||
|
- `libreportal app add <slug|id>` (the `app_add` task) + `webuiRegistryCatalogScan`
|
||||||
|
(registry_catalog.json + pin-verified same-origin icons) + App Center
|
||||||
|
"Available — Add" cards (indigo pill, official badge; local always wins).
|
||||||
|
The Improvements stream is now explicitly hotfix-only (unknown types skip+log).
|
||||||
|
- En route, two latent trust-gate bugs fixed: `LP_INDEX_SIGSTATE` (and the whole
|
||||||
|
resolve-global set) was stranded in command-substitution subshells — on a
|
||||||
|
signed box every apply would have refused as unsigned. `lpFetchIndexInto` +
|
||||||
|
direct-call resolve now propagate them.
|
||||||
|
- Harness-tested: 10/10 (read path), 46/46 (bundle applier), 14/14 (catalog scan);
|
||||||
|
live task-loop + WebUI verified visually.
|
||||||
|
- ⬜ **Deferred (additive, demand-gated — intentionally NOT built).** Community
|
||||||
|
trust-tier **host-script quarantine** (§3.2) + multi-source "tap" UX +
|
||||||
|
`type:"theme"|"component"` bundle handlers + the warrant-canary countersigning
|
||||||
|
`index_serial`. The browsable marketplace *website* (shipped as a dev-mode-gated
|
||||||
|
LibrePortal app) is designed in `marketplace-website.md`.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user