86 lines
3.2 KiB
Bash
Executable file
86 lines
3.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
|
tmp="$(mktemp -d)"
|
|
trap 'rm -rf -- "$tmp"' EXIT
|
|
|
|
awk '/^ cat > "\$BACKUP_RUNNER" <<.BACKUP_RUNNER_EOF/ { copying=1; next }
|
|
copying && /^BACKUP_RUNNER_EOF$/ { exit }
|
|
copying { print }' ochenstarik-server-backup-7.sh > "$tmp/runner"
|
|
awk '/^\[\[ "\$EUID"/ { exit } { print }' "$tmp/runner" > "$tmp/runner-functions"
|
|
bash -n "$tmp/runner-functions"
|
|
source "$tmp/runner-functions"
|
|
|
|
# Exercise the real create_backup early-return path with only the SSH transport
|
|
# replaced. This never connects to a host or reads the real filesystem.
|
|
protect_initial_files() { :; }
|
|
mkdir -p "$tmp/bin"
|
|
cat > "$tmp/bin/scp" <<'SCP_STUB'
|
|
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
printf '%s\n' "$*" >> "$SCP_CALLS"
|
|
exit "${SCP_EXIT_CODE:-0}"
|
|
SCP_STUB
|
|
chmod +x "$tmp/bin/scp"
|
|
export PATH="$tmp/bin:$PATH" SCP_CALLS="$tmp/scp-calls"
|
|
|
|
BACKUP_ROOT="$tmp/encrypted-root"
|
|
BACKUP_ENCRYPTION=age
|
|
AGE_RECIPIENT='age1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'
|
|
OFFSITE_TARGET='backup@example.test'
|
|
OFFSITE_PATH='/srv/backups'
|
|
OFFSITE_KNOWN_HOSTS="$tmp/known_hosts"
|
|
mkdir -p "$BACKUP_ROOT/initial"
|
|
touch "$OFFSITE_KNOWN_HOSTS"
|
|
archive="$BACKUP_ROOT/initial/initial-20261023-120000.tar.zst.age"
|
|
printf 'ciphertext fixture\n' > "$archive"
|
|
(
|
|
cd "$BACKUP_ROOT/initial"
|
|
sha256sum "$(basename "$archive")" > "$(basename "$archive").sha256"
|
|
)
|
|
checksum="${archive}.sha256"
|
|
|
|
# A failed first offsite upload must leave both immutable local files intact,
|
|
# return failure, and retry those exact files on the next invocation.
|
|
if (SCP_EXIT_CODE=42 create_backup initial 0) > "$tmp/failed.out" 2>&1; then
|
|
printf 'Initial offsite failure was accepted as success.\n' >&2
|
|
exit 1
|
|
fi
|
|
if grep -Fq 'Первичный снимок уже существует' "$tmp/failed.out"; then
|
|
printf 'Failed upload was reported as a successful existing backup.\n' >&2
|
|
exit 1
|
|
fi
|
|
[[ -f "$archive" && -f "$checksum" ]]
|
|
(
|
|
cd "$BACKUP_ROOT/initial"
|
|
sha256sum --check --status "$(basename "$checksum")"
|
|
)
|
|
[[ "$(wc -l < "$SCP_CALLS")" == 1 ]]
|
|
grep -Fq -- "$archive" "$SCP_CALLS"
|
|
grep -Fq -- "$checksum" "$SCP_CALLS"
|
|
|
|
create_backup initial 0 > "$tmp/retry.out"
|
|
grep -Fq 'Первичный снимок уже существует' "$tmp/retry.out"
|
|
[[ "$(wc -l < "$SCP_CALLS")" == 2 ]]
|
|
[[ "$(sha256sum "$archive" | awk '{print $1}')" == \
|
|
"$(cd "$BACKUP_ROOT/initial" && sha256sum --check --status "$(basename "$checksum")" && sha256sum "$(basename "$archive")" | awk '{print $1}')" ]]
|
|
|
|
# Selecting age cannot silently accept an existing plaintext initial snapshot.
|
|
plain_root="$tmp/plain-root"
|
|
mkdir -p "$plain_root/initial"
|
|
plain_archive="$plain_root/initial/initial-20261022-120000.tar.zst"
|
|
printf 'plaintext fixture\n' > "$plain_archive"
|
|
(
|
|
cd "$plain_root/initial"
|
|
sha256sum "$(basename "$plain_archive")" > "$(basename "$plain_archive").sha256"
|
|
)
|
|
BACKUP_ROOT="$plain_root"
|
|
if (create_backup initial 0) > "$tmp/plain.out" 2>&1; then
|
|
printf 'Age policy silently accepted an existing plaintext snapshot.\n' >&2
|
|
exit 1
|
|
fi
|
|
grep -Fq 'уже создан без шифрования' "$tmp/plain.out"
|
|
[[ -f "$plain_archive" && "$(wc -l < "$SCP_CALLS")" == 2 ]]
|
|
|
|
printf 'Initial backup retry and encryption-policy tests passed.\n'
|