#!/usr/bin/env bash # Sync the published apt tree to Cloudflare R2 (served as apt.nucleic.blakeslee.xyz; # NAROS.md §3.2). # Uses rclone's S3 backend with env-provided credentials (CI secrets): # R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET (default naros-apt) # R2_JURISDICTION (optional: default, eu, or fedramp) set -euo pipefail OS_DIR="$(cd "$(dirname "$0")/.." && pwd)" REPO="$OS_DIR/dist/repo" : "${R2_ACCOUNT_ID:?}" "${R2_ACCESS_KEY_ID:?}" "${R2_SECRET_ACCESS_KEY:?}" BUCKET="${R2_BUCKET:-naros-apt}" [ -d "$REPO" ] || { echo "no repo at $REPO — run repo/publish.sh first" >&2; exit 2; } if [[ ! "$R2_ACCOUNT_ID" =~ ^[[:xdigit:]]{32}$ ]]; then echo "R2_ACCOUNT_ID must be the 32-character Cloudflare account ID" >&2 exit 2 fi case "${R2_JURISDICTION:-default}" in default) ENDPOINT="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" ;; eu|fedramp) ENDPOINT="https://${R2_ACCOUNT_ID}.${R2_JURISDICTION}.r2.cloudflarestorage.com" ;; *) echo "R2_JURISDICTION must be default, eu, or fedramp" >&2; exit 2 ;; esac # /dev/null is intentional: this remote is configured entirely through environment # variables, so rclone must not search for (and warn about) rclone.conf. export RCLONE_CONFIG=/dev/null \ RCLONE_CONFIG_R2_TYPE=s3 \ RCLONE_CONFIG_R2_PROVIDER=Cloudflare \ RCLONE_CONFIG_R2_ACCESS_KEY_ID="$R2_ACCESS_KEY_ID" \ RCLONE_CONFIG_R2_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY" \ RCLONE_CONFIG_R2_ENDPOINT="$ENDPOINT" \ RCLONE_CONFIG_R2_REGION=auto \ RCLONE_CONFIG_R2_ACL=private \ RCLONE_CONFIG_R2_NO_CHECK_BUCKET=true # pool/ first, dists/ last: clients never see an index referencing a not-yet-uploaded deb. rclone copy "$REPO/pool" "r2:$BUCKET/pool" --checksum rclone sync "$REPO/dists" "r2:$BUCKET/dists" --checksum echo "synced $REPO -> r2:$BUCKET"