release(v1.7.39-alpha): hotfix web-ui perms after OTA (nginx 500) + startup self-heal

v1.7.38 shipped with an OTA bug: the tar-extracted staging dir inherited 700
perms and nginx (www-data) returned 500/403 on every request after the swap.
.116 hit this on rollout; had to chmod by hand to recover.

- update.rs: after extraction, explicitly chmod 755 dirs + 644 files on the
  new staging dir before the mv into place, so nginx can stat/serve them.
- main.rs: self-heal on startup — if /opt/archipelago/web-ui is not
  world-readable, run `sudo chmod -R u=rwX,go=rX` to repair. This is what
  rescues nodes upgrading from v1.7.37/v1.7.38, since their extractor
  (running on the old binary) doesn't have the chmod fix yet — the new
  binary's first boot fixes the mess before nginx serves a single request.

Everything v1.7.38 shipped is still in this release:
- auth.rs auto-heals is_onboarding_complete() from setup_complete +
  password_hash so nodes don't bounce back to /onboarding/intro after
  browser clear / reboot / update
- useOnboarding tri-state: backend-unreachable no longer defaults to intro
- login sounds gated by isFirstInstallPhase() — silent after onboarding,
  typing sounds unaffected
- FIPS app / Nostr Relay / Nostr VPN / Routstr / Penpot removed from
  catalog + frontend + Rust + docker + icons; 15 image versions deleted
  from tx1138, .168, gitea-local
- AIUI baked into release tarball via demo/aiui/
- prebuild hook syncs app-catalog/catalog.json → public/catalog.json

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-22 13:26:54 -04:00
co-authored by Claude Opus 4.7
parent 36a6101026
commit b8d084368e
6 changed files with 58 additions and 3 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "archipelago"
version = "1.7.37-alpha"
version = "1.7.39-alpha"
edition = "2021"
description = "Archipelago Bitcoin Node OS - Native backend"
authors = ["Archipelago Team"]
+30
View File
@@ -86,6 +86,36 @@ async fn main() -> Result<()> {
info!("Starting Archipelago Bitcoin Node OS");
// Self-heal web-ui permissions. The OTA updater in <=v1.7.38 left
// /opt/archipelago/web-ui as drwx------ (700) after the atomic
// swap — nginx (www-data) then returned 500/403 on every request
// until someone shelled in and chmod'd it. Check on every boot
// and repair if needed so a node auto-recovers after the next
// service restart that follows a broken OTA.
tokio::spawn(async move {
use std::os::unix::fs::PermissionsExt;
let web_ui = std::path::Path::new("/opt/archipelago/web-ui");
if let Ok(meta) = tokio::fs::metadata(web_ui).await {
let mode = meta.permissions().mode() & 0o777;
if mode & 0o005 != 0o005 {
tracing::warn!(
"web-ui perms {:o} not world-readable — self-healing",
mode
);
let _ = tokio::process::Command::new("sudo")
.args([
"-n",
"chmod",
"-R",
"u=rwX,go=rX",
"/opt/archipelago/web-ui",
])
.status()
.await;
}
}
});
// Load configuration
let config = Config::load().await?;
info!("📁 Data directory: {}", config.data_dir.display());
+15
View File
@@ -914,6 +914,21 @@ pub async fn apply_update(data_dir: &Path) -> Result<()> {
])
.await;
// Set world-readable perms so nginx (runs as www-data)
// can stat + serve the files. Without this, the tar
// extraction inherits the staging-dir's 700 mode and
// nginx returns 403/500 for every request after the
// swap — exactly what bit .116 on the v1.7.38 rollout.
let _ = host_sudo(&["chmod", "755", &staging_new]).await;
let _ = host_sudo(&[
"find", &staging_new, "-type", "d", "-exec", "chmod", "755", "{}", "+",
])
.await;
let _ = host_sudo(&[
"find", &staging_new, "-type", "f", "-exec", "chmod", "644", "{}", "+",
])
.await;
// Preserve paths that are installed outside the Vue build
// (baked in by the ISO or sibling installers) and so
// aren't in the new tarball. Without this copy, every OTA