feat: integrate local Blossom, reviewed nsites and scoped app access
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# Blossom on Archipelago
|
||||
|
||||
Candidate package, not a published catalogue release. Follow
|
||||
[`docs/app-developer-guide.md`](../../docs/app-developer-guide.md) and
|
||||
[`docs/candidate-catalog-qualification.md`](../../docs/candidate-catalog-qualification.md)
|
||||
for lifecycle and catalogue acceptance.
|
||||
|
||||
## Package contract
|
||||
|
||||
- MIT upstream `hzrd149/blossom-server` 6.4.1, source commit
|
||||
`a492dc61c4a581bbd0992546b2aec6f9aa543f75`. The Dockerfile verifies the source
|
||||
archive SHA-256 and uses upstream's frozen dependency lock for the server.
|
||||
- Manifest-owned local build; the runtime payload must include `docker/blossom`.
|
||||
No unpublished registry image is advertised. Initial installation needs access
|
||||
to the open-source build dependencies; normal startup uses cached dependencies.
|
||||
- Rootless container, read-only root, no capabilities, no new privileges,
|
||||
explicit `slirp4netns`. Host port 8191 binds IPv4 loopback behind AppGate.
|
||||
Keep that private backend binding: any FIPS/IPv6 ingress belongs at the gate.
|
||||
- Persistent data and SQLite under `/var/lib/archipelago/blossom/data`.
|
||||
Preserve this directory on uninstall. No automatic expiry/pruning, automatic
|
||||
mirroring, media conversion, or upstream administration dashboard.
|
||||
- Uploads require BUD-11 signatures from the profile identities supplied by
|
||||
`{{NODE_IDENTITY_PUBKEYS}}`. No profile means startup fails closed. Changes to
|
||||
that allowlist take effect on restart, including revocation of removed profiles.
|
||||
The appliance identity is excluded. Listing requires the owner's signature.
|
||||
- The custom local UI loads the canonical, host-managed `nostr-provider.js`
|
||||
through the documented lifecycle hook. A missing provider fails verification.
|
||||
The UI uses the platform identity chooser and ordinary NIP-07 signing; there
|
||||
is no generated browser key, nsec input, or second consent modal.
|
||||
- Upload authorization is scoped to the file hash, actual server hostname and
|
||||
five-minute expiry. Local upload does not send a public Nostr announcement.
|
||||
- Uploaded files are returned as sandboxed attachments. Untrusted HTML/SVG must
|
||||
not acquire this app's origin or signer access. Published website rendering
|
||||
needs the separate website origin, not a relaxation of this policy.
|
||||
|
||||
AppGate protects reads as well as the UI. Blossom itself is content-addressed,
|
||||
not an encrypted per-user vault: other authorized node users who know a hash can
|
||||
retrieve its bytes. Do not open the whole app gate to publish one website. Public
|
||||
asset serving must authorize exact selected hashes; external replication requires
|
||||
its own explicit content/destination review. An inaccessible local URL is not a
|
||||
working public Blossom endpoint.
|
||||
|
||||
## Qualification evidence — 2026-10-08
|
||||
|
||||
- Manifest preflight: 16 passed, no warnings. Generated catalogue drift: zero.
|
||||
- Candidate built and started on Framework with read-only root and the declared
|
||||
resource/security constraints. All protocol tests use synthetic identities and
|
||||
files; no public relay or external Blossom server is contacted.
|
||||
- `tests/apps/blossom/protocol.ts` passed against the candidate: authenticated
|
||||
upload/readback, exact hash/size/bytes, wrong identity/server/expired/anonymous
|
||||
upload rejection, owner-only listing, disabled mirror, canonical provider and
|
||||
health endpoint. HTML response has sandbox CSP and attachment headers.
|
||||
- Fixture survived container recreation with the same data directory and restart
|
||||
with explicit slirp4netns. An earlier test using Podman's default pasta hit a
|
||||
transient port teardown conflict; that is not the package's configured network.
|
||||
- Canonical Rust parser: all shipped manifests parse in the isolated test runner.
|
||||
- Setup/source tests: 13 passed, dashboard typecheck passed including the final
|
||||
receipt-review presentation changes.
|
||||
- Packaged UI passed a real Chromium test at mobile width: explicit identity
|
||||
chooser, consent before upload, signer refusal blocks upload, hash/host-scoped
|
||||
upload, consent reset and no external requests. Signer and upload transport
|
||||
were mocked for this UI test; live protocol checks above are separate.
|
||||
- Framework's normal installer succeeded after the operator temporarily disabled
|
||||
dashboard 2FA. Candidate manifest and build context are staged in the runtime
|
||||
payload. The app is healthy, with its canonical bridge installed by the hook,
|
||||
read-only root, slirp4netns and a loopback backend behind AppGate. Anonymous
|
||||
HTTPS access on port 8191 returns the gate's 401 sign-in page.
|
||||
- Real HTTPS tab signer acceptance passed: profile chooser, refusal prevents any
|
||||
upload, and an approved BUD-11 authorization stores a synthetic local file.
|
||||
No real identity key was exported or public Nostr event sent. Existing native
|
||||
Bitcoin/LND processes retained their original start times during installation.
|
||||
- No signed catalogue, source proposal, public Nostr event, OTA or ISO published.
|
||||
|
||||
- Real HTTP tab signing also passed. Normal app stop/start, restart with a new
|
||||
container, uninstall with `preserve_data:true`, reinstall, and management restart
|
||||
all preserved the uploaded synthetic file, verified by hash. Native Bitcoin/LND
|
||||
processes retained their original start times.
|
||||
- Local website archive integration is implemented in source: an explicit action
|
||||
signs a hash/server-scoped upload, stores the saved draft through the local
|
||||
manifest-owned Blossom backend, verifies exact readback and records a receipt.
|
||||
It does not announce or replicate anything. Its backend RPC is not yet deployed.
|
||||
|
||||
Still required before release: cross-profile identity switch (only one profile
|
||||
was available), HTTP/HTTPS iframe and physical companion validation, arranged
|
||||
reboot, integrated website archive acceptance, then reviewed source/mirror parity
|
||||
and signed catalogue gates. Selective public asset routes remain separate work;
|
||||
the authenticated app address must never be advertised as a public Blossom URL.
|
||||
Restore dashboard 2FA with the operator after live testing.
|
||||
@@ -0,0 +1,87 @@
|
||||
app:
|
||||
id: blossom
|
||||
name: Blossom
|
||||
version: 6.4.1-archy.1
|
||||
upstream:
|
||||
kind: github
|
||||
repo: hzrd149/blossom-server
|
||||
description: Local file storage for Nostr and websites, using your Archipelago signer. External publishing is a separate explicit choice.
|
||||
category: data
|
||||
container:
|
||||
network: slirp4netns
|
||||
build:
|
||||
context: /opt/archipelago/docker/blossom
|
||||
dockerfile: Dockerfile
|
||||
tag: localhost/archipelago-blossom:6.4.1-archy.1
|
||||
derived_env:
|
||||
- key: ARCHY_BLOSSOM_PUBKEYS
|
||||
template: '{{NODE_IDENTITY_PUBKEYS}}'
|
||||
dependencies:
|
||||
- storage: 1Gi
|
||||
resources:
|
||||
cpu_limit: 1
|
||||
memory_limit: 512Mi
|
||||
disk_limit: 5Gi
|
||||
security:
|
||||
capabilities: []
|
||||
readonly_root: true
|
||||
no_new_privileges: true
|
||||
network_policy: isolated
|
||||
seccomp_profile: default
|
||||
ports:
|
||||
- host: 8191
|
||||
container: 3000
|
||||
protocol: tcp
|
||||
bind: 127.0.0.1
|
||||
auth: gated
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /var/lib/archipelago/blossom/data
|
||||
target: /data
|
||||
options: [rw]
|
||||
- type: bind
|
||||
source: /var/lib/archipelago/blossom/bridge
|
||||
target: /bridge
|
||||
options: [rw]
|
||||
- type: bind
|
||||
source: /var/lib/archipelago/blossom/config.json
|
||||
target: /config/config.json
|
||||
options: [ro]
|
||||
- type: tmpfs
|
||||
target: /tmp
|
||||
options: [rw, nosuid, nodev, size=64m]
|
||||
files:
|
||||
- path: /var/lib/archipelago/blossom/config.json
|
||||
overwrite: false
|
||||
content: '{}'
|
||||
hooks:
|
||||
post_install:
|
||||
- copy_from_host:
|
||||
src: web-ui/nostr-provider.js
|
||||
dest: /bridge/nostr-provider.js
|
||||
- exec: [sh, -c, 'test -s /bridge/nostr-provider.js']
|
||||
health_check:
|
||||
type: http
|
||||
endpoint: http://127.0.0.1:3000
|
||||
path: /healthz
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
interfaces:
|
||||
main:
|
||||
name: Local files
|
||||
type: ui
|
||||
port: 8191
|
||||
protocol: http
|
||||
path: /
|
||||
metadata:
|
||||
author: hzrd149 / Archipelago
|
||||
tier: optional
|
||||
icon: /assets/img/app-icons/blossom.svg
|
||||
license: MIT
|
||||
repo: https://github.com/hzrd149/blossom-server
|
||||
tags: [nostr, blossom, storage, websites]
|
||||
launch:
|
||||
open_in_new_tab: false
|
||||
requires_host_frame: false
|
||||
@@ -67,6 +67,7 @@ app:
|
||||
path: /
|
||||
|
||||
metadata:
|
||||
guest_access: true # Explicit app-only sharing through AppGate; app accounts still apply.
|
||||
icon: /assets/img/app-icons/homeassistant.png
|
||||
category: home
|
||||
author: Home Assistant
|
||||
|
||||
@@ -84,5 +84,6 @@ app:
|
||||
path: /
|
||||
|
||||
metadata:
|
||||
guest_access: true # Explicit app-only sharing through AppGate; app accounts still apply.
|
||||
launch:
|
||||
open_in_new_tab: true
|
||||
|
||||
@@ -63,6 +63,7 @@ app:
|
||||
path: /
|
||||
|
||||
metadata:
|
||||
guest_access: true # Explicit app-only sharing through AppGate; app accounts still apply.
|
||||
icon: /assets/img/app-icons/jellyfin.webp
|
||||
category: data
|
||||
author: Jellyfin
|
||||
|
||||
@@ -59,6 +59,7 @@ app:
|
||||
path: /
|
||||
|
||||
metadata:
|
||||
guest_access: true # Explicit app-only sharing through AppGate; app accounts still apply.
|
||||
icon: /assets/img/app-icons/nextcloud.webp
|
||||
category: data
|
||||
author: Nextcloud
|
||||
|
||||
@@ -60,6 +60,7 @@ app:
|
||||
path: /
|
||||
|
||||
metadata:
|
||||
guest_access: true # Explicit app-only sharing through AppGate; app accounts still apply.
|
||||
icon: /assets/img/app-icons/photoprism.svg
|
||||
category: data
|
||||
author: PhotoPrism
|
||||
|
||||
@@ -219,3 +219,6 @@ app:
|
||||
nostr_integration:
|
||||
relay_type: public
|
||||
monetization_enabled: true
|
||||
|
||||
metadata:
|
||||
guest_access: true
|
||||
|
||||
Reference in New Issue
Block a user