@@ -3513,6 +3513,22 @@ assert_rc "plaintext archive still restores" "$rc" "0"
35133513assert_eq " plaintext restore brings back the Caddyfile" " $( cat " $BK /Caddyfile" ) " " CADDY-ORIG"
35143514rm -f " $BK " /backups/pithead-backup-*
35153515
3516+ # 6b) Truncated plaintext archive (#549): mirrors the encrypted-branch tamper/truncation check
3517+ # (4b above) on the gzip path — a truncated archive must be rejected by a full-stream `tar -tzf`
3518+ # verify BEFORE extraction, with nothing written, instead of half-overwriting config.json/.env.
3519+ out=" $( cd " $BK " && PATH=" $BK /bin:$PATH " ./pithead backup -y --no-encrypt 2>&1 ) "
3520+ plain_trunc_src=" $( ls " $BK " /backups/pithead-backup-* .tar.gz 2> /dev/null | head -1) "
3521+ config_before=" $( cat " $BK /config.json" ) "
3522+ env_before=" $( cat " $BK /.env" ) "
3523+ head -c " $(( $(wc - c < "$plain_trunc_src ") / 2 )) " " $plain_trunc_src " > " $BK /backups/truncated-plain.tar.gz"
3524+ out=" $( cd " $BK " && PATH=" $BK /bin:$PATH " ./pithead restore -y " $BK /backups/truncated-plain.tar.gz" 2>&1 ) "
3525+ rc=$?
3526+ [ " $rc " -ne 0 ] && ok " truncated plaintext archive exits non-zero" || bad " truncated plaintext archive exits non-zero" " rc=0"
3527+ assert_contains " truncated plaintext archive names integrity failure" " $out " " integrity"
3528+ assert_eq " truncated plaintext archive leaves config.json untouched" " $( cat " $BK /config.json" ) " " $config_before "
3529+ assert_eq " truncated plaintext archive leaves .env untouched" " $( cat " $BK /.env" ) " " $env_before "
3530+ rm -f " $BK " /backups/pithead-backup-* " $BK /backups/truncated-plain.tar.gz"
3531+
35163532# 7) A failed encrypted backup (openssl dies mid-stream) removes the partial archive.
35173533cat > " $BK /bin/openssl" << 'EOF '
35183534#!/usr/bin/env bash
@@ -3542,6 +3558,51 @@ rc=$?
35423558assert_contains " encrypted restore w/o passphrase explains" " $out " " PITHEAD_BACKUP_PASSPHRASE"
35433559rm -f " $BK " /backups/pithead-backup-*
35443560
3561+ echo " == black-box: failed plaintext backup restarts a running stack, removes the partial archive (#551) =="
3562+ # Companion to the #549 test above: a failed tar must not strand the stack stopped, nor leave a
3563+ # partial (root-owned) archive that looks like a valid backup. Shadow tar to fail unconditionally
3564+ # and simulate a RUNNING stack (was_running=1), so the failure path must call stack_up for real —
3565+ # proven here by "compose up" showing up in the docker log, not by stubbing stack_up away.
3566+ FB=" $SANDBOX /failbackup"
3567+ mkdir -p " $FB /build/tari" " $FB /data/tor" " $FB /data/dashboard" " $FB /bin"
3568+ cp " $STACK " " $FB /pithead"
3569+ cp " $ROOT /build/tari/config.toml.template" " $FB /build/tari/"
3570+ cat > " $FB /bin/docker" << 'EOF '
3571+ #!/usr/bin/env bash
3572+ echo "[docker] $*" >>"${DOCKER_LOG:-/dev/null}"
3573+ case "$*" in
3574+ "compose ps --status running -q") echo cid123 ;; # non-empty -> stack treated as RUNNING
3575+ esac
3576+ exit 0
3577+ EOF
3578+ cat > " $FB /bin/sudo" << 'EOF '
3579+ #!/usr/bin/env bash
3580+ [ "$1" = "chown" ] && exit 0
3581+ exec "$@"
3582+ EOF
3583+ cat > " $FB /bin/tar" << 'EOF '
3584+ #!/usr/bin/env bash
3585+ exit 1
3586+ EOF
3587+ chmod +x " $FB /bin/docker" " $FB /bin/sudo" " $FB /bin/tar"
3588+ cat > " $FB /.env" << EOF
3589+ MONERO_ONION_ADDRESS=mona.onion
3590+ TARI_ONION_ADDRESS=taria.onion
3591+ P2POOL_ONION_ADDRESS=p2pa.onion
3592+ PROXY_AUTH_TOKEN=FBTOKEN
3593+ HOST_IP=box.lan
3594+ DEPLOYMENT_COMPLETED=true
3595+ COMPOSE_PROFILES=local_node
3596+ EOF
3597+ printf ' { "monero": {"mode":"local","wallet_address":"%s","node_username":"u","node_password":"p"}, "tari":{"wallet_address":"T"}, "p2pool":{"pool":"main"}, "dashboard":{"secure":true,"host":"box.lan"} }\n' " $WALLET " > " $FB /config.json"
3598+
3599+ out=" $( cd " $FB " && DOCKER_LOG=" $FB /docker.log" PATH=" $FB /bin:$PATH " ./pithead backup -y --no-encrypt 2>&1 ) "
3600+ rc=$?
3601+ [ " $rc " -ne 0 ] && ok " failed plaintext backup (running stack) exits non-zero" || bad " failed plaintext backup (running stack) exits non-zero" " rc=0"
3602+ assert_contains " failed plaintext backup names the cause" " $out " " partial archive was removed"
3603+ assert_eq " failed plaintext backup leaves no archive behind" " $( ls " $FB " /backups/pithead-backup-* 2> /dev/null | head -1) " " "
3604+ assert_contains " failed plaintext backup restarts the stack" " $( cat " $FB /docker.log" 2> /dev/null) " " compose up"
3605+
35453606echo " == black-box: reset-dashboard targets .env dirs, not config.json (#139) =="
35463607# reset-dashboard must wipe the LIVE deployment's data dirs (from .env), not a path the user may
35473608# have edited into config.json without applying. docker = noop; sudo only LOGS (never executes the
0 commit comments