release(v1.7.40-alpha): fix tarball root perms at source so OTA can't 500 again
Some checks failed
Build Archipelago ISO (dev) / build-iso (push) Failing after 11m1s

v1.7.38 and v1.7.39 both shipped with `./` inside the frontend tarball marked
drwx------ (700). Tar extraction preserves archive perms, so every node that
pulled the OTA landed with /opt/archipelago/web-ui at 700, nginx (www-data)
returned 500 "permission denied" on every page, and the browser showed
"Internal Server Error nginx". .116 hit this on both v1.7.38 and v1.7.39
rollouts. The v1.7.39 runtime self-heal in main.rs was the wrong layer —
systemd's ReadOnlyPaths namespace made /opt/archipelago read-only from inside
the archipelago service, so chmod from there returned EROFS.

Root cause: create-release-manifest.sh used mktemp -d (700 default umask) for
staging, then tar preserved that 700 in the archive's root entry.

Fix the archive itself:
- chmod 755 staging dir + `find -type d -exec chmod 755` + `-type f chmod 644`
  before tar, so the on-disk entries are correct.
- tar --owner=0 --group=0 --mode='u=rwX,go=rX' to normalize archive perms
  belt-and-braces in case file-mode drift ever reappears.
- Post-tar verify: `tar tvzf | head -1` must show drwxr-xr-x at root, or
  the release script aborts before the manifest is even generated.

Binary unchanged semantically — the main.rs self-heal stays in as a last-
resort belt (can't hurt on nodes whose FS isn't namespace-isolated), and the
update.rs in-extractor chmod stays in so v1.7.40-onwards extractors are
double-safe. The authoritative fix is the archive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-22 13:54:44 -04:00
parent 3218f71703
commit 50744952b7
8 changed files with 56 additions and 15 deletions

View File

@@ -87,8 +87,39 @@ if [ -z "$FRONTEND_ARCHIVE" ]; then
echo " Including AIUI from demo/aiui/"
cp -r "$PROJECT_ROOT/demo/aiui" "$STAGING_DIR/aiui"
fi
# Force world-readable perms on every entry BEFORE tar, so the
# archive's internal mode bits are 755/644 regardless of what
# the staging dir's umask gave us. Without this, mktemp -d
# creates the staging dir at 700, that 700 gets baked into the
# tarball's root `./` entry, and every node that extracts the
# archive ends up with /opt/archipelago/web-ui at 700 — which
# causes nginx (www-data) to return 500 "permission denied" on
# every page. Bit us on the v1.7.38 + v1.7.39 rollouts.
chmod 755 "$STAGING_DIR"
find "$STAGING_DIR" -type d -exec chmod 755 {} +
find "$STAGING_DIR" -type f -exec chmod 644 {} +
echo "Creating frontend archive $FRONTEND_ARCHIVE..."
tar -czf "$FRONTEND_ARCHIVE" -C "$STAGING_DIR" .
# --mode is a belt-and-braces in case a file's on-disk perms
# drift again; forces 755 dir / 644 file in the archive too.
tar --owner=0 --group=0 \
--mode='u=rwX,go=rX' \
-czf "$FRONTEND_ARCHIVE" \
-C "$STAGING_DIR" .
# Verify the archive root entry is world-readable before we
# declare success — catches regressions in tar-flag handling
# (BSD tar, busybox tar) that might silently drop --mode.
root_mode=$(tar tvzf "$FRONTEND_ARCHIVE" | head -1 | awk '{print $1}')
case "$root_mode" in
drwxr-xr-x|drwxr-x*x*)
echo " Tarball root perms OK: $root_mode"
;;
*)
echo " ERROR: tarball root perms are $root_mode (want drwxr-xr-x) — aborting release"
rm -f "$FRONTEND_ARCHIVE"
rm -rf "$STAGING_DIR"
exit 1
;;
esac
rm -rf "$STAGING_DIR"
fi
fi