Initial commit: VaultMesh Skills collection
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>
This commit is contained in:
96
backup-sovereign/scripts/30_generate_proof.sh
Executable file
96
backup-sovereign/scripts/30_generate_proof.sh
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/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 "$@"
|
||||
Reference in New Issue
Block a user