create-release.sh builds the frontend at step 4 and validates the curated
changelog at step 5, then requires the freshly built bundle to contain the new
version. The version reaches the bundle only through the hand-written What's
New list, so on a fresh release that check can only pass if the changelog and
What's New entries are written BEFORE the script runs. Writing them after is
what aborted the first attempt.
Leads with the downgrade bug, since that is the one users saw: an Update button
offering the release withdrawn for an actively exploited 2FA bypass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Operations docs move out of git entirely rather than being sanitized. They
stay on disk for local use and are gitignored, so the Phase 6 export (which
takes HEAD) can never carry them. 15 files: the fleet runbook, hotfix
process, node inventories, internal trackers, session handoffs, the key
rotation/signing-posture records, and the open-source plan itself.
For the docs that remain public, infra identifiers are replaced with things
that are better documentation rather than placeholders: curl examples now
use `archipelago.local`, the product's own mDNS name, so a reader can run
them as-is instead of substituting an address that was never theirs.
Deliberately NOT scrubbed, both verified as functional rather than leaked:
- `tx1138.com` is the shipped default block explorer (DEFAULT_TX_EXPLORER in
useTxExplorer.ts, surfaced in WalletSettingsModal). Product behavior.
- `git.tx1138.com` in core/container/{image_policy,registry}.rs is a retired-
registry constant the code matches on to strip stale entries from legacy
node configs. Removing it would break migration for older nodes.
- `192.168.1.254` in bulletproof-containers.md is the LAN gateway in a podman
bug description, and `192.168.1.x` in user-walkthrough.md is already generic.
Whether a personal domain should be the shipped explorer default in a public
product is a separate product question, not a security one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Leads with the update that switched nodes off and left them unable to
switch back on — the one an operator most needs to understand, and the
reason to take this release promptly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Leads with the honest version: five screens were open and the previous
release's own audit reported them as fine, found by scanning from another
machine rather than asking the node. States plainly that what leaked was
the page, not credentials — the macaroon path was verified, not assumed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Leads with what changes for the operator: app screens now require the node
password across LAN, Tailscale, mesh and Tor; the wallet/protocol ports that
must stay open stayed open; the mesh leak found during on-node verification;
nodes repairing their own legacy containers; and the signing-key rotation.
Known gaps disclosed, including the eleven still-undeclared ports and that
non-browser clients will now meet the login page.
The new block uses <strong> rather than the literal ** markers in earlier
entries, which render as asterisks in the modal.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
States plainly that the speed is unchanged — the fix gates the teleported
chrome, not the KeepAlive caching that made tab switching instant.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Leads with the reason to take the update: two ports handed anyone who
could reach them full control of the node's money. Written for an
operator, not a developer — what was exposed, who could reach it, and
what to treat as compromised.
Includes the gaps rather than burying them: the 5x lifecycle gate was not
run, two fleet nodes still share SSH host keys (rotation is a deliberate
operator decision, not an oversight), and Core can now reach Tor but is
not yet routed through it.
create-release.sh hard-fails without this section, so it lands before the
release run rather than during it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
create-release-manifest.sh's changelog extraction pulls every non-blank
line between the version header and the next "## ", not just "- "
bullets — so the previous commit's "### Known gap" markdown heading and
its paragraph leaked into releases/manifest.json (and, via
sync-whats-new.py, the Settings "What's New" modal) as a malformed,
truncated entry (the closing clarification sentence was cut by the
extractor's 10-line cap).
Rewritten as a single "- " bullet, matching every other CHANGELOG entry,
so it renders cleanly and completely in both the OTA manifest and the
in-app modal instead of showing raw "### " syntax to node operators.
Also folds in core/Cargo.lock's version bump, which create-release.sh's
own commit step omits from its `git add` list.
Same binary/frontend artifacts as the prior commit (identical sha256/
size in the regenerated manifest) — only the changelog text changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
scripts/sync-whats-new.py --check (part of the release gate) requires
every CHANGELOG version to have a matching block in the Settings
"What's New" modal. Also strips CHANGELOG markdown bold/italic markup
from the v1.7.119-alpha bullets first — the modal renderer only
strips backticks, not **/* emphasis, so it would have leaked literal
asterisks into the user-facing modal text.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Written ahead of create-release.sh, which validates a curated
CHANGELOG.md section already exists rather than generating one.
Leads with FED-08 (private-channel invoice route hints) and FED-09
(doctor/Tor setgid restart-loop fix), covers phase-02 sessionStorage
security hardening and the PWA auto-update decision, and records the
5x lifecycle gate omission (node .228 unreachable) as a known gap
rather than a footnote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rewrites the prepared 1.7.117 section to include the mesh flash flow,
first-class Reticulum fixes, radio-first routing, mesh chat polish, the
transactions-modal phone fixes, services-vs-apps classification, the
lightning slow-payment fix, cached-resource page loads, load-shedding,
FIPS uptime hardening, and companion 0.5.25. What's New modal block
regenerated from the new bullets (sync-whats-new --check passes).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bundles all post-115 fixes into an OTA release: boot READY-before-recovery
+ Restart=always (no more 'server starting up'), and the app-install
daemon-kill fix (v6 relay only bridges live app ports; port-cleanup
excludes our own PID).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fips::config::install() now writes /etc/fips/fips.d/80-web-ui.nft
(tcp 80/8443 accept) and reloads the baseline on every install/upgrade —
the hardening firewall default-denies inbound on fips0 and the UI was
unreachable over the mesh without it (root-caused live 2026-07-26).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The release gate requires ≥3 curated changelog bullets; the Pine app is
user-facing and deserved one anyway. Carries the version bumps and manifest
from the aborted cut so the tree is clean for the re-run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Supersedes the unpublished v1.7.107. Covers the multi-anchor FIPS fix, WiFi
self-heal, mesh fast-rejoin, kiosk TV-scaling, kiosk dark theme / VT hints /
UTF-8 logo / power-button hardening, and the ISO build fixes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ISO built FIPS from an unpinned --depth 1 clone of upstream main, so
every build shipped whatever happened to be on main that day. Pin to
v0.4.1 via a FIPS_VERSION build arg — the version fips/config.rs renders
its typed config against, and the one validated in the field on .198 and
the thinkpad. The pin lands inside the STEP 1 recipe-hash range, so the
cached rootfs correctly invalidates on the next build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Login video continuity, cloud bottom-bar music player, demo intro on
every visit — regenerated the What's New block to match.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v1.8.00-alpha changelog section never shipped as an OTA (no tag, live
manifest stayed 1.7.99-alpha); its content ships now as v1.7.100-alpha.
First 10 bullets are the OTA manifest changelog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The add-anchor form previously hardcoded transport=udp. Expose a
TCP/UDP selector (default tcp) so public internet anchors and
local-network anchors can both be added. Includes changelog + What's
New entry for v1.7.96-alpha.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The kiosk attached-display showed a separate app-tile launcher grid
(Kiosk.vue at /kiosk) instead of the normal onboarding/login/dashboard.
The grid is auth-gated, so it only surfaced once the kiosk browser held a
persisted session; otherwise it bounced to login — masking the issue.
Remove the grid entirely. /kiosk now just persists kiosk mode + safe-area
insets and redirects to the root app. The launcher keeps pointing at
/kiosk (not directly at /) so the 'kiosk' localStorage flag is still set —
App.vue uses it to skip the remote relay, which would otherwise double
xdotool input on the kiosk display. Route made public so the auth guard
doesn't bounce it before the redirect runs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FIPS peer content browse over the mesh was failing with "Peer returned
error: 404 Not Found" and never falling back to Tor. `is_peer_allowed_path`
only allowed `/content/<id>` (item fetches) — the catalog endpoint is
exactly `/content` (no trailing slash), so it 404'd over the FIPS peer
listener. A FIPS 404 was also treated as a successful response, so the dial
never retried Tor. Fixes: allow `/content` over the mesh; add
`fips_should_fall_back()` so a FIPS 404/5xx in Auto mode falls back to Tor
(handles version-skew peers reaching a different route). Also correct the
reconnect hint text — the public anchor is TCP/8443, not UDP/8668.
Federation: deleted nodes reappeared because transitive discovery
(`merge` of a peer's advertised trusted peers) re-added any unknown DID.
Add a tombstone store (`removed-nodes.json`): remove_node tombstones the
DID, transitive merge skips tombstoned DIDs, and a remote-triggered
peer-joined is ignored for a removed DID. Explicit local re-add (add_node)
clears the tombstone.
UI: the app credentials modal panel stretched edge-to-edge (height:100%,
max-width:none, items-stretch overlay). Constrain it to a centered card
(max-width 34rem, rounded, dimmed full-screen backdrop) matching the
AppIconGrid / wallet-receive modal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The whole fleet was silently never reaching the FIPS mesh: the default
public anchor was configured as fips.v0l.io:8668/udp, but the anchor only
answers on TCP/8443. Fix the default to 185.18.221.160:8443/tcp (IPv4
literal — the hostname resolves IPv6-first and the daemon binds v4-only,
which fails the handshake with EAFNOSUPPORT), and auto-seed it in
anchors::load() so every node dials it without operator action (removal
still persists). Proven live on .116: cold start → anchor_connected in
~400ms, anchor became mesh parent.
Wire fips::update::apply() against upstream GitHub releases (stable
channel only): resolve /releases/latest → SHA256-verify the .deb against
checksums-linux.txt → install → restart. dpkg runs via `systemd-run` to
escape archipelago's ProtectSystem=strict sandbox (else /var/lib/dpkg is
read-only), with --force-confold (archipelago manages /etc/fips conffiles)
and --force-downgrade (dev builds sort newer than the stable tag).
Validated live: .116 upgraded 0.3.0-dev -> stable v0.3.0.
Also: standalone fips-ui dashboard app (apps/fips-ui + docker/fips-ui,
static nginx proxying /rpc/v1 same-origin, copiable own-anchor address);
reserve UI port 8336; register fips/fips-ui as platform-managed. Includes
the Lightning wallet cross-origin (CORS) + LND proxy auth + nginx
self-healer fix so the wallet screen connects instead of "failed to fetch".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>