feat: harden identity and recovery operations
This commit is contained in:
33
ops/backup-postgres.sh
Executable file
33
ops/backup-postgres.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
umask 077
|
||||
|
||||
backup_directory="${1:-storage/app/backups}"
|
||||
mkdir -p "$backup_directory"
|
||||
|
||||
database_name="$(docker compose exec -T postgres printenv POSTGRES_DB)"
|
||||
database_user="$(docker compose exec -T postgres printenv POSTGRES_USER)"
|
||||
|
||||
if [[ ! "$database_name" =~ ^[A-Za-z0-9_]+$ ]] || [[ ! "$database_user" =~ ^[A-Za-z0-9_]+$ ]]; then
|
||||
echo "Nome de base de dados ou utilizador inválido." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
backup_path="${backup_directory%/}/reserva-${timestamp}.dump"
|
||||
temporary_path="${backup_path}.partial"
|
||||
|
||||
docker compose exec -T postgres pg_dump \
|
||||
--username="$database_user" \
|
||||
--dbname="$database_name" \
|
||||
--format=custom \
|
||||
--no-owner \
|
||||
--no-privileges > "$temporary_path"
|
||||
|
||||
docker compose exec -T postgres pg_restore --list < "$temporary_path" > /dev/null
|
||||
mv "$temporary_path" "$backup_path"
|
||||
shasum -a 256 "$backup_path" > "${backup_path}.sha256"
|
||||
|
||||
echo "$backup_path"
|
||||
51
ops/test-restore-postgres.sh
Executable file
51
ops/test-restore-postgres.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
backup_path="${1:-}"
|
||||
|
||||
if [[ -z "$backup_path" ]] || [[ ! -f "$backup_path" ]]; then
|
||||
echo "Utilização: $0 <ficheiro.dump>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
database_user="$(docker compose exec -T postgres printenv POSTGRES_USER)"
|
||||
restore_database="reserva_restore_$(date -u +%Y%m%d%H%M%S)_$$"
|
||||
|
||||
if [[ ! "$database_user" =~ ^[A-Za-z0-9_]+$ ]] || [[ ! "$restore_database" =~ ^reserva_restore_[0-9_]+$ ]]; then
|
||||
echo "Identificador de restauro inválido." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
docker compose exec -T postgres dropdb \
|
||||
--username="$database_user" \
|
||||
--if-exists \
|
||||
"$restore_database" > /dev/null
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
docker compose exec -T postgres createdb \
|
||||
--username="$database_user" \
|
||||
"$restore_database"
|
||||
|
||||
docker compose exec -T postgres pg_restore \
|
||||
--username="$database_user" \
|
||||
--dbname="$restore_database" \
|
||||
--no-owner \
|
||||
--no-privileges < "$backup_path"
|
||||
|
||||
migration_count="$(docker compose exec -T postgres psql \
|
||||
--username="$database_user" \
|
||||
--dbname="$restore_database" \
|
||||
--tuples-only \
|
||||
--no-align \
|
||||
--command='select count(*) from migrations')"
|
||||
|
||||
if [[ ! "$migration_count" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "O restauro não contém o histórico de migrations esperado." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Restauro validado em base temporária (${migration_count} migrations)."
|
||||
Reference in New Issue
Block a user