Some apps carry a complete account system and are broken by an upstream
challenge: git clients speak basic-auth (not browser cookies), and a
BTCPay checkout link handed to a customer must open for that customer.
Both were behind the gate's login page — the "non-browser clients need an
access token" gap disclosed in five consecutive releases.
- New manifest port policy `auth: open`: the daemon still fronts the port
exactly like `gated` (loopback pin, external binds, frame-header fixes,
app-down retry page, Tor upstream) but serves it without the login
challenge. Requires auth_rationale, same burden of proof as `none`.
Gitea 3001 and BTCPay 23000 declare it.
- Runtime operator override per app (security.set-app-gate → app-configs/
<id>.json "gateEnabled"), surfaced as Settings → app → Access control.
Wins over the manifest in both directions and applies on the next
request — no restart, and it works today on catalog-covered apps whose
signed manifest still says `gated`.
- The gate resolves policy per-request from the live port map, so a
toggle takes effect without waiting for the 60s rebind sweep. "Off"
never releases the port: gated apps are loopback-pinned, so releasing
would strand them, not open them.
- security.app-gate-status now reports gate_enabled + any override.
- New guard test pins the `auth: open` set (both entries reviewed); the
`auth: none` count moves 25 → 26, absorbing pre-existing drift from the
phoenixd onboarding (loopback JSON API with its own generated password).
- Docs: the manifest spec's ports row documented only host/container/
protocol — bind, auth, auth_rationale and session_passthrough were
undocumented. Added a full "Ports & the app gate" section plus a
developer-guide entry telling app authors to enforce their own auth
regardless, since the operator can flip the gate either way.
Verified live on archi-dev-box from an external address: gated → 401 gate
page; override off → Gitea 200 own page, BTCPay 302 to its own login,
git-over-HTTP info/refs 200; override on → 401 again; clear → default.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Companion tap/scroll/type now works INSIDE cross-origin app iframes and
kiosk tabs. The web relay synthesizes untrusted DOM events in the top
document, which can never cross an origin boundary — so apps served
through the appgate were dead to the remote. The kiosk Chromium now
exposes a loopback-only CDP port (default origin check intact, no
--remote-allow-origins) and a backend bridge (api/handler/cdp.rs)
dispatches validated companion input as Input.dispatchKeyEvent /
dispatchMouseEvent / mouseWheel — trusted events that hit-test through
any frame, move real focus, and insert text like a physical device.
- Session keeper self-heals across kiosk Chromium restarts; inert on
nodes without a kiosk unit (falls back to the existing relay path).
- The kiosk relay subscriber self-tags (?kiosk=1) and the backend mutes
its key/click/scroll messages while the bridge is live, so input never
applies twice; cursor moves still flow for the on-screen cursor.
- While companion input is active the native OS pointer is hidden
(cursor:none, auto-restores 30s after the last event) so the dead
physical-mouse cursor doesn't sit next to the virtual one.
- docs/tv-input-iframe-apps.md scope note updated: gamepad keys stay on
uinput; CDP is for companion pointer/typing only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- alby-hub + phoenixd icons re-set with the standard 12% inner margin
(they shipped edge-to-edge; every other icon carries whitespace).
- scripts/normalize-app-icon.py: wraps any third-party SVG mark onto the
house canvas — the system applies the tile plate (archy-app-icon)
automatically but deliberately no runtime inset, so the margin must be
baked; the guide now says exactly that.
- MarketplaceAppDetails: the icon now carries archy-app-icon like the
store tiles — the treatment no longer stops at the detail page.
- v1.8.2 changelog: third curated bullet (the ceremony gate requires 3).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An app whose frame never loads while its backend reports Running (the
embed-refusal signature: frame-busting JS, top-level-origin apps,
SameSite=Strict logins — everything the gate's header stripping cannot
fix) is remembered in localStorage; every later launch opens a tab
straight from the click (user gesture, so no popup blocker), and
opensInTab() gives it the tab-launch icon. A successful iframe load
clears the memory and entries expire after 7 days, so nodes that gain
embedding (gate improvements) get re-probed instead of being remembered
broken forever. Dev guide updated; v1.8.2 changelog + What's New curated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
phoenixd: the orchestrator treats bind paths containing a dot as file
mounts and never creates their source dir, so the image's default
/phoenix/.phoenix target crash-looped the unit (statfs: no such file).
Datadir moved to /data via PHOENIX_DATADIR; data_uid 1000:1000 matches the
image's phoenix user — without it phoenixd dies on phoenix.conf
'Permission denied'. Both verified end-to-end on archi-dev-box: orch
install OK, seed.dat + db on the host, authenticated /getinfo answers.
alby-hub: launch flips to embedded — pairs with the gate change that
neutralizes upstream frame blocking.
Dev guide: iframe embedding rules (who blocks framing and why the gate
may strip it; when open_in_new_tab is legitimate; test in the embedded
session, never a tab).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Learned installing alby-hub/phoenixd for real: the id-only payload fails
with 'Missing dockerImage' (the store normally injects the image from the
catalog), the session helper silently reuses a stale cached session
without ARCHY_FORCE_LOGIN=1, needs jq, and its set -euo pipefail kills an
interactive shell chain without output — so the guide now wraps the flow
in a heredoc subshell.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The old RPC example skipped login entirely and implied disk manifests show
up in the App Store. Documents: store lists signed-catalog + Nostr apps
only; the runtime-payload staging path (naive /opt/archipelago/apps copies
are deleted on every backend start); the rpc.bash session helper; and the
full lifecycle loop to run before submitting to the catalog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>