#!/usr/bin/env bash
#
# Pre-commit hook for domin8 artifact verification
#
# This hook validates that programmatic commits match their artifact commit messages
# and ensures artifact integrity for MCP-governed changes.
#
# Installation:
# ln -s ../../scripts/pre-commit .git/hooks/pre-commit
# chmod +x .git/hooks/pre-commit
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "🔍 domin8 pre-commit validation..."
# Get the commit message being used
COMMIT_MSG_FILE=".git/COMMIT_EDITMSG"
if [ ! -f "$COMMIT_MSG_FILE" ]; then
echo -e "${YELLOW}⚠️ No commit message file found, skipping validation${NC}"
exit 0
fi
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# Check if this is a programmatic commit (contains "Programmatic Commit" marker)
if echo "$COMMIT_MSG" | grep -q "^# Programmatic Commit"; then
echo "📋 Detected programmatic commit, validating..."
# Extract artifact UUID from commit message
ARTIFACT_UUID=$(echo "$COMMIT_MSG" | grep "^Artifact UUID:" | awk '{print $3}')
if [ -z "$ARTIFACT_UUID" ]; then
echo -e "${RED}❌ Error: Programmatic commit missing artifact UUID${NC}"
echo "Commit message must contain 'Artifact UUID: <uuid>'"
exit 1
fi
echo "🔎 Validating artifact: $ARTIFACT_UUID"
# Find the artifact directory
AGENT_DATA_ROOT="$HOME/.domin8/agent_data"
ARTIFACT_DIR=""
for file_dir in "$AGENT_DATA_ROOT"/*; do
if [ -d "$file_dir/artifacts/$ARTIFACT_UUID" ]; then
ARTIFACT_DIR="$file_dir/artifacts/$ARTIFACT_UUID"
break
fi
done
if [ -z "$ARTIFACT_DIR" ]; then
echo -e "${RED}❌ Error: Artifact $ARTIFACT_UUID not found${NC}"
exit 1
fi
# Verify artifact has commit.md
if [ ! -f "$ARTIFACT_DIR/commit.md" ]; then
echo -e "${RED}❌ Error: Artifact missing commit.md${NC}"
exit 1
fi
# Read the artifact's commit message
ARTIFACT_COMMIT_MSG=$(cat "$ARTIFACT_DIR/commit.md")
# Compare commit messages (ignore comments and whitespace)
COMMIT_MSG_CLEAN=$(echo "$COMMIT_MSG" | grep -v '^#' | sed '/^$/d')
ARTIFACT_COMMIT_MSG_CLEAN=$(echo "$ARTIFACT_COMMIT_MSG" | grep -v '^#' | sed '/^$/d')
if [ "$COMMIT_MSG_CLEAN" != "$ARTIFACT_COMMIT_MSG_CLEAN" ]; then
echo -e "${RED}❌ Error: Commit message doesn't match artifact commit.md${NC}"
echo ""
echo "Expected (from artifact):"
echo "$ARTIFACT_COMMIT_MSG_CLEAN"
echo ""
echo "Got:"
echo "$COMMIT_MSG_CLEAN"
exit 1
fi
# Verify artifact status
ARTIFACT_STATUS=$(python3 -c "import json; print(json.load(open('$ARTIFACT_DIR/meta.json'))['status'])")
if [ "$ARTIFACT_STATUS" != "approved" ] && [ "$ARTIFACT_STATUS" != "committed" ]; then
echo -e "${RED}❌ Error: Artifact status is '$ARTIFACT_STATUS', must be 'approved'${NC}"
exit 1
fi
# Verify artifact integrity
if ! uv run domin8 verify "$ARTIFACT_UUID" &>/dev/null; then
echo -e "${RED}❌ Error: Artifact verification failed${NC}"
exit 1
fi
echo -e "${GREEN}✅ Programmatic commit validated${NC}"
fi
# Check for manual edits to programmatic commits (detection heuristic)
STAGED_FILES=$(git diff --cached --name-only)
for file in $STAGED_FILES; do
# Check if file was part of a recent programmatic commit
LAST_COMMIT_MSG=$(git log -1 --format=%B -- "$file" 2>/dev/null || echo "")
if echo "$LAST_COMMIT_MSG" | grep -q "^# Programmatic Commit"; then
echo -e "${YELLOW}⚠️ Warning: Staging changes to file from programmatic commit: $file${NC}"
echo " Consider creating a new artifact instead of manual edits"
fi
done
echo -e "${GREEN}✅ Pre-commit validation passed${NC}"
exit 0