Skip to content

Commit 93d756c

Browse files
committed
feat(git-hooks): make security checks mandatory, lint/test optional
Synchronized git hooks from socket-registry to enforce security at push-time while allowing fast local commits with --no-verify. **Bypassable with --no-verify**: - Lint - Unit tests **NOT bypassable** (enforced at push): - AI attribution detection - Security checks (API keys, secrets, .env files, etc.) See socket-registry commit f57bbb18 for full details.
1 parent ef04c02 commit 93d756c

File tree

4 files changed

+115
-45
lines changed

4 files changed

+115
-45
lines changed

.git-hooks/pre-push

Lines changed: 109 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/bin/bash
22
# Socket Security Pre-push Hook
3-
# Final security check before pushing to remote.
3+
# MANDATORY ENFORCEMENT LAYER - Cannot be bypassed with --no-verify.
4+
# Validates all commits being pushed for security issues and AI attribution.
45

56
set -e
67

@@ -10,7 +11,7 @@ YELLOW='\033[1;33m'
1011
GREEN='\033[0;32m'
1112
NC='\033[0m'
1213

13-
echo "${GREEN}Running final security validation before push...${NC}"
14+
echo "${GREEN}Running mandatory pre-push validation...${NC}"
1415

1516
# Allowed public API key (used in socket-lib).
1617
ALLOWED_PUBLIC_KEY="sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api"
@@ -19,6 +20,8 @@ ALLOWED_PUBLIC_KEY="sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api"
1920
remote="$1"
2021
url="$2"
2122

23+
TOTAL_ERRORS=0
24+
2225
# Read stdin for refs being pushed.
2326
while read local_ref local_sha remote_ref remote_sha; do
2427
# Get the range of commits being pushed.
@@ -30,59 +33,122 @@ while read local_ref local_sha remote_ref remote_sha; do
3033
range="$remote_sha..$local_sha"
3134
fi
3235

33-
# Get all files changed in these commits.
34-
CHANGED_FILES=$(git diff --name-only "$range" 2>/dev/null || echo "")
35-
36-
if [ -z "$CHANGED_FILES" ]; then
37-
continue
38-
fi
39-
4036
ERRORS=0
4137

42-
# Check for sensitive files.
43-
if echo "$CHANGED_FILES" | grep -qE '^\.env(\.local)?$'; then
44-
echo "${RED}✗ BLOCKED: Attempting to push .env file!${NC}"
45-
echo "Files: $(echo "$CHANGED_FILES" | grep -E '^\.env(\.local)?$')"
46-
ERRORS=$((ERRORS + 1))
47-
fi
38+
# ============================================================================
39+
# CHECK 1: Scan commit messages for AI attribution
40+
# ============================================================================
41+
echo "Checking commit messages for AI attribution..."
4842

49-
# Check for .DS_Store.
50-
if echo "$CHANGED_FILES" | grep -q '\.DS_Store'; then
51-
echo "${YELLOW}⚠ WARNING: .DS_Store file in push${NC}"
52-
echo "Files: $(echo "$CHANGED_FILES" | grep '\.DS_Store')"
53-
fi
43+
# Check each commit in the range for AI patterns.
44+
while IFS= read -r commit_sha; do
45+
full_msg=$(git log -1 --format='%B' "$commit_sha")
5446

55-
# Sample files for API keys (only check files that exist).
56-
for file in $CHANGED_FILES; do
57-
if [ -f "$file" ] && [ ! -d "$file" ]; then
58-
# Skip test files.
59-
if echo "$file" | grep -qE '\.(test|spec)\.|/test/|/tests/|fixtures/|\.example$'; then
60-
continue
61-
fi
62-
63-
# Check for Socket API keys.
64-
if grep -E 'sktsec_[a-zA-Z0-9_-]{40,}' "$file" 2>/dev/null | grep -v "$ALLOWED_PUBLIC_KEY" | grep -v 'your_api_key_here' | grep -v 'fake-token' | grep -v 'test-token' | grep -q .; then
65-
echo "${RED}✗ BLOCKED: Real API key detected in push!${NC}"
66-
echo "File: $file"
67-
echo "Line(s):"
68-
grep -n 'sktsec_' "$file" | grep -v "$ALLOWED_PUBLIC_KEY" | grep -v 'your_api_key_here' | grep -v 'fake-token' | grep -v 'test-token' | head -3
69-
ERRORS=$((ERRORS + 1))
47+
if echo "$full_msg" | grep -qiE "(Generated with|Co-Authored-By: Claude|Co-Authored-By: AI|🤖 Generated|AI generated|Claude Code|@anthropic|Assistant:|Generated by Claude|Machine generated)"; then
48+
if [ $ERRORS -eq 0 ]; then
49+
echo "${RED}✗ BLOCKED: AI attribution found in commit messages!${NC}"
50+
echo "Commits with AI attribution:"
7051
fi
52+
echo " - $(git log -1 --oneline "$commit_sha")"
53+
ERRORS=$((ERRORS + 1))
7154
fi
72-
done
55+
done < <(git rev-list "$range")
7356

7457
if [ $ERRORS -gt 0 ]; then
7558
echo ""
76-
echo "${RED}✗ Push blocked by security validation!${NC}"
77-
echo "Remove sensitive data from your commits before pushing."
59+
echo "These commits were likely created with --no-verify, bypassing the"
60+
echo "commit-msg hook that strips AI attribution."
7861
echo ""
7962
echo "To fix:"
80-
echo " 1. Remove sensitive data from files"
81-
echo " 2. Amend or rebase your commits"
82-
echo " 3. Push again"
83-
exit 1
63+
echo " git rebase -i $remote_sha"
64+
echo " Mark commits as 'reword', remove AI attribution, save"
65+
echo " git push"
66+
fi
67+
68+
# ============================================================================
69+
# CHECK 2: File content security checks
70+
# ============================================================================
71+
echo "Checking files for security issues..."
72+
73+
# Get all files changed in these commits.
74+
CHANGED_FILES=$(git diff --name-only "$range" 2>/dev/null || echo "")
75+
76+
if [ -n "$CHANGED_FILES" ]; then
77+
# Check for sensitive files.
78+
if echo "$CHANGED_FILES" | grep -qE '^\.env(\.local)?$'; then
79+
echo "${RED}✗ BLOCKED: Attempting to push .env file!${NC}"
80+
echo "Files: $(echo "$CHANGED_FILES" | grep -E '^\.env(\.local)?$')"
81+
ERRORS=$((ERRORS + 1))
82+
fi
83+
84+
# Check for .DS_Store.
85+
if echo "$CHANGED_FILES" | grep -q '\.DS_Store'; then
86+
echo "${RED}✗ BLOCKED: .DS_Store file in push!${NC}"
87+
echo "Files: $(echo "$CHANGED_FILES" | grep '\.DS_Store')"
88+
ERRORS=$((ERRORS + 1))
89+
fi
90+
91+
# Check for log files.
92+
if echo "$CHANGED_FILES" | grep -E '\.log$' | grep -v 'test.*\.log' | grep -q .; then
93+
echo "${RED}✗ BLOCKED: Log file in push!${NC}"
94+
echo "Files: $(echo "$CHANGED_FILES" | grep -E '\.log$' | grep -v 'test.*\.log')"
95+
ERRORS=$((ERRORS + 1))
96+
fi
97+
98+
# Check file contents for secrets.
99+
for file in $CHANGED_FILES; do
100+
if [ -f "$file" ] && [ ! -d "$file" ]; then
101+
# Skip test files, example files, and hook scripts.
102+
if echo "$file" | grep -qE '\.(test|spec)\.(m?[jt]s|tsx?)$|\.example$|/test/|/tests/|fixtures/|\.git-hooks/|\.husky/'; then
103+
continue
104+
fi
105+
106+
# Check for hardcoded user paths.
107+
if grep -E '(/Users/[^/\s]+/|/home/[^/\s]+/|C:\\Users\\[^\\]+\\)' "$file" 2>/dev/null | grep -q .; then
108+
echo "${RED}✗ BLOCKED: Hardcoded personal path found in: $file${NC}"
109+
grep -n -E '(/Users/[^/\s]+/|/home/[^/\s]+/|C:\\Users\\[^\\]+\\)' "$file" | head -3
110+
ERRORS=$((ERRORS + 1))
111+
fi
112+
113+
# Check for Socket API keys.
114+
if grep -E 'sktsec_[a-zA-Z0-9_-]+' "$file" 2>/dev/null | grep -v "$ALLOWED_PUBLIC_KEY" | grep -v 'your_api_key_here' | grep -v 'SOCKET_SECURITY_API_KEY=' | grep -v 'fake-token' | grep -v 'test-token' | grep -q .; then
115+
echo "${RED}✗ BLOCKED: Real API key detected in: $file${NC}"
116+
grep -n 'sktsec_' "$file" | grep -v "$ALLOWED_PUBLIC_KEY" | grep -v 'your_api_key_here' | grep -v 'fake-token' | grep -v 'test-token' | head -3
117+
ERRORS=$((ERRORS + 1))
118+
fi
119+
120+
# Check for AWS keys.
121+
if grep -iE '(aws_access_key|aws_secret|AKIA[0-9A-Z]{16})' "$file" 2>/dev/null | grep -q .; then
122+
echo "${RED}✗ BLOCKED: Potential AWS credentials found in: $file${NC}"
123+
grep -n -iE '(aws_access_key|aws_secret|AKIA[0-9A-Z]{16})' "$file" | head -3
124+
ERRORS=$((ERRORS + 1))
125+
fi
126+
127+
# Check for GitHub tokens.
128+
if grep -E 'gh[ps]_[a-zA-Z0-9]{36}' "$file" 2>/dev/null | grep -q .; then
129+
echo "${RED}✗ BLOCKED: Potential GitHub token found in: $file${NC}"
130+
grep -n -E 'gh[ps]_[a-zA-Z0-9]{36}' "$file" | head -3
131+
ERRORS=$((ERRORS + 1))
132+
fi
133+
134+
# Check for private keys.
135+
if grep -E '-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----' "$file" 2>/dev/null | grep -q .; then
136+
echo "${RED}✗ BLOCKED: Private key found in: $file${NC}"
137+
ERRORS=$((ERRORS + 1))
138+
fi
139+
fi
140+
done
84141
fi
142+
143+
TOTAL_ERRORS=$((TOTAL_ERRORS + ERRORS))
85144
done
86145

87-
echo "${GREEN}✓ Security validation passed!${NC}"
146+
if [ $TOTAL_ERRORS -gt 0 ]; then
147+
echo ""
148+
echo "${RED}✗ Push blocked by mandatory validation!${NC}"
149+
echo "Fix the issues above before pushing."
150+
exit 1
151+
fi
152+
153+
echo "${GREEN}✓ All mandatory validation passed!${NC}"
88154
exit 0

.husky/commit-msg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Run commit message validation and auto-strip AI attribution.
2+
.git-hooks/commit-msg "$1"

.husky/pre-commit

100644100755
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Run security checks first.
2-
.husky/security-checks.sh
1+
# Optional checks - can be bypassed with --no-verify for fast local commits.
2+
# Mandatory security checks run in pre-push hook.
33

44
if [ -z "${DISABLE_PRECOMMIT_LINT}" ]; then
55
pnpm lint --staged

.husky/pre-push

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Run pre-push security validation.
2+
.git-hooks/pre-push "$@"

0 commit comments

Comments
 (0)