#!/bin/bash # backfill-proofs.sh - Generate/upgrade OpenTimestamp proofs for all commits # Usage: backfill-proofs.sh [repository-path] set -e REPO_PATH="${1:-.}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$REPO_PATH" # Verify we're in a git repository if ! git rev-parse --git-dir > /dev/null 2>&1; then echo "Error: not a git repository" >&2 exit 1 fi # Find the generate-proof.sh script GENERATE_SCRIPT="" # Check if generate-proof.sh is in the same directory as this script if [ -f "$SCRIPT_DIR/generate-proof.sh" ]; then GENERATE_SCRIPT="$SCRIPT_DIR/generate-proof.sh" # Check in repository root elif [ -f "generate-proof.sh" ]; then GENERATE_SCRIPT="./generate-proof.sh" # Check if skill is installed globally elif [ -f "$HOME/.openclaw/workspace/skills/git-ots-hook/scripts/generate-proof.sh" ]; then GENERATE_SCRIPT="$HOME/.openclaw/workspace/skills/git-ots-hook/scripts/generate-proof.sh" else echo "Error: generate-proof.sh not found" >&2 exit 1 fi chmod +x "$GENERATE_SCRIPT" # Ensure .ots directory exists mkdir -p .ots # Cache file for attestation status (avoids repeated ots info calls) STATUS_CACHE=".ots/.attestation-cache" if [ ! -f "$STATUS_CACHE" ]; then echo "# Attestation status cache" > "$STATUS_CACHE" echo "# Format: commit-hash:status:timestamp" >> "$STATUS_CACHE" fi # Function to check cached status get_cached_status() { local commit="$1" local cache_line=$(grep "^$commit:" "$STATUS_CACHE" 2>/dev/null | tail -1) if [ -n "$cache_line" ]; then local status=$(echo "$cache_line" | cut -d: -f2) local timestamp=$(echo "$cache_line" | cut -d: -f3) local now=$(date +%s) local age=$((now - timestamp)) # Cache valid for 1 hour (3600 seconds) if [ "$age" -lt 3600 ]; then echo "$status" return 0 fi fi return 1 } # Function to cache status cache_status() { local commit="$1" local status="$2" local now=$(date +%s) echo "$commit:$status:$now" >> "$STATUS_CACHE" } echo "[ots-backfill] Scanning commit history..." # Get all commit hashes (oldest to newest) COMMITS=$(git rev-list --reverse HEAD) TOTAL=$(echo "$COMMITS" | wc -l) CURRENT=0 # Track if any proofs were updated UPDATED=0 for COMMIT in $COMMITS; do CURRENT=$((CURRENT + 1)) echo "[ots-backfill] Processing commit $CURRENT/$TOTAL: ${COMMIT:0:8}" # Check if proof exists for this commit PROOF_FILE=".ots/${COMMIT}.ots" if [ -f "$PROOF_FILE" ]; then # Check cached status first CACHED_STATUS=$(get_cached_status "$COMMIT" || echo "") if [ "$CACHED_STATUS" = "attested" ]; then echo " ✓ Already attested (cached, skipping)" continue fi # Check if already fully attested (only if not cached or cache expired) PENDING_COUNT=$(ots info "$PROOF_FILE" 2>&1 | grep -c "PendingAttestation" || echo "0") if [ "$PENDING_COUNT" -eq 0 ]; then echo " ✓ Already attested" cache_status "$COMMIT" "attested" continue fi # Cache as pending cache_status "$COMMIT" "pending" # Try to upgrade existing proof (only contacts calendars if pending) echo " Upgrading pending proof..." if ots upgrade "$PROOF_FILE" 2>/dev/null; then echo " ✓ Upgraded to attested" cache_status "$COMMIT" "attested" UPDATED=$((UPDATED + 1)) else echo " - Still pending (no upgrade available yet)" fi else # Generate new proof for this commit echo " Generating new proof..." "$GENERATE_SCRIPT" "$COMMIT" "$PROOF_FILE" >/dev/null 2>&1 echo " ✓ Generated proof" cache_status "$COMMIT" "pending" UPDATED=$((UPDATED + 1)) fi done # Create/update latest proof symlink LATEST_COMMIT=$(git rev-parse HEAD) if [ -f ".ots/${LATEST_COMMIT}.ots" ]; then cp ".ots/${LATEST_COMMIT}.ots" ".ots/proof.ots" echo "[ots-backfill] Updated .ots/proof.ots for latest commit" fi # Save previous commit chain info echo "[ots-backfill] Saving commit chain..." git rev-list HEAD | while read COMMIT; do PREV=$(git rev-parse ${COMMIT}^1 2>/dev/null || echo "") if [ -n "$PREV" ]; then echo "$COMMIT:$PREV" >> ".ots/commit-chain.txt" fi done echo "" echo "[ots-backfill] Complete! Processed $TOTAL commits, updated $UPDATED proofs" echo "" echo "Proofs stored in: .ots/" echo " - Individual proofs: .ots/.ots" echo " - Latest proof: .ots/proof.ots" echo " - Commit chain: .ots/commit-chain.txt"