TASK-17: Deploy script auto-tags successful clean deploys with next
alpha version number. Skips if commit already tagged or working tree
is dirty.
BUG-3: Updated IndeedHub submodule — removed dead nostrConfig with
hardcoded ws://localhost:7777 that caused WebSocket reconnection spam
in browser console. Relay detection via relay.ts (auto-detect /relay
proxy) is the active path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Background task spawned on server startup: every 15 minutes, checks opt-in
status, builds anonymous health report (node ID hash, version, uptime,
CPU/RAM/disk %, container states, recent alerts), saves to disk, and POSTs
to TELEMETRY_COLLECTOR_URL env var if configured. Non-fatal on failure.
Fixed FiredAlert field references (kind not rule_type, timestamp not
fired_at) in both monitoring and analytics modules.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests expected router.push but panel mode (now default) uses panelAppId
store state instead. Updated assertions to check panelAppId. Fixed
BTCPay app ID from 'btcpay' to 'btcpay-server'. All 515 tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: telemetry.report RPC builds anonymous health report with node ID
(SHA-256 hash of pubkey, truncated), version, uptime, container states,
CPU/RAM, federation peers, and recent alerts. Saves latest report to disk.
Requires analytics opt-in (existing analytics.enable/disable flow).
Frontend: "Beta Telemetry" section in Settings with enable/disable toggle.
Shows what data is and isn't collected. Mock backend handles all analytics
and telemetry RPCs.
Privacy: No wallet data, no private keys, no DIDs, no IP addresses.
Node identified by truncated hash only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Health endpoint now returns JSON with version and service status instead
of plain "OK". Updated BETA-PROGRESS.md: BUG-1 done, TASK-8 done (12/12
+ code audit), FEATURE-4 at ~80%, overall at ~55%. Added session #5 log.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaced single hardcoded release note with scrollable history of all
alpha releases (alpha.1 through alpha.9). Each release has version badge,
date, and categorized highlights. Inner container scrolls independently
with max-height 85vh. Current release highlighted with orange badge,
older releases in muted style with left border timeline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Password hashing migrated from bcrypt to Argon2id (m=64MiB, t=3, p=4).
Transparent upgrade: on successful bcrypt login, re-hashes with Argon2id
and persists. New signups and password changes use Argon2id directly.
Unifies crypto stack — Argon2id was already used for TOTP and backup KDF.
Bitcoin RPC password: no longer falls back to hardcoded "archipelago123".
On first boot, generates a random 32-char hex password from CSPRNG,
saves to /var/lib/archipelago/secrets/bitcoin-rpc-password with 0600
permissions. Existing installs with secrets file are unaffected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- RBAC: Viewer role changed from prefix "system." to explicit allowlist
of safe read-only methods. Prevents Viewer access to system.factory-reset,
system.shutdown, system.reboot, system.disk-cleanup.
- identity.create: Name/label param now enforces max 100 chars.
- sanitize_error_message: Changed from contains() to starts_with() for
prefix matching, preventing internal errors that happen to contain
user-facing keywords from leaking through.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TASK-31: Cleaned up Apps page nav header structure (tabs + categories + search).
TASK-38: Added Bitcoin Core sync progress gauge to homepage System Stats card —
shows sync percentage, block height, and green/orange color coding. Only
appears when Bitcoin is running. Grid expands to 4 columns when visible.
Updated MASTER_PLAN.md — cleaned up completed sections, moved done items.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BUG-1 (P0): CSRF tokens now HMAC-derived from session token instead of
random — survives backend restarts, eliminates cookie/header race conditions.
Frontend retries 403s as belt-and-suspenders.
TASK-8 H2: federation.peer-joined verifies ed25519 signature on join messages.
TASK-8 H3: federation.peer-address-changed requires signed proof from known peer.
TASK-8 H4: Rust backend default bind 0.0.0.0 → 127.0.0.1 (nginx proxies all).
BUG-20: ElectrumX index estimate string fixed from ~55GB to ~130GB.
BUG-37: App card Start/Stop buttons split into loading vs interactive states
to prevent WebSocket state flicker during container scans.
BUG-40: Uninstall modal uses Teleport to body with z-[3000] for full overlay.
BUG-41: Uninstalling overlay on card + optimistic store removal.
Updated MASTER_PLAN.md and BETA-PROGRESS.md to reflect all completed work.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch docker-compose from regtest to signet, add standalone testnet stack
(docker-compose.testnet.yml) with Bitcoin+LND+ThunderHub+Fedimint. Mock
backend now auto-detects Podman/Docker sockets and includes full LND/Lightning
RPC mocks. Dev scripts refactored with boot mode, testnet option, and macOS
EAGAIN fix for port cleanup. Added dev faucet button to Home.vue.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- BUG-33: CPU load alert threshold increased from 2x to 4x core count
(8→16 on 4-core machine) to reduce false alerts during container ops
- TASK-27: Launch buttons for new-tab apps now show external link icon
(BTCPay, Grafana, PhotoPrism, Portainer, OnlyOffice, etc.)
- TASK-36: Iframe error screen now distinguishes between X-Frame-Options
blocked vs container not reachable, with appropriate messaging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Boot screen (BootScreen.vue) is already fully production-integrated:
- RootRedirect health checks → shows boot screen if server down
- Polls /rpc/v1 until healthy → transitions to login/onboarding
- Kiosk launcher loads browser immediately, boot screen handles wait
- All audio/icon assets deployed to /opt/archipelago/web-ui/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mobile mesh had overflow:hidden inherited from desktop layout,
preventing scrolling. Added overflow:visible override for mobile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mobile mesh view uses 0 top padding so the Dashboard's mobileTabPaddingTop
takes effect correctly (pushes content below fixed tab bar).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Mesh: remove display:flex from .mesh-header CSS that overrode
Tailwind hidden class, causing title/peers to show on mobile
- Federation: add title={did} on node name for hover tooltip
- Cloud: add title={did} on peer name for hover tooltip
- Both already show node.name when available, DID as fallback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reverted inline-style sticky header. The hack used hardcoded rgba
background that didn't match across screens and shifted position
between tabs. Will implement properly with a shared layout component.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
My Apps/App Store/Services tabs, category filters, and search bar
now stay fixed at the top on scroll using sticky positioning with
glass-blur background. Applied to both Apps.vue and Marketplace.vue
desktop views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reordered receive method tabs from [Lightning, On-Chain, Ecash] to
[On-Chain, Lightning, Ecash] in both ReceiveBitcoinModal and Web5
view. Default selection changed to 'onchain'.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mobile mesh view had padding: 0 causing glass cards to go edge-to-edge.
Added 12px padding for consistent gutters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added fedimintd to the metadata map with title "Fedimint Guardian"
and description clarifying it's the federation consensus node.
Shares the fedimint.png icon.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When ElectrumX is indexing and can't accept TCP connections, the UI
now shows the actual index size (e.g. "126.9 GB") in the Indexed
Height field instead of a generic "Building..." label. Also shows
the size in the status message for better progress visibility.
Updated estimated full index size from 55GB to 130GB (2026 mainnet).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fedimintd serves JSON-RPC API on 8174 and Guardian web UI on 8175.
Updated all port mappings: frontend AppSession, nginx HTTP/HTTPS
proxies, PodmanClient static map.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dynamic port extraction from container bindings, falling back to the
static PodmanClient address map for apps without port bindings (e.g.
host-network containers).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- Remove most hardcoded port overrides from docker_packages.rs, use
dynamic port extraction from actual container bindings with fallback
to static map in PodmanClient
- Fix OnlyOffice (8044), NginxPM (8181), Fedimint (8174) port mappings
- Remove Tailscale fake web UI port (no web UI)
- ElectrumX: detect "Connection reset" as syncing state (not error)
Deploy script:
- Auto-configure sysctl unprivileged_port_start=80 for rootless
- Auto-enable loginctl linger for container persistence
- Auto-enable podman.socket for Portainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extended INSTALLED_ALIASES to cover all container name variants so
marketplace correctly shows "Already Installed" for every deployed app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Correct off-by-one in UID mapping: container UID N → host UID
(100000 + N - 1), not (100000 + N)
- Deploy script auto-fixes UID ownership on every deploy
- Bitcoin UI nginx uses __BITCOIN_RPC_AUTH__ placeholder injected
from secrets at deploy time
- container rules updated for rootless podman architecture
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bitcoin UI nginx: use __BITCOIN_RPC_AUTH__ placeholder, injected at
deploy time from secrets file (fixes auth prompt regression)
- Deploy script: sed-replaces placeholder with real base64 RPC creds
before building bitcoin-ui Docker image
- Container state: "created" → "stopped" (not "starting") so ollama/
tailscale show correctly
- Comprehensive INSTALLED_ALIASES for marketplace
All container credentials now flow from secrets files through the
deploy script. Manual container recreation is no longer needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add automatic UID mapping fix to deploy script: uses sudo chown to
set host UIDs matching rootless podman's subuid mapping (container
UID 0→100000, 70→100070, 101→100101, 472→100472, 999→100999)
- Fix rpcallowip: rootless podman uses 10.89.0.0/16 not 10.88.0.0/16,
changed to 0.0.0.0/0 (safe: only accessible via port mapping)
- ProtectHome=no + no PrivateTmp: rootless podman needs shared /tmp
and writable ~/.local/share/containers
All 22 containers now running under rootless podman with working
Bitcoin RPC at block 941163.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RestrictNamespaces and SystemCallFilter block rootless podman from
creating user namespaces needed for container isolation. Removed these
along with RestrictSUIDSGID (implied by NoNewPrivileges). ProtectHome
set to no (rootless podman needs ~/.local/share/containers writable).
Remaining active protections: NoNewPrivileges, ProtectSystem=strict,
ReadWritePaths, RestrictAddressFamilies, MemoryDenyWriteExecute,
RestrictRealtime, SystemCallArchitectures=native.
Also reduced initial scan delay from 15s to 3s for faster container
visibility after boot, and removed Ollama from auto-deploy.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The security hardening (NoNewPrivileges, RestrictAddressFamilies,
MemoryDenyWriteExecute, RestrictRealtime, ProtectSystem=strict) all
blocked podman container management via sudo. These are temporarily
disabled until TASK-11 (rootless podman migration) is complete.
Remaining active protections: ProtectSystem=true (/usr, /boot),
ProtectHome=yes, PrivateTmp=yes, PrivateDevices=no (mesh radio).
Also adds TASK-11 to MASTER_PLAN.md for tracking the rootless podman
migration that will allow re-enabling full security hardening.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added containers_scanned flag to StatusInfo in the data model. Starts
false, set to true after the first Podman scan completes (~15s after
boot). Marketplace now shows a shimmer "Checking..." indicator on app
buttons until the scan finishes, preventing users from accidentally
re-installing apps that are already present but not yet enumerated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CARGO_PKG_VERSION already contains -alpha from Cargo.toml, so the
format!("{}-alpha", ...) was producing 1.2.0-alpha-alpha. Use the
Cargo version directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add https: to CSP frame-src so external site iframes (BotFights,
484 Kitchen, etc.) load without being blocked by Content-Security-Policy
- Show spinner + "Starting..." on marketplace cards for containers that
are booting up, preventing users from re-installing running apps
- Add spinner to transitional state badges (starting/stopping/installing)
on installed app cards in Apps view
- Add "What's New" button to Settings version card with release notes
modal covering recent highlights in layman-friendly language
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: systemd PrivateDevices=yes hid /dev/ttyUSB* from the service,
preventing .198 from connecting to its Heltec V3 after the security hardening.
Changes:
- Set PrivateDevices=no in systemd service (serial access needs physical devices;
other hardening layers remain: NoNewPrivileges, ProtectSystem, RestrictNamespaces)
- Add SupplementaryGroups=dialout for explicit serial permissions
- Add fallback auto-detect when configured serial path fails to open
- Add exponential backoff on reconnect (5s→60s cap) to reduce log spam
- Add pre-open device existence check with actionable error messages
- Add udev rule (99-mesh-radio.rules) for stable /dev/mesh-radio symlink
- Add /dev/mesh-radio to serial candidate list (checked first)
- Add Connect button per detected device in Mesh UI
- Deploy udev rule to both servers and ISO build
- Fix FEDI_HASH unbound variable in deploy script
- Fix deploy binary step to handle hung service stop gracefully
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bitcoin Knots: added -proxy=127.0.0.1:9050 for P2P connections through Tor
- LND: enabled tor.active=true, tor.socks, tor.streamisolation in lnd.conf
- Tor setup handled by existing archipelago-setup-tor.service at first boot
- .onion display and Tor toggle already present in Settings UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SecretsManager: raw key stored in Zeroizing<[u8; 32]>, auto-zeroed on drop
- SecretsManager: replaced thread_rng with OsRng (CSPRNG) for nonces
- Remember-me secret: derived from machine-id via SHA-256 (deterministic, no
plaintext key storage)
- Bitcoin ecash balance: uses checked_add with u64::MAX saturation on overflow
- TOTP setup/confirm: added to EndpointRateLimiter (3 and 5 per 5min)
- AppId validation and Tor service name validation already existed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>