Collection of operational skills for VaultMesh infrastructure including: - backup-sovereign: Backup and recovery operations - btc-anchor: Bitcoin anchoring - cloudflare-tunnel-manager: Cloudflare tunnel management - container-registry: Container registry operations - disaster-recovery: Disaster recovery procedures - dns-sovereign: DNS management - eth-anchor: Ethereum anchoring - gitea-bootstrap: Gitea setup and configuration - hetzner-bootstrap: Hetzner server provisioning - merkle-forest: Merkle tree operations - node-hardening: Node security hardening - operator-bootstrap: Operator initialization - proof-verifier: Cryptographic proof verification - rfc3161-anchor: RFC3161 timestamping - secrets-vault: Secrets management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
97 lines
2.5 KiB
Bash
Executable File
97 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# === METADATA ===
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# === CONFIGURATION ===
|
|
: "${OUTPUT_DIR:=$SKILL_ROOT/outputs}"
|
|
: "${NODE_NAME:=node-a}"
|
|
|
|
# === FUNCTIONS ===
|
|
log_info() { echo "[INFO] $(date -Iseconds) $*"; }
|
|
log_error() { echo "[ERROR] $(date -Iseconds) $*" >&2; }
|
|
die() { log_error "$@"; exit 1; }
|
|
|
|
b3_file() {
|
|
if command -v b3sum &>/dev/null; then
|
|
b3sum "$1" | awk '{print $1}'
|
|
else
|
|
blake3 "$1"
|
|
fi
|
|
}
|
|
|
|
b3_string() {
|
|
if command -v b3sum &>/dev/null; then
|
|
echo -n "$1" | b3sum | awk '{print $1}'
|
|
else
|
|
echo -n "$1" | blake3
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
local last_run_file="$OUTPUT_DIR/last_run_dir.txt"
|
|
[[ -f "$last_run_file" ]] || die "No last run pointer. Run 11_backup_apply.sh first."
|
|
|
|
local run_dir
|
|
run_dir="$(cat "$last_run_file")"
|
|
|
|
local manifest="$run_dir/manifest.json"
|
|
[[ -f "$manifest" ]] || die "Missing manifest: $manifest"
|
|
|
|
# Find encrypted archive
|
|
local encrypted=""
|
|
if [[ -f "$run_dir/archive.tar.gz.age" ]]; then
|
|
encrypted="$run_dir/archive.tar.gz.age"
|
|
else
|
|
die "Missing encrypted archive. Run 21_encrypt_apply.sh first."
|
|
fi
|
|
|
|
log_info "Generating proof receipts..."
|
|
log_info "Run directory: $run_dir"
|
|
|
|
# Compute BLAKE3 hashes
|
|
local manifest_b3 encrypted_b3
|
|
manifest_b3=$(b3_file "$manifest")
|
|
encrypted_b3=$(b3_file "$encrypted")
|
|
|
|
log_info "Manifest BLAKE3: $manifest_b3"
|
|
log_info "Encrypted BLAKE3: $encrypted_b3"
|
|
|
|
# Compute ROOT = BLAKE3(manifest_b3 || encrypted_b3)
|
|
# Using stable text concatenation
|
|
local concat root_b3
|
|
concat="${manifest_b3}${encrypted_b3}"
|
|
root_b3=$(b3_string "$concat")
|
|
|
|
log_info "ROOT BLAKE3: $root_b3"
|
|
|
|
# Write ROOT.txt
|
|
echo "$root_b3" > "$run_dir/ROOT.txt"
|
|
log_info "Wrote: $run_dir/ROOT.txt"
|
|
|
|
# Write PROOF.json
|
|
cat > "$run_dir/PROOF.json" <<EOF
|
|
{
|
|
"version": 1,
|
|
"node": "$NODE_NAME",
|
|
"created_at": "$(date -Iseconds)",
|
|
"artifacts": {
|
|
"manifest_blake3": "$manifest_b3",
|
|
"encrypted_archive_blake3": "$encrypted_b3",
|
|
"root_blake3": "$root_b3"
|
|
},
|
|
"computation": "ROOT = BLAKE3(manifest_blake3 || encrypted_archive_blake3)",
|
|
"notes": "ROOT can be anchored via merkle-forest/rfc3161-anchor skills."
|
|
}
|
|
EOF
|
|
log_info "Wrote: $run_dir/PROOF.json"
|
|
|
|
log_info "Proof generation complete."
|
|
log_info "Next: ./scripts/40_verify_backup.sh"
|
|
}
|
|
|
|
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"
|