From f58d0a5a154c67d25074d8a96d6dfb6af1160be7 Mon Sep 17 00:00:00 2001 From: Sami Ahmed Date: Sun, 21 Jun 2026 16:41:14 -0700 Subject: [PATCH] scripts: add pre-commit hook that auto-validates .onion addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hook scans every staged file for: 1. Filename matches: triangles.conf, *.onion 2. Content matches: lines starting with 'addnode=' followed by a base32-encoded .onion address If any address fails v3 onion checksum validation, the commit is blocked with a clear diagnostic showing the bad address, the reason, and (when possible) a suggestion of the correct address. Run with --ci mode on the validator so it exits 1 on any failure. Install: cp scripts/pre-commit .git/hooks/pre-commit chmod +x .git/hooks/pre-commit Bypass (NEVER do this for normal commits): git commit --no-verify Tested: ✓ Clean config: commit allowed, validator says PASSED ✓ Corrupted config (btb6 vs gtb6): commit blocked with full diagnostic + 'did you mean: gtb6?' suggestion --- scripts/pre-commit | 106 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 scripts/pre-commit diff --git a/scripts/pre-commit b/scripts/pre-commit new file mode 100755 index 0000000..a7fa7e2 --- /dev/null +++ b/scripts/pre-commit @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# .git/hooks/pre-commit — Cryptographic Triangles +# +# Auto-runs scripts/validate_onion_seeds.py against any staged file that +# contains .onion addresses. Blocks the commit if any address fails v3 +# onion checksum validation. +# +# This is the primary defense against the "1-character .onion transposition +# bug" that caused 4,842 Tor "No more HSDir" errors during the 2026-06-21 +# from-zero sync test. See scripts/validate_onion_seeds.py for the validator +# and references/sync-security-audit-2026-06-21.md for the full story. +# +# The hook scans staged files for two patterns: +# 1. Filename matches: triangles.conf, *.onion +# 2. Content contains addnode= entries with .onion addresses +# +# To install: +# cp scripts/pre-commit .git/hooks/pre-commit +# chmod +x .git/hooks/pre-commit +# +# To bypass (in emergencies only — NEVER do this for normal commits): +# git commit --no-verify + +set -e + +REPO_ROOT="$(git rev-parse --show-toplevel)" +VALIDATOR="${REPO_ROOT}/scripts/validate_onion_seeds.py" + +# Find the validator +if [[ ! -x "$VALIDATOR" ]]; then + echo "pre-commit: WARNING: $VALIDATOR not found or not executable" >&2 + echo "pre-commit: skipping v3 onion validation" >&2 + echo "pre-commit: install with: chmod +x $VALIDATOR" >&2 + exit 0 +fi + +# Two-pass detection: +# Pass 1: filename-based — files named triangles.conf or *.onion +# Pass 2: content-based — any file containing "addnode=" + .onion address + +STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR) + +# Pass 1: filename-based +NAME_MATCHES=$(echo "$STAGED_FILES" | grep -E '(triangles\.conf$|\.onion$)' || true) + +# Pass 2: content-based — find staged files containing addnode= with .onion addresses +CONTENT_MATCHES="" +for f in $STAGED_FILES; do + if [[ -f "$f" ]] && grep -qE '^[[:space:]]*addnode=[a-z2-7]{56}\.onion' "$f" 2>/dev/null; then + CONTENT_MATCHES="$CONTENT_MATCHES $f" + fi +done + +# Combine and dedupe +ALL_MATCHES=$(printf "%s\n%s\n" "$NAME_MATCHES" "$CONTENT_MATCHES" | sort -u | grep -v '^$' || true) + +if [[ -z "$ALL_MATCHES" ]]; then + # Nothing to validate + exit 0 +fi + +# Filter to only files that exist (skip deletions) +EXISTING_CONFIGS="" +for f in $ALL_MATCHES; do + if [[ -f "$f" ]]; then + EXISTING_CONFIGS="$EXISTING_CONFIGS $f" + fi +done + +if [[ -z "$EXISTING_CONFIGS" ]]; then + exit 0 +fi + +COUNT=$(echo $EXISTING_CONFIGS | wc -w) +echo "pre-commit: validating $COUNT staged file(s) with .onion addresses..." + +# Build the validator command +CMD="python3 \"$VALIDATOR\" --no-color --ci" +if [[ -f "${REPO_ROOT}/src/onionseed.h" ]]; then + CMD="$CMD --against \"${REPO_ROOT}/src/onionseed.h\"" +fi + +# Run the validator +if eval $CMD $EXISTING_CONFIGS; then + echo "pre-commit: v3 onion validation PASSED" + exit 0 +else + EXIT_CODE=$? + echo "" >&2 + echo "pre-commit: v3 onion validation FAILED (exit $EXIT_CODE)" >&2 + echo "" >&2 + echo " The commit was blocked because one or more .onion addresses failed" >&2 + echo " v3 hidden service checksum validation. This means the .onion address" >&2 + echo " has a typo or character transposition that Tor will reject at runtime" >&2 + echo " with 'ed25519 validation failed' / 'No more HSDir available to query'." >&2 + echo "" >&2 + echo " Fix the .onion address in the affected file, then re-stage and commit." >&2 + echo "" >&2 + echo " To inspect the failure in detail, run manually:" >&2 + echo " python3 $VALIDATOR --against ${REPO_ROOT}/src/onionseed.h \\" >&2 + echo " $EXISTING_CONFIGS" >&2 + echo "" >&2 + echo " To bypass this check (DO NOT do this for normal commits):" >&2 + echo " git commit --no-verify" >&2 + exit 1 +fi