fix: preserve apps and diagnostics when first-boot setup retries

This commit is contained in:
archipelago
2026-10-05 17:21:08 -04:00
parent a902cc84fe
commit a6b9e7ab49
4 changed files with 103 additions and 5 deletions
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Execute unbundled first-boot retry with temporary paths and fake system commands."""
import os
from pathlib import Path
import subprocess
import tempfile
root = Path(__file__).resolve().parents[2]
source = (root / 'scripts/first-boot-containers.sh').read_text()
# Exercise the real early-exit path, excluding the unrelated bundled installer.
source = source.split('TARGET_IP=$(hostname -I', 1)[0]
with tempfile.TemporaryDirectory(prefix='archy-firstboot-retry-') as directory:
tmp = Path(directory)
for original, replacement in [('/var/lib/archipelago', tmp / 'data'),
('/opt/archipelago', tmp / 'opt'),
('/home/archipelago', tmp / 'home'),
('/var/log', tmp / 'logs')]:
source = source.replace(original, str(replacement))
for folder in ['data/secrets', 'data/wireguard', 'opt', 'logs']:
(tmp / folder).mkdir(parents=True, exist_ok=True)
(tmp / 'opt/.unbundled').touch()
for name in ['bitcoin-rpc-password', 'mempool-db-password',
'btcpay-db-password', 'mysql-root-db-password']:
(tmp / 'data/secrets' / name).write_text('fixture-preserved')
(tmp / 'data/wireguard/private.key').write_text('fixture-preserved')
candidate = tmp / 'firstboot.sh'
candidate.write_text(source)
# Functions take precedence over host commands. Unexpected privileged work
# fails, and no real Podman/systemd command can run through these stubs.
harness = r'''
id() { if [ "$*" = '-u' ]; then echo 0; else echo 1000; fi; }
chown() { :; }
loginctl() { :; }
modprobe() { :; }
systemctl() { :; }
ufw() { echo 'Status: inactive'; }
openssl() { echo 'unexpected credential rotation' >&2; return 99; }
runuser() {
printf '%s\n' "$*" >> "$TRACE"
case "$*" in
*'podman system migrate'*) return 99 ;;
*'podman container exists filebrowser'*) return 0 ;;
*'podman ps -a'*) echo fedimint-clientd; return 0 ;;
*'podman network create archy-net'*) return 0 ;;
*) echo 'unexpected system command' >&2; return 99 ;;
esac
}
export -f id chown loginctl modprobe systemctl ufw openssl runuser
bash "$CANDIDATE"
'''
before = {str(p): p.read_bytes() for p in (tmp / 'data').rglob('*') if p.is_file()}
for attempt in range(2):
trace = tmp / f'trace-{attempt}'
result = subprocess.run(['bash', '-c', harness], capture_output=True,
text=True, timeout=15, env=os.environ | {
'CANDIDATE': str(candidate), 'TRACE': str(trace),
'ARCHY_REGISTRY': 'fixture.invalid',
'BITCOIN_KNOTS_IMAGE': 'fixture.invalid/bitcoin',
})
assert result.returncode == 0, result.stderr
assert not result.stderr, result.stderr
assert 'Unbundled first-boot complete' in result.stdout, result.stdout
assert 'system migrate' not in trace.read_text(), trace.read_text()
assert all(Path(p).read_bytes() == content for p, content in before.items())
print('PASS repeated unbundled setup logs correctly without stopping apps or rotating stored secrets')