All checks were successful
Build and deploy / Validate source (push) Successful in 8s
Build and deploy / Integration suite on a real stack (push) Successful in 3m38s
Build and deploy / Secret scan and release gate (push) Successful in 7s
Build and deploy / Publish images (push) Successful in 1m2s
A backup service runs pg_dump every day at 03:00 Brasília, checks the archive, encrypts it with age to a public key and uploads it with a token for that bucket only. The server cannot read or delete backups: the private key stays with the owner, the bucket's lifecycle rule expires copies and its lock stops early deletion. Each run is recorded and shown on the Kanban's Integrations tab. tests/backup_test.py backs up, restores into a scratch database and compares the rows in CI. Setup and restore: docs/BACKUP.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34 lines
2.1 KiB
Bash
34 lines
2.1 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
case "$S3_BUCKET" in *[!a-z0-9.-]*|'') echo 'Invalid local bucket name' >&2; exit 1;; esac
|
|
if [ "$MINIO_ROOT_USER" = "$S3_APP_USER" ]; then echo 'Runtime storage user must not be root' >&2; exit 1; fi
|
|
# Disposable local secrets are passed via environment, never traced/logged.
|
|
mc alias set local http://storage:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null
|
|
mc mb --ignore-existing "local/$S3_BUCKET" >/dev/null
|
|
mc anonymous set none "local/$S3_BUCKET" >/dev/null
|
|
mc admin user add local "$S3_APP_USER" "$S3_APP_PASSWORD" >/dev/null
|
|
# Use shell builtins only: the minimal MinIO image does not ship sed/cat.
|
|
policy=''
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
while [ "${line#*dtf-local-artwork}" != "$line" ]; do
|
|
policy="$policy${line%%dtf-local-artwork*}$S3_BUCKET"
|
|
line=${line#*dtf-local-artwork}
|
|
done
|
|
policy="$policy$line
|
|
"
|
|
done < /policy.json
|
|
printf '%s' "$policy" > /tmp/policy.json
|
|
mc admin policy create local dtf-artwork /tmp/policy.json >/dev/null
|
|
mc admin policy attach local dtf-artwork --user "$S3_APP_USER" >/dev/null
|
|
mc ilm import "local/$S3_BUCKET" < /lifecycle.json
|
|
# The backup bucket and its own account, which can write and read backups but
|
|
# not delete them: the same separation as the backup token on R2.
|
|
case "$S3_BACKUP_BUCKET" in *[!a-z0-9.-]*|'') echo 'Invalid local backup bucket name' >&2; exit 1;; esac
|
|
mc mb --ignore-existing "local/$S3_BACKUP_BUCKET" >/dev/null
|
|
mc anonymous set none "local/$S3_BACKUP_BUCKET" >/dev/null
|
|
mc admin user add local "$S3_BACKUP_USER" "$S3_BACKUP_PASSWORD" >/dev/null
|
|
printf '%s' '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:ListBucket","s3:GetBucketLocation"],"Resource":["arn:aws:s3:::'"$S3_BACKUP_BUCKET"'"]},{"Effect":"Allow","Action":["s3:GetObject","s3:PutObject","s3:AbortMultipartUpload","s3:ListMultipartUploadParts"],"Resource":["arn:aws:s3:::'"$S3_BACKUP_BUCKET"'/*"]}]}' > /tmp/backup-policy.json
|
|
mc admin policy create local dtf-backup /tmp/backup-policy.json >/dev/null
|
|
mc admin policy attach local dtf-backup --user "$S3_BACKUP_USER" >/dev/null
|
|
echo 'Local storage runtime account provisioned.'
|