Replace legacy scripts with separated ots/node hooks
- Remove deprecated scripts/ directory (6 files) - Add hooks/post-commit-ots (ots CLI version) - Add hooks/pre-commit-ots (ots CLI backfill) - Add hooks/post-commit-node (Node.js version, local proofs only) - Add hooks/pre-commit-node (Node.js backfill, no upgrade) - Update hooks/install.sh to auto-detect and install matching hooks - Update documentation (SKILL.md, README.md, AGENTS.md) - Add node_modules/ to .gitignore for Node.js mode Breaking change: Scripts removed, use new hooks/ directory.
This commit is contained in:
parent
eec64d16c6
commit
b1e305d831
14 changed files with 484 additions and 616 deletions
52
AGENTS.md
52
AGENTS.md
|
|
@ -9,15 +9,13 @@ Use this skill when the user wants to:
|
||||||
- Create cryptographic proof of commit history
|
- Create cryptographic proof of commit history
|
||||||
- Anchor commits to Bitcoin blockchain via OpenTimestamp
|
- Anchor commits to Bitcoin blockchain via OpenTimestamp
|
||||||
|
|
||||||
## Installation (Recommended)
|
## Installation (Auto-Detect)
|
||||||
|
|
||||||
**Self-contained hooks** - No external dependencies:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Install prerequisites
|
# 1. Install prerequisites (ots CLI recommended)
|
||||||
pipx install opentimestamps-client
|
pipx install opentimestamps-client
|
||||||
|
|
||||||
# 2. Install hooks (single command)
|
# 2. Install hooks (auto-detects available tools)
|
||||||
./hooks/install.sh .
|
./hooks/install.sh .
|
||||||
|
|
||||||
# 3. Commit proofs to repository
|
# 3. Commit proofs to repository
|
||||||
|
|
@ -25,31 +23,48 @@ git add .ots/ .gitignore
|
||||||
git commit -m "Add OpenTimestamp proofs for commit history"
|
git commit -m "Add OpenTimestamp proofs for commit history"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation (Manual)
|
## Installation Modes
|
||||||
|
|
||||||
Copy hook files directly:
|
The installer auto-detects and installs matching hooks:
|
||||||
|
|
||||||
|
| Detected | Hooks Installed | Attestation |
|
||||||
|
|----------|----------------|-------------|
|
||||||
|
| `ots` CLI | `post-commit-ots`, `pre-commit-ots` | Full Bitcoin |
|
||||||
|
| `@opentimestamps/ots` (node) | `post-commit-node`, `pre-commit-node` | Local only |
|
||||||
|
|
||||||
|
**Recommendation:** Always prefer ots CLI for production use.
|
||||||
|
|
||||||
|
## Manual Installation
|
||||||
|
|
||||||
|
### ots CLI Mode
|
||||||
```bash
|
```bash
|
||||||
cp hooks/post-commit .git/hooks/
|
cp hooks/post-commit-ots .git/hooks/
|
||||||
cp hooks/pre-commit .git/hooks/
|
cp hooks/pre-commit-ots .git/hooks/
|
||||||
chmod +x .git/hooks/post-commit .git/hooks/pre-commit
|
chmod +x .git/hooks/*
|
||||||
```
|
```
|
||||||
|
|
||||||
**.gitignore**:
|
### Node.js Mode
|
||||||
```
|
```bash
|
||||||
.ots/.attestation-cache
|
cp hooks/post-commit-node .git/hooks/
|
||||||
|
cp hooks/pre-commit-node .git/hooks/
|
||||||
|
chmod +x .git/hooks/*
|
||||||
|
npm install @opentimestamps/ots # If not already installed
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Files
|
## Key Files
|
||||||
|
|
||||||
| File | Purpose | Version? |
|
| File | Purpose | Version? |
|
||||||
|------|---------|----------|
|
|------|---------|----------|
|
||||||
| `generate-proof.sh` | Creates proof for commit | Yes |
|
| `hooks/post-commit-ots` | Post-commit hook (ots CLI) | Yes |
|
||||||
| `backfill-proofs.sh` | Upgrades all historical proofs | Yes |
|
| `hooks/pre-commit-ots` | Backfill hook (ots CLI) | Yes |
|
||||||
| `install-ots-hook.sh` | Installs both hooks | Yes |
|
| `hooks/post-commit-node` | Post-commit hook (Node.js) | Yes |
|
||||||
| `.ots/*.ots` | Binary proofs | Yes |
|
| `hooks/pre-commit-node` | Backfill hook (Node.js) | Yes |
|
||||||
|
| `hooks/install.sh` | Auto-detect installer | Yes |
|
||||||
|
| `.ots/*.ots` | Individual proofs | Yes |
|
||||||
|
| `.ots/proof.ots` | Latest proof reference | Yes |
|
||||||
| `.ots/commit-chain.txt` | Commit chain | Yes |
|
| `.ots/commit-chain.txt` | Commit chain | Yes |
|
||||||
| `.ots/.attestation-cache` | Local cache | No |
|
| `.ots/.attestation-cache` | Local cache | No |
|
||||||
|
| `node_modules/` | Node dependencies (if used) | No |
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
|
|
@ -67,4 +82,5 @@ ots verify .ots/<commit-hash>.ots
|
||||||
- Proofs take ~10 min to become Bitcoin-attested
|
- Proofs take ~10 min to become Bitcoin-attested
|
||||||
- Cache avoids redundant calendar calls (1-hour validity)
|
- Cache avoids redundant calendar calls (1-hour validity)
|
||||||
- Pre-commit backfill adds ~10-15s to commit time
|
- Pre-commit backfill adds ~10-15s to commit time
|
||||||
- Safe to commit `.ots/` directory (binary proofs are small: ~500B each)
|
- Node.js version creates local proofs only (no calendar submission)
|
||||||
|
- Safe to commit `.ots/` directory (binary proofs are ~500-900B each)
|
||||||
|
|
|
||||||
33
README.md
33
README.md
|
|
@ -13,14 +13,12 @@ Proofs are stored in `.ots/` and can be versioned alongside your code for tamper
|
||||||
|
|
||||||
## Quick Install
|
## Quick Install
|
||||||
|
|
||||||
### Recommended: Self-Contained Hooks
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone or download this skill
|
# Clone or download this skill
|
||||||
git clone <repository-url>
|
git clone <repository-url>
|
||||||
cd git-ots-hook
|
cd git-ots-hook
|
||||||
|
|
||||||
# Install both hooks (single command)
|
# Install both hooks (auto-detects ots CLI or Node.js)
|
||||||
./hooks/install.sh /path/to/your/repo
|
./hooks/install.sh /path/to/your/repo
|
||||||
|
|
||||||
# Commit the proofs
|
# Commit the proofs
|
||||||
|
|
@ -31,31 +29,32 @@ git commit -m "Add OpenTimestamp proofs"
|
||||||
|
|
||||||
That's it! The hooks are now installed and will automatically timestamp every commit.
|
That's it! The hooks are now installed and will automatically timestamp every commit.
|
||||||
|
|
||||||
### Legacy: Script-Based Installation
|
|
||||||
|
|
||||||
The older `scripts/` directory is still available but deprecated. See `SKILL.md` for details.
|
|
||||||
|
|
||||||
## Manual Installation
|
## Manual Installation
|
||||||
|
|
||||||
If you prefer to install hooks manually without the installer:
|
### For ots CLI (Recommended)
|
||||||
|
|
||||||
### 1. Copy Hook Files
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp hooks/post-commit /path/to/your/repo/.git/hooks/
|
cp hooks/post-commit-ots .git/hooks/post-commit
|
||||||
cp hooks/pre-commit /path/to/your/repo/.git/hooks/
|
cp hooks/pre-commit-ots .git/hooks/pre-commit
|
||||||
chmod +x /path/to/your/repo/.git/hooks/post-commit
|
chmod +x .git/hooks/post-commit .git/hooks/pre-commit
|
||||||
chmod +x /path/to/your/repo/.git/hooks/pre-commit
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Setup .gitignore
|
### For Node.js (Local proofs only)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp hooks/post-commit-node .git/hooks/post-commit
|
||||||
|
cp hooks/pre-commit-node .git/hooks/pre-commit
|
||||||
|
chmod +x .git/hooks/post-commit .git/hooks/pre-commit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setup .gitignore
|
||||||
|
|
||||||
Add to your `.gitignore`:
|
|
||||||
```
|
```
|
||||||
.ots/.attestation-cache
|
.ots/.attestation-cache
|
||||||
|
node_modules/
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Commit Initial Proofs
|
### Commit Initial Proofs
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git add .ots/
|
git add .ots/
|
||||||
|
|
|
||||||
163
SKILL.md
163
SKILL.md
|
|
@ -1,163 +1,128 @@
|
||||||
---
|
---
|
||||||
name: git-ots-hook
|
name: git-ots-hook
|
||||||
description: Install and manage OpenTimestamp git hooks that generate cryptographic proof for every commit. Use when you need to add tamper-evident timestamps to git commits using the OpenTimestamp protocol. Supports both ots CLI and nodejs fallback.
|
description: Install and manage OpenTimestamp git hooks that generate cryptographic proof for every commit. Use when you need to add tamper-evident timestamps to git commits using the OpenTimestamp protocol. Auto-detects ots CLI (recommended) or Node.js package.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Git OpenTimestamp Hook
|
# Git OpenTimestamp Hook
|
||||||
|
|
||||||
Automatically generates OpenTimestamp proofs for git commits via git hooks.
|
Automatically generates OpenTimestamp proofs for git commits via git hooks.
|
||||||
|
|
||||||
## Quick Start (Recommended)
|
## Quick Start
|
||||||
|
|
||||||
**New: Self-contained hooks** - No external dependencies, simple installation:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install both hooks (post-commit + pre-commit backfill)
|
# Install both hooks (auto-detects ots CLI or Node.js)
|
||||||
./hooks/install.sh /path/to/repo
|
./hooks/install.sh /path/to/repo
|
||||||
|
|
||||||
# Or from repo root
|
# Or from repo root
|
||||||
./hooks/install.sh .
|
./hooks/install.sh .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Legacy Installation
|
The installer will:
|
||||||
|
1. Detect available tools (ots CLI preferred, Node.js fallback)
|
||||||
The older `scripts/` directory is still available for backward compatibility, but the new `hooks/` directory is recommended for simpler deployment.
|
2. Install matching hooks
|
||||||
|
3. Setup `.gitignore` (excludes cache + node_modules)
|
||||||
|
4. Install `@opentimestamps/ots` locally if using Node.js mode
|
||||||
|
|
||||||
## What It Does
|
## What It Does
|
||||||
|
|
||||||
- **Post-commit hook** (`hooks/post-commit`): Generates `.ots/<commit-hash>.ots` for each new commit
|
- **Auto-detects tools**: ots CLI (full Bitcoin attestation) or Node.js package (local proofs only)
|
||||||
- **Pre-commit backfill** (`hooks/pre-commit`): Before each commit, upgrades all historical proofs to attested status
|
- **Post-commit hook**: Generates `.ots/<commit-hash>.ots` for each new commit
|
||||||
- Creates `.ots/proof.ots` with latest commit proof
|
- **Pre-commit backfill**: Upgrades historical proofs to attested status (ots CLI only)
|
||||||
|
- Creates `.ots/proof.ots` (latest proof reference)
|
||||||
- Stores commit chain in `.ots/commit-chain.txt`
|
- Stores commit chain in `.ots/commit-chain.txt`
|
||||||
- Works with `ots` CLI (preferred) or `@opentimestamps/ots` node package (fallback)
|
- Smart caching: Skips calendar calls for recently checked proofs
|
||||||
- **Self-contained**: No external script dependencies, simple drop-in installation
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
Install one of:
|
**Option 1: ots CLI (Recommended - Full Bitcoin attestation)**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Option 1: ots CLI (recommended)
|
pipx install opentimestamps-client
|
||||||
git clone https://github.com/opentimestamps/opentimestamps-client
|
```
|
||||||
cd opentimestamps-client
|
|
||||||
pipx install .
|
|
||||||
|
|
||||||
# Option 2: Node.js fallback
|
**Option 2: Node.js (Local proofs only)**
|
||||||
npm install -g @opentimestamps/ots
|
```bash
|
||||||
|
# Package will be installed locally by the installer
|
||||||
|
# Or globally: npm install -g @opentimestamps/ots
|
||||||
```
|
```
|
||||||
|
|
||||||
## Generated Files
|
## Generated Files
|
||||||
|
|
||||||
The hooks create:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
repo/
|
repo/
|
||||||
├── .ots/
|
├── .ots/
|
||||||
│ ├── proof.ots # Timestamp proof for latest commit
|
│ ├── <commit-hash>.ots # Individual proof per commit
|
||||||
│ ├── <commit-hash>.ots # Individual proof for each commit
|
│ ├── proof.ots # Latest commit proof (reference)
|
||||||
│ ├── prev-commit.txt # Previous commit hash (for chaining)
|
│ ├── prev-commit.txt # Previous commit hash (chaining)
|
||||||
│ └── commit-chain.txt # Full commit chain mapping
|
│ ├── commit-chain.txt # Full commit chain mapping
|
||||||
|
│ └── .attestation-cache # Local cache (gitignore this)
|
||||||
└── ...
|
└── ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Proof files include:
|
|
||||||
- Commit hash timestamp (OpenTimestamp format)
|
|
||||||
- Bitcoin attestation (after ~10 min confirmation)
|
|
||||||
- Commit chain references
|
|
||||||
|
|
||||||
## Manual Usage
|
## Manual Usage
|
||||||
|
|
||||||
### New Self-Contained Hooks (Recommended)
|
**Install hooks (auto-detect):**
|
||||||
|
|
||||||
**Install hooks:**
|
|
||||||
```bash
|
```bash
|
||||||
./hooks/install.sh /path/to/repo
|
./hooks/install.sh /path/to/repo
|
||||||
```
|
```
|
||||||
|
|
||||||
**Manual hook installation:**
|
**Manual installation:**
|
||||||
Copy `hooks/post-commit` and `hooks/pre-commit` directly to `.git/hooks/`
|
|
||||||
|
|
||||||
### Legacy Scripts (Deprecated)
|
|
||||||
|
|
||||||
**Generate proof for a specific commit:**
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/generate-proof.sh <commit-hash> [output-file]
|
# For ots CLI:
|
||||||
|
cp hooks/post-commit-ots .git/hooks/post-commit
|
||||||
|
cp hooks/pre-commit-ots .git/hooks/pre-commit
|
||||||
|
|
||||||
|
# For Node.js:
|
||||||
|
cp hooks/post-commit-node .git/hooks/post-commit
|
||||||
|
cp hooks/pre-commit-node .git/hooks/pre-commit
|
||||||
|
|
||||||
|
chmod +x .git/hooks/post-commit .git/hooks/pre-commit
|
||||||
```
|
```
|
||||||
|
|
||||||
**Backfill proofs for entire history:**
|
**Check attestation status:**
|
||||||
```bash
|
```bash
|
||||||
./scripts/backfill-proofs.sh /path/to/repo
|
ots info .ots/<commit-hash>.ots | grep -c "PendingAttestation"
|
||||||
```
|
# 0 = attested, >0 = pending
|
||||||
|
|
||||||
**Setup .gitignore (excludes cache only, keeps proofs):**
|
|
||||||
```bash
|
|
||||||
./scripts/setup-gitignore.sh /path/to/repo
|
|
||||||
```
|
|
||||||
|
|
||||||
**Check proof attestation status:**
|
|
||||||
```bash
|
|
||||||
./scripts/check-attestation.sh .ots/<commit-hash>.ots
|
|
||||||
# Output: "attested" or "pending"
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```bash
|
|
||||||
./scripts/generate-proof.sh abc123def456 .ots/proof.ots
|
|
||||||
./scripts/backfill-proofs.sh .
|
|
||||||
./scripts/setup-gitignore.sh .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstall
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rm /path/to/repo/.git/hooks/post-commit
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
### Versioning Proofs (Recommended)
|
### Versioning Proofs
|
||||||
|
|
||||||
To include proofs in your repository (recommended for tamper-evidence):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Commit proofs with your code
|
|
||||||
git add .ots/
|
git add .ots/
|
||||||
git commit -m "Add OpenTimestamp proofs"
|
git commit -m "Add OpenTimestamp proofs"
|
||||||
```
|
```
|
||||||
|
|
||||||
The `.ots/` directory contains:
|
**Commit these:**
|
||||||
- `*.ots` - Binary proof files (commit these)
|
- `*.ots` - Individual proof per commit
|
||||||
- `commit-chain.txt` - Commit chain mapping (commit this)
|
- `proof.ots` - Latest proof reference
|
||||||
- `prev-commit.txt` - Latest previous commit (commit this)
|
- `commit-chain.txt` - Full chain
|
||||||
- `.attestation-cache` - Local cache (add to `.gitignore`)
|
- `prev-commit.txt` - Previous commit link
|
||||||
|
|
||||||
**Recommended `.gitignore`:**
|
**Ignore these:**
|
||||||
```
|
- `.attestation-cache` - Local performance cache
|
||||||
.ots/.attestation-cache
|
- `node_modules/` - If using Node.js mode (auto-added by installer)
|
||||||
```
|
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
|
|
||||||
- **Pre-commit backfill** can slow down commits on large histories
|
- **First backfill:** ~30-60s (scans history, contacts calendars)
|
||||||
- First backfill: Full scan + calendar calls (~30-60s)
|
- **Subsequent commits:** ~10-15s (cached status skips redundant calls)
|
||||||
- Subsequent commits: Cached status skips calendar calls (~10-15s)
|
- **Cache:** 1-hour validity, 10-min recheck for pending proofs
|
||||||
- Cache expires after 1 hour, re-checks pending proofs after 10 min
|
|
||||||
|
|
||||||
### Other Notes
|
### Modes
|
||||||
|
|
||||||
- Hook is silent if neither `ots` nor node package is found
|
| Feature | ots CLI | Node.js |
|
||||||
- Proofs become "attested" after ~10 min (Bitcoin confirmation)
|
|---------|---------|---------|
|
||||||
|
| Calendar submission | ✓ | ✗ |
|
||||||
|
| Bitcoin attestation | ✓ | ✗ |
|
||||||
|
| Local proofs | ✓ | ✓ |
|
||||||
|
| Upgrade support | ✓ | ✗ |
|
||||||
|
| Speed | Fast | Fast |
|
||||||
|
|
||||||
## Troubleshooting
|
**Recommendation:** Use ots CLI for production. Node.js for development/testing only.
|
||||||
|
|
||||||
**Hook not running?**
|
## Uninstall
|
||||||
- Check it's executable: `chmod +x .git/hooks/post-commit`
|
|
||||||
- Test manually: `.git/hooks/post-commit`
|
|
||||||
|
|
||||||
**Proof not generating?**
|
```bash
|
||||||
- Verify `ots` or `@opentimestamps/ots` is installed
|
rm .git/hooks/post-commit .git/hooks/pre-commit
|
||||||
- Check hook output: `git commit` shows `[ots]` messages
|
```
|
||||||
|
|
||||||
**Want auto-commit proofs?**
|
|
||||||
- Modify the hook to run `git add .ots/proof.ots && git commit --amend --no-edit`
|
|
||||||
- ⚠️ This changes commit history - use with caution
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Git OpenTimestamp Hooks Installer
|
# Git OpenTimestamp Hooks Installer
|
||||||
# Copies self-contained hooks to git repository
|
# Detects available tools and installs matching hooks
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
|
@ -9,21 +9,50 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
cd "$REPO_PATH"
|
cd "$REPO_PATH"
|
||||||
|
|
||||||
# Verify we're in a git repository
|
|
||||||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||||
echo "Error: not a git repository" >&2
|
echo "Error: not a git repository" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
HOOKS_DIR="$(git rev-parse --git-dir)/hooks"
|
HOOKS_DIR="$(git rev-parse --git-dir)/hooks"
|
||||||
|
MODE=""
|
||||||
|
|
||||||
echo "Installing OpenTimestamp hooks to: $HOOKS_DIR"
|
# Detect available tools
|
||||||
|
if command -v ots &> /dev/null; then
|
||||||
|
MODE="ots"
|
||||||
|
echo "Detected: ots CLI"
|
||||||
|
elif command -v node &> /dev/null && node -e "require('@opentimestamps/ots')" &> /dev/null 2>&1; then
|
||||||
|
MODE="node"
|
||||||
|
echo "Detected: @opentimestamps/ots (Node.js)"
|
||||||
|
echo "Note: Node version creates local proofs only (no calendar submission)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Install node package locally if not already present
|
||||||
|
if [ ! -d "node_modules/@opentimestamps" ]; then
|
||||||
|
echo "Installing @opentimestamps/ots locally..."
|
||||||
|
npm install @opentimestamps/ots
|
||||||
|
echo "✓ Package installed"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Error: Neither ots CLI nor @opentimestamps/ots found" >&2
|
||||||
|
echo "Install one of:" >&2
|
||||||
|
echo " pipx install opentimestamps-client (recommended)" >&2
|
||||||
|
echo " npm install @opentimestamps/ots (local proofs only)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Copy hooks
|
echo ""
|
||||||
cp "$SCRIPT_DIR/post-commit" "$HOOKS_DIR/post-commit"
|
echo "Installing $MODE hooks to: $HOOKS_DIR"
|
||||||
cp "$SCRIPT_DIR/pre-commit" "$HOOKS_DIR/pre-commit"
|
|
||||||
|
# Copy appropriate hooks
|
||||||
|
if [ "$MODE" = "ots" ]; then
|
||||||
|
cp "$SCRIPT_DIR/post-commit-ots" "$HOOKS_DIR/post-commit"
|
||||||
|
cp "$SCRIPT_DIR/pre-commit-ots" "$HOOKS_DIR/pre-commit"
|
||||||
|
else
|
||||||
|
cp "$SCRIPT_DIR/post-commit-node" "$HOOKS_DIR/post-commit"
|
||||||
|
cp "$SCRIPT_DIR/pre-commit-node" "$HOOKS_DIR/pre-commit"
|
||||||
|
fi
|
||||||
|
|
||||||
# Make executable
|
|
||||||
chmod +x "$HOOKS_DIR/post-commit" "$HOOKS_DIR/pre-commit"
|
chmod +x "$HOOKS_DIR/post-commit" "$HOOKS_DIR/pre-commit"
|
||||||
|
|
||||||
echo "✓ Post-commit hook installed"
|
echo "✓ Post-commit hook installed"
|
||||||
|
|
@ -32,19 +61,33 @@ echo "✓ Pre-commit backfill hook installed"
|
||||||
# Setup .gitignore
|
# Setup .gitignore
|
||||||
GITIGNORE=".gitignore"
|
GITIGNORE=".gitignore"
|
||||||
if [ ! -f "$GITIGNORE" ]; then
|
if [ ! -f "$GITIGNORE" ]; then
|
||||||
echo ".ots/.attestation-cache" > "$GITIGNORE"
|
cat > "$GITIGNORE" << 'EOF'
|
||||||
|
.ots/.attestation-cache
|
||||||
|
node_modules/
|
||||||
|
EOF
|
||||||
echo "✓ Created .gitignore"
|
echo "✓ Created .gitignore"
|
||||||
elif ! grep -q ".ots/.attestation-cache" "$GITIGNORE"; then
|
elif ! grep -q ".ots/.attestation-cache" "$GITIGNORE"; then
|
||||||
echo "" >> "$GITIGNORE"
|
|
||||||
echo ".ots/.attestation-cache" >> "$GITIGNORE"
|
echo ".ots/.attestation-cache" >> "$GITIGNORE"
|
||||||
|
if [ "$MODE" = "node" ] && ! grep -q "node_modules/" "$GITIGNORE"; then
|
||||||
|
echo "node_modules/" >> "$GITIGNORE"
|
||||||
|
fi
|
||||||
echo "✓ Updated .gitignore"
|
echo "✓ Updated .gitignore"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Mode: $MODE"
|
||||||
|
if [ "$MODE" = "ots" ]; then
|
||||||
|
echo " - Full Bitcoin attestation via calendars"
|
||||||
|
echo " - Proofs submitted to remote calendars"
|
||||||
|
else
|
||||||
|
echo " - Local proofs only (no calendar submission)"
|
||||||
|
echo " - For full attestation, use: pipx install opentimestamps-client"
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next steps:"
|
echo "Next steps:"
|
||||||
echo "1. Make a test commit to verify hooks work"
|
echo "1. Make a test commit"
|
||||||
echo "2. Commit the .ots/ directory: git add .ots/"
|
echo "2. Commit proofs: git add .ots/ && git commit -m 'Add OpenTimestamp proofs'"
|
||||||
echo "3. Commit with message: git commit -m 'Add OpenTimestamp proofs'"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "To uninstall:"
|
echo "To uninstall:"
|
||||||
echo " rm $HOOKS_DIR/post-commit $HOOKS_DIR/pre-commit"
|
echo " rm $HOOKS_DIR/post-commit $HOOKS_DIR/pre-commit"
|
||||||
|
|
|
||||||
49
hooks/post-commit-node
Executable file
49
hooks/post-commit-node
Executable file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Git OpenTimestamp Post-Commit Hook (Node.js version)
|
||||||
|
# Requires: @opentimestamps/ots (npm install)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OUTPUT_DIR=".ots"
|
||||||
|
OUTPUT_FILE="$OUTPUT_DIR/proof.ots"
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
COMMIT_HASH=$(git rev-parse HEAD)
|
||||||
|
|
||||||
|
# Generate proof using Node.js
|
||||||
|
node -e "
|
||||||
|
const ots = require('@opentimestamps/ots');
|
||||||
|
const fs = require('fs');
|
||||||
|
const hash = '$COMMIT_HASH';
|
||||||
|
const output = '$OUTPUT_FILE';
|
||||||
|
const hashBuffer = Buffer.from(hash, 'hex');
|
||||||
|
|
||||||
|
ots.Timestamp.hash(hashBuffer).then(timestamp => {
|
||||||
|
// Note: This creates a local proof only, not submitted to calendars
|
||||||
|
// For full Bitcoin attestation, use the ots CLI version
|
||||||
|
const proof = {
|
||||||
|
hash: hash,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
status: 'pending',
|
||||||
|
note: 'Local proof only - use ots CLI for calendar submission'
|
||||||
|
};
|
||||||
|
fs.writeFileSync(output, JSON.stringify(proof, null, 2));
|
||||||
|
console.log('[ots-node] Generated local proof: ' + hash.substring(0, 8));
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('[ots-node] Error:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
"
|
||||||
|
|
||||||
|
# Save previous commit for chaining
|
||||||
|
PREV_COMMIT=$(git rev-parse HEAD^1 2>/dev/null || echo "")
|
||||||
|
if [ -n "$PREV_COMMIT" ]; then
|
||||||
|
echo "$PREV_COMMIT" > "$OUTPUT_DIR/prev-commit.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create individual proof file (JSON format for node version)
|
||||||
|
INDIVIDUAL_PROOF="$OUTPUT_DIR/${COMMIT_HASH}.ots"
|
||||||
|
cp "$OUTPUT_FILE" "$INDIVIDUAL_PROOF"
|
||||||
|
|
||||||
|
echo "[ots-node] Proof generated successfully"
|
||||||
41
hooks/post-commit-ots
Executable file
41
hooks/post-commit-ots
Executable file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Git OpenTimestamp Post-Commit Hook (ots CLI version)
|
||||||
|
# Requires: opentimestamps-client (pipx install opentimestamps-client)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OUTPUT_DIR=".ots"
|
||||||
|
OUTPUT_FILE="$OUTPUT_DIR/proof.ots"
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
COMMIT_HASH=$(git rev-parse HEAD)
|
||||||
|
|
||||||
|
# Generate proof using ots CLI
|
||||||
|
temp_file=$(mktemp)
|
||||||
|
temp_ots="${temp_file}.ots"
|
||||||
|
|
||||||
|
python3 -c "import sys; sys.stdout.buffer.write(bytes.fromhex('$COMMIT_HASH'))" > "$temp_file"
|
||||||
|
ots stamp "$temp_file" 2>/dev/null
|
||||||
|
|
||||||
|
if [ -f "$temp_ots" ]; then
|
||||||
|
mv "$temp_ots" "$OUTPUT_FILE"
|
||||||
|
rm -f "$temp_file"
|
||||||
|
echo "[ots] Generated proof: ${COMMIT_HASH:0:8}"
|
||||||
|
else
|
||||||
|
rm -f "$temp_file"
|
||||||
|
echo "[ots] Warning: Failed to generate proof" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save previous commit for chaining
|
||||||
|
PREV_COMMIT=$(git rev-parse HEAD^1 2>/dev/null || echo "")
|
||||||
|
if [ -n "$PREV_COMMIT" ]; then
|
||||||
|
echo "$PREV_COMMIT" > "$OUTPUT_DIR/prev-commit.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create individual proof file
|
||||||
|
INDIVIDUAL_PROOF="$OUTPUT_DIR/${COMMIT_HASH}.ots"
|
||||||
|
cp "$OUTPUT_FILE" "$INDIVIDUAL_PROOF"
|
||||||
|
|
||||||
|
echo "[ots] Proof generated successfully"
|
||||||
100
hooks/pre-commit-node
Executable file
100
hooks/pre-commit-node
Executable file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Git OpenTimestamp Pre-Commit Backfill Hook (Node.js version)
|
||||||
|
# Requires: @opentimestamps/ots (npm install)
|
||||||
|
# Note: Node version only generates local proofs, no calendar submission
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OUTPUT_DIR=".ots"
|
||||||
|
STATUS_CACHE="$OUTPUT_DIR/.attestation-cache"
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
# Initialize cache
|
||||||
|
if [ ! -f "$STATUS_CACHE" ]; then
|
||||||
|
echo "# Format: commit-hash:status:timestamp" > "$STATUS_CACHE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
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)
|
||||||
|
if [ "$((now - timestamp))" -lt 3600 ]; then
|
||||||
|
echo "$status"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_status() {
|
||||||
|
local commit="$1"
|
||||||
|
local status="$2"
|
||||||
|
echo "$commit:$status:$(date +%s)" >> "$STATUS_CACHE"
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_proof_node() {
|
||||||
|
local hash="$1"
|
||||||
|
local output="$2"
|
||||||
|
|
||||||
|
node -e "
|
||||||
|
const ots = require('@opentimestamps/ots');
|
||||||
|
const fs = require('fs');
|
||||||
|
const hash = '$hash';
|
||||||
|
const output = '$output';
|
||||||
|
const hashBuffer = Buffer.from(hash, 'hex');
|
||||||
|
|
||||||
|
ots.Timestamp.hash(hashBuffer).then(timestamp => {
|
||||||
|
const proof = { hash: hash, timestamp: new Date().toISOString(), status: 'pending' };
|
||||||
|
fs.writeFileSync(output, JSON.stringify(proof, null, 2));
|
||||||
|
}).catch(err => { console.error('Error:', err); process.exit(1); });
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[ots-node] Backfilling proofs (local only, no calendar)..."
|
||||||
|
|
||||||
|
COMMITS=$(git rev-list --reverse HEAD)
|
||||||
|
TOTAL=$(echo "$COMMITS" | wc -l)
|
||||||
|
CURRENT=0
|
||||||
|
UPDATED=0
|
||||||
|
|
||||||
|
for COMMIT in $COMMITS; do
|
||||||
|
CURRENT=$((CURRENT + 1))
|
||||||
|
PROOF_FILE="$OUTPUT_DIR/${COMMIT}.ots"
|
||||||
|
|
||||||
|
if [ $CURRENT -le 3 ] || [ $CURRENT -eq $TOTAL ]; then
|
||||||
|
echo "[ots-node] Processing $CURRENT/$TOTAL: ${COMMIT:0:8}"
|
||||||
|
elif [ $CURRENT -eq 4 ]; then
|
||||||
|
echo "[ots-node] ... processing remaining ..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$PROOF_FILE" ]; then
|
||||||
|
# Node version doesn't support upgrade, just check cache
|
||||||
|
CACHED_STATUS=$(get_cached_status "$COMMIT" || echo "")
|
||||||
|
[ "$CACHED_STATUS" = "attested" ] && continue
|
||||||
|
|
||||||
|
# Mark as pending (node can't attest)
|
||||||
|
cache_status "$COMMIT" "pending"
|
||||||
|
else
|
||||||
|
if generate_proof_node "$COMMIT" "$PROOF_FILE"; then
|
||||||
|
cache_status "$COMMIT" "pending"
|
||||||
|
UPDATED=$((UPDATED + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Update latest proof
|
||||||
|
LATEST_COMMIT=$(git rev-parse HEAD)
|
||||||
|
[ -f "$OUTPUT_DIR/${LATEST_COMMIT}.ots" ] && cp "$OUTPUT_DIR/${LATEST_COMMIT}.ots" "$OUTPUT_DIR/proof.ots"
|
||||||
|
|
||||||
|
# Save commit chain
|
||||||
|
rm -f "$OUTPUT_DIR/commit-chain.txt"
|
||||||
|
git rev-list HEAD | while read COMMIT; do
|
||||||
|
PREV=$(git rev-parse ${COMMIT}^1 2>/dev/null || echo "")
|
||||||
|
[ -n "$PREV" ] && echo "$COMMIT:$PREV" >> "$OUTPUT_DIR/commit-chain.txt"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[ots-node] Backfill complete: $UPDATED generated (local proofs only)"
|
||||||
125
hooks/pre-commit-ots
Executable file
125
hooks/pre-commit-ots
Executable file
|
|
@ -0,0 +1,125 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Git OpenTimestamp Pre-Commit Backfill Hook (ots CLI version)
|
||||||
|
# Requires: opentimestamps-client (pipx install opentimestamps-client)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OUTPUT_DIR=".ots"
|
||||||
|
STATUS_CACHE="$OUTPUT_DIR/.attestation-cache"
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
# Initialize cache
|
||||||
|
if [ ! -f "$STATUS_CACHE" ]; then
|
||||||
|
echo "# Format: commit-hash:status:timestamp" > "$STATUS_CACHE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
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)
|
||||||
|
if [ "$((now - timestamp))" -lt 3600 ]; then
|
||||||
|
echo "$status"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_status() {
|
||||||
|
local commit="$1"
|
||||||
|
local status="$2"
|
||||||
|
echo "$commit:$status:$(date +%s)" >> "$STATUS_CACHE"
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_proof() {
|
||||||
|
local hash="$1"
|
||||||
|
local output="$2"
|
||||||
|
local temp_file=$(mktemp)
|
||||||
|
local temp_ots="${temp_file}.ots"
|
||||||
|
|
||||||
|
python3 -c "import sys; sys.stdout.buffer.write(bytes.fromhex('$hash'))" > "$temp_file"
|
||||||
|
ots stamp "$temp_file" 2>/dev/null
|
||||||
|
|
||||||
|
if [ -f "$temp_ots" ]; then
|
||||||
|
mv "$temp_ots" "$output"
|
||||||
|
rm -f "$temp_file"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
rm -f "$temp_file"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
is_attested() {
|
||||||
|
local proof_file="$1"
|
||||||
|
local pending_count=$(ots info "$proof_file" 2>&1 | grep -c "PendingAttestation" || echo "0")
|
||||||
|
[ "$pending_count" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade_proof() {
|
||||||
|
local proof_file="$1"
|
||||||
|
ots upgrade "$proof_file" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[ots] Backfilling proofs..."
|
||||||
|
|
||||||
|
COMMITS=$(git rev-list --reverse HEAD)
|
||||||
|
TOTAL=$(echo "$COMMITS" | wc -l)
|
||||||
|
CURRENT=0
|
||||||
|
UPDATED=0
|
||||||
|
|
||||||
|
for COMMIT in $COMMITS; do
|
||||||
|
CURRENT=$((CURRENT + 1))
|
||||||
|
PROOF_FILE="$OUTPUT_DIR/${COMMIT}.ots"
|
||||||
|
|
||||||
|
if [ $CURRENT -le 3 ] || [ $CURRENT -eq $TOTAL ]; then
|
||||||
|
echo "[ots] Processing $CURRENT/$TOTAL: ${COMMIT:0:8}"
|
||||||
|
elif [ $CURRENT -eq 4 ]; then
|
||||||
|
echo "[ots] ... processing remaining ..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$PROOF_FILE" ]; then
|
||||||
|
CACHED_STATUS=$(get_cached_status "$COMMIT" || echo "")
|
||||||
|
|
||||||
|
[ "$CACHED_STATUS" = "attested" ] && continue
|
||||||
|
|
||||||
|
if is_attested "$PROOF_FILE"; then
|
||||||
|
cache_status "$COMMIT" "attested"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
cache_status "$COMMIT" "pending"
|
||||||
|
|
||||||
|
CACHE_LINE=$(grep "^$COMMIT:" "$STATUS_CACHE" | tail -1)
|
||||||
|
CACHE_TIME=$(echo "$CACHE_LINE" | cut -d: -f3)
|
||||||
|
CACHE_AGE=$(($(date +%s) - CACHE_TIME))
|
||||||
|
|
||||||
|
[ "$CACHE_AGE" -lt 600 ] && continue
|
||||||
|
|
||||||
|
if upgrade_proof "$PROOF_FILE"; then
|
||||||
|
cache_status "$COMMIT" "attested"
|
||||||
|
UPDATED=$((UPDATED + 1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if generate_proof "$COMMIT" "$PROOF_FILE"; then
|
||||||
|
cache_status "$COMMIT" "pending"
|
||||||
|
UPDATED=$((UPDATED + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Update latest proof
|
||||||
|
LATEST_COMMIT=$(git rev-parse HEAD)
|
||||||
|
[ -f "$OUTPUT_DIR/${LATEST_COMMIT}.ots" ] && cp "$OUTPUT_DIR/${LATEST_COMMIT}.ots" "$OUTPUT_DIR/proof.ots"
|
||||||
|
|
||||||
|
# Save commit chain
|
||||||
|
rm -f "$OUTPUT_DIR/commit-chain.txt"
|
||||||
|
git rev-list HEAD | while read COMMIT; do
|
||||||
|
PREV=$(git rev-parse ${COMMIT}^1 2>/dev/null || echo "")
|
||||||
|
[ -n "$PREV" ] && echo "$COMMIT:$PREV" >> "$OUTPUT_DIR/commit-chain.txt"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[ots] Backfill complete: $UPDATED updated"
|
||||||
|
|
@ -1,165 +0,0 @@
|
||||||
#!/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"
|
|
||||||
|
|
||||||
# Skip upgrade if cache is fresh (< 10 min old)
|
|
||||||
CACHE_LINE=$(grep "^$COMMIT:" "$STATUS_CACHE" | tail -1)
|
|
||||||
CACHE_TIME=$(echo "$CACHE_LINE" | cut -d: -f3)
|
|
||||||
NOW=$(date +%s)
|
|
||||||
CACHE_AGE=$((NOW - CACHE_TIME))
|
|
||||||
|
|
||||||
if [ "$CACHE_AGE" -lt 600 ]; then
|
|
||||||
echo " - Pending (cached <10min, skipping calendar call)"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Try to upgrade existing proof (contacts calendars)
|
|
||||||
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)"
|
|
||||||
# Update cache timestamp
|
|
||||||
cache_status "$COMMIT" "pending"
|
|
||||||
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/<commit-hash>.ots"
|
|
||||||
echo " - Latest proof: .ots/proof.ots"
|
|
||||||
echo " - Commit chain: .ots/commit-chain.txt"
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# check-attestation.sh - Check if an OpenTimestamp proof is fully attested
|
|
||||||
# Usage: check-attestation.sh <proof-file>
|
|
||||||
# Returns: 0 if fully attested, 1 if pending
|
|
||||||
|
|
||||||
PROOF_FILE="${1:-}"
|
|
||||||
|
|
||||||
if [ -z "$PROOF_FILE" ] || [ ! -f "$PROOF_FILE" ]; then
|
|
||||||
echo "Error: proof file not found: $PROOF_FILE" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for PendingAttestation in ots info output
|
|
||||||
if ots info "$PROOF_FILE" 2>&1 | grep -q "PendingAttestation"; then
|
|
||||||
echo "pending"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "attested"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# generate-proof.sh - Generate OpenTimestamp proof for a git commit
|
|
||||||
# Usage: generate-proof.sh <commit-hash> [output-file]
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
COMMIT_HASH="${1:-}"
|
|
||||||
OUTPUT_FILE="${2:-.ots/proof.ots}"
|
|
||||||
|
|
||||||
if [ -z "$COMMIT_HASH" ]; then
|
|
||||||
echo "Error: commit hash required" >&2
|
|
||||||
echo "Usage: $0 <commit-hash> [output-file]" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure .ots directory exists
|
|
||||||
mkdir -p "$(dirname "$OUTPUT_FILE")"
|
|
||||||
|
|
||||||
# Function to generate proof using ots CLI
|
|
||||||
generate_with_ots_cli() {
|
|
||||||
local hash="$1"
|
|
||||||
local output="$2"
|
|
||||||
|
|
||||||
# Create a temporary file with the hash (convert hex to binary)
|
|
||||||
local temp_file=$(mktemp)
|
|
||||||
local temp_ots="${temp_file}.ots"
|
|
||||||
|
|
||||||
# Use python3 for hex to binary conversion (more portable than xxd)
|
|
||||||
python3 -c "import sys; sys.stdout.buffer.write(bytes.fromhex('$hash'))" > "$temp_file"
|
|
||||||
|
|
||||||
# Generate timestamp - ots creates .ots file alongside the original
|
|
||||||
ots stamp "$temp_file"
|
|
||||||
|
|
||||||
# Move the generated .ots file to the desired location
|
|
||||||
if [ -f "$temp_ots" ]; then
|
|
||||||
mkdir -p "$(dirname "$output")"
|
|
||||||
mv "$temp_ots" "$output"
|
|
||||||
echo "Generated proof with ots CLI: $output"
|
|
||||||
else
|
|
||||||
echo "Error: ots did not generate proof file" >&2
|
|
||||||
rm -f "$temp_file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -f "$temp_file"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to generate proof using opentimestamps-nodejs
|
|
||||||
generate_with_node() {
|
|
||||||
local hash="$1"
|
|
||||||
local output="$2"
|
|
||||||
|
|
||||||
# Use nodejs opentimestamps library
|
|
||||||
# This requires @opentimestamps/ots to be installed globally
|
|
||||||
node -e "
|
|
||||||
const ots = require('@opentimestamps/ots');
|
|
||||||
const fs = require('fs');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
|
|
||||||
const hash = '$hash';
|
|
||||||
const output = '$output';
|
|
||||||
|
|
||||||
// Convert hex hash to buffer
|
|
||||||
const hashBuffer = Buffer.from(hash, 'hex');
|
|
||||||
|
|
||||||
// Create timestamp
|
|
||||||
ots.Timestamp.hash(hashBuffer).then(timestamp => {
|
|
||||||
// In a real implementation, this would contact the calendar server
|
|
||||||
// For now, we create a minimal proof structure
|
|
||||||
console.log('Warning: nodejs fallback creates local proof only');
|
|
||||||
console.log('Install ots CLI for full functionality: https://github.com/opentimestamps/opentimestamps-client');
|
|
||||||
|
|
||||||
// Create a simple proof file (this is a placeholder - real impl needs calendar)
|
|
||||||
const proof = {
|
|
||||||
hash: hash,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
status: 'pending'
|
|
||||||
};
|
|
||||||
|
|
||||||
fs.writeFileSync(output, JSON.stringify(proof, null, 2));
|
|
||||||
console.log('Generated local proof: ' + output);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('Error generating timestamp:', err);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if ots CLI is available
|
|
||||||
if command -v ots &> /dev/null; then
|
|
||||||
echo "Using ots CLI..."
|
|
||||||
generate_with_ots_cli "$COMMIT_HASH" "$OUTPUT_FILE"
|
|
||||||
elif command -v node &> /dev/null && node -e "require('@opentimestamps/ots')" &> /dev/null; then
|
|
||||||
echo "Using opentimestamps-nodejs fallback..."
|
|
||||||
generate_with_node "$COMMIT_HASH" "$OUTPUT_FILE"
|
|
||||||
else
|
|
||||||
echo "Error: Neither ots CLI nor @opentimestamps/ots node package found" >&2
|
|
||||||
echo "Install one of:" >&2
|
|
||||||
echo " - ots CLI: https://github.com/opentimestamps/opentimestamps-client" >&2
|
|
||||||
echo " - Node package: npm install -g @opentimestamps/ots" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get previous commit hash for chaining (before appending to proof file)
|
|
||||||
PREV_COMMIT=$(git rev-parse HEAD^1 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
# Store previous commit hash in a separate metadata file for chaining
|
|
||||||
if [ -n "$PREV_COMMIT" ]; then
|
|
||||||
echo "$PREV_COMMIT" > "$(dirname "$OUTPUT_FILE")/prev-commit.txt"
|
|
||||||
echo "Chaining info saved: $PREV_COMMIT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Proof generated for commit: $COMMIT_HASH"
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# install-ots-hook.sh - Install OpenTimestamp post-commit hook
|
|
||||||
# Usage: install-ots-hook.sh [repository-path] [backfill]
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
REPO_PATH="${1:-.}"
|
|
||||||
ENABLE_BACKFILL="${2:-}" # Second arg: "backfill" to enable pre-commit backfill hook
|
|
||||||
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
|
|
||||||
|
|
||||||
HOOKS_DIR="$(git rev-parse --git-dir)/hooks"
|
|
||||||
POST_COMMIT_HOOK="$HOOKS_DIR/post-commit"
|
|
||||||
|
|
||||||
echo "Installing OpenTimestamp hooks in: $REPO_PATH"
|
|
||||||
|
|
||||||
# Create the post-commit hook
|
|
||||||
cat > "$POST_COMMIT_HOOK" << 'HOOK_SCRIPT'
|
|
||||||
#!/bin/bash
|
|
||||||
# Post-commit hook: generate OpenTimestamp proof for each commit
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Get the commit hash
|
|
||||||
COMMIT_HASH=$(git rev-parse HEAD)
|
|
||||||
|
|
||||||
# Find the generate-proof.sh script
|
|
||||||
# Try relative paths first, then check common locations
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
GENERATE_SCRIPT=""
|
|
||||||
|
|
||||||
# Check if generate-proof.sh is in the same directory as this hook
|
|
||||||
if [ -f "$SCRIPT_DIR/generate-proof.sh" ]; then
|
|
||||||
GENERATE_SCRIPT="$SCRIPT_DIR/generate-proof.sh"
|
|
||||||
# Check in .git/hooks directory
|
|
||||||
elif [ -f ".git/hooks/generate-proof.sh" ]; then
|
|
||||||
GENERATE_SCRIPT=".git/hooks/generate-proof.sh"
|
|
||||||
# Check in repository root
|
|
||||||
elif [ -f "generate-proof.sh" ]; then
|
|
||||||
GENERATE_SCRIPT="./generate-proof.sh"
|
|
||||||
# Check if skill is installed globally (common OpenClaw path)
|
|
||||||
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 "Warning: generate-proof.sh not found, skipping OpenTimestamp proof" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure the script is executable
|
|
||||||
chmod +x "$GENERATE_SCRIPT"
|
|
||||||
|
|
||||||
# Generate the proof
|
|
||||||
echo "[ots] Generating proof for commit: $COMMIT_HASH"
|
|
||||||
"$GENERATE_SCRIPT" "$COMMIT_HASH"
|
|
||||||
|
|
||||||
echo "[ots] Proof generated successfully"
|
|
||||||
HOOK_SCRIPT
|
|
||||||
|
|
||||||
# Make the hook executable
|
|
||||||
chmod +x "$POST_COMMIT_HOOK"
|
|
||||||
|
|
||||||
echo "✓ Post-commit hook installed successfully"
|
|
||||||
|
|
||||||
# Optionally install pre-commit backfill hook
|
|
||||||
if [ "$ENABLE_BACKFILL" = "backfill" ]; then
|
|
||||||
PRE_COMMIT_HOOK="$HOOKS_DIR/pre-commit"
|
|
||||||
cp "$SCRIPT_DIR/pre-commit-backfill" "$PRE_COMMIT_HOOK"
|
|
||||||
chmod +x "$PRE_COMMIT_HOOK"
|
|
||||||
echo "✓ Pre-commit backfill hook installed (will backfill proofs before each commit)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Optionally setup .gitignore
|
|
||||||
if [ -f "$SCRIPT_DIR/setup-gitignore.sh" ]; then
|
|
||||||
"$SCRIPT_DIR/setup-gitignore.sh" "$REPO_PATH"
|
|
||||||
elif [ -f "$HOME/.openclaw/workspace/skills/git-ots-hook/scripts/setup-gitignore.sh" ]; then
|
|
||||||
"$HOME/.openclaw/workspace/skills/git-ots-hook/scripts/setup-gitignore.sh" "$REPO_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Next steps:"
|
|
||||||
echo "1. Ensure scripts are accessible (copy to repo root or install skill globally)"
|
|
||||||
echo "2. Verify ots CLI or @opentimestamps/ots is installed"
|
|
||||||
echo "3. Add .ots/ to git tracking: git add .ots/"
|
|
||||||
echo "4. Commit proofs: git commit -m 'Add OpenTimestamp proofs'"
|
|
||||||
echo "5. Make a test commit to verify the hooks work"
|
|
||||||
echo ""
|
|
||||||
echo "To uninstall:"
|
|
||||||
echo " rm $POST_COMMIT_HOOK"
|
|
||||||
if [ "$ENABLE_BACKFILL" = "backfill" ]; then
|
|
||||||
echo " rm $PRE_COMMIT_HOOK"
|
|
||||||
fi
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Pre-commit hook: backfill proofs for all commits before creating new commit
|
|
||||||
# This ensures all historical commits have attested proofs
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Get the directory where this hook is installed
|
|
||||||
HOOKS_DIR="$(git rev-parse --git-dir)/hooks"
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
|
|
||||||
# Find the backfill-proofs.sh script
|
|
||||||
BACKFILL_SCRIPT=""
|
|
||||||
|
|
||||||
if [ -f "$SCRIPT_DIR/backfill-proofs.sh" ]; then
|
|
||||||
BACKFILL_SCRIPT="$SCRIPT_DIR/backfill-proofs.sh"
|
|
||||||
elif [ -f ".git/hooks/backfill-proofs.sh" ]; then
|
|
||||||
BACKFILL_SCRIPT=".git/hooks/backfill-proofs.sh"
|
|
||||||
elif [ -f "backfill-proofs.sh" ]; then
|
|
||||||
BACKFILL_SCRIPT="./backfill-proofs.sh"
|
|
||||||
elif [ -f "$HOME/.openclaw/workspace/skills/git-ots-hook/scripts/backfill-proofs.sh" ]; then
|
|
||||||
BACKFILL_SCRIPT="$HOME/.openclaw/workspace/skills/git-ots-hook/scripts/backfill-proofs.sh"
|
|
||||||
else
|
|
||||||
# Silently skip if backfill script not found
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x "$BACKFILL_SCRIPT"
|
|
||||||
|
|
||||||
echo "[ots] Backfilling proofs before commit..."
|
|
||||||
"$BACKFILL_SCRIPT" .
|
|
||||||
|
|
||||||
echo "[ots] Ready to commit"
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# setup-gitignore.sh - Create/update .gitignore for OpenTimestamp proofs
|
|
||||||
# Usage: setup-gitignore.sh [repository-path]
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
REPO_PATH="${1:-.}"
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
GITIGNORE=".gitignore"
|
|
||||||
|
|
||||||
# Create .gitignore if it doesn't exist
|
|
||||||
if [ ! -f "$GITIGNORE" ]; then
|
|
||||||
echo "# OpenTimestamp proofs cache (exclude from version control)" > "$GITIGNORE"
|
|
||||||
echo ".ots/.attestation-cache" >> "$GITIGNORE"
|
|
||||||
echo ""
|
|
||||||
echo "Created $GITIGNORE with OpenTimestamp cache exclusion"
|
|
||||||
else
|
|
||||||
# Check if already has the cache exclusion
|
|
||||||
if grep -q ".ots/.attestation-cache" "$GITIGNORE"; then
|
|
||||||
echo "$GITIGNORE already excludes .ots/.attestation-cache"
|
|
||||||
else
|
|
||||||
echo "" >> "$GITIGNORE"
|
|
||||||
echo "# OpenTimestamp proofs cache (exclude from version control)" >> "$GITIGNORE"
|
|
||||||
echo ".ots/.attestation-cache" >> "$GITIGNORE"
|
|
||||||
echo "Added .ots/.attestation-cache to $GITIGNORE"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Next steps:"
|
|
||||||
echo "1. Review and commit your .gitignore"
|
|
||||||
echo "2. Add .ots/ directory to track proofs: git add .ots/"
|
|
||||||
echo "3. Commit proofs: git commit -m 'Add OpenTimestamp proofs'"
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue