Skip to content

Commit 894a49d

Browse files
dmealingclaude
andcommitted
fix(hooks): keep private names out of the committed hook
The previous hook listed private project names in its PATTERNS line — itself a leak in a public repo. The committed hook now contains only generic structural patterns (home paths) and loads project-name patterns from an untracked, gitignored .githooks/deny-list.local (template: deny-list.example). The guard now names no private project. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent d122713 commit 894a49d

3 files changed

Lines changed: 35 additions & 13 deletions

File tree

.githooks/deny-list.example

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Local denylist for the pre-commit hygiene hook (TEMPLATE — contains no real names).
2+
#
3+
# Copy to deny-list.local (which is gitignored) and add the real private/other-project
4+
# names you want blocked, one extended-regex per line. Blank lines and #-comments ignored.
5+
# Keeping the real names ONLY in the untracked .local file ensures this PUBLIC repo's
6+
# committed files never name a private project.
7+
#
8+
# Examples of the kinds of patterns to add locally (replace with your own):
9+
# some-private-app
10+
# another-client-name
11+
# @somescope/

.githooks/pre-commit

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,39 @@
11
#!/usr/bin/env bash
22
#
33
# metaobjects is a PUBLIC repository.
4-
# Block commits that leak private/other-project names or absolute local paths.
5-
# See CLAUDE.md -> "Public repository hygiene".
4+
# Block commits that leak absolute local paths, or private/other-project names.
5+
#
6+
# IMPORTANT: this committed hook names NO private project. The structural
7+
# patterns below are generic (home paths). Private project names live ONLY in an
8+
# UNTRACKED local denylist so the guard itself never becomes a leak:
9+
#
10+
# .githooks/deny-list.local (gitignored; one regex per line; you create it)
11+
# .githooks/deny-list.example (committed template, placeholders only)
612
#
713
# Activate (one-time, per clone): git config core.hooksPath .githooks
14+
# cp .githooks/deny-list.example .githooks/deny-list.local
15+
# # then edit deny-list.local with the real names
816
# Bypass (discouraged): git commit --no-verify
917
#
1018
set -uo pipefail
1119

12-
# Case-insensitive forbidden patterns. Keep in sync with CLAUDE.md.
13-
# - other/private project names (and known abbreviations/derivations)
14-
# - absolute local paths that leak a developer's home directory
15-
# NOTES:
16-
# - matches the separate "sibling-ai-project" project, NOT bare "draagon" — "com.draagon.meta"
17-
# is this project's own legacy package namespace and is legitimate.
18-
# - "trainer-website" is an accepted example-consumer name and is intentionally NOT guarded;
19-
# "downstream-consumer" / "@acme/" / "acme" (a private consumer) ARE guarded.
20-
PATTERNS='party-?lore|sibling-app|acme-?website|\bmikes\b|@acme/|acme|sibling-ai-project|csharp-adopter|sibling-project|/home/[A-Za-z0-9._-]+/|~/Development'
20+
# Generic, non-sensitive structural patterns — safe to commit (name no project):
21+
PATTERNS='/home/[A-Za-z0-9._-]+/|~/Development'
2122

2223
# Legitimate matches to ignore (e.g. the published npm author email).
2324
ALLOW='doug@dougmealing\.com'
2425

25-
# Scan only newly-ADDED staged lines, attributed to their file.
26+
# Merge in private-name patterns from the untracked local denylist, if present.
27+
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo .)"
28+
DENY_FILE="$ROOT/.githooks/deny-list.local"
29+
if [ -f "$DENY_FILE" ]; then
30+
extra=$(grep -vE '^[[:space:]]*(#|$)' "$DENY_FILE" | paste -sd'|' -)
31+
[ -n "$extra" ] && PATTERNS="$PATTERNS|$extra"
32+
fi
33+
34+
# Scan only newly-ADDED staged lines, attributed to their file; skip the hooks dir.
2635
hits=$(git diff --cached --diff-filter=ACM -U0 --no-color 2>/dev/null | awk '
2736
/^\+\+\+ / { f=$2; sub(/^b\//,"",f); next }
28-
# skip the hook itself (its PATTERNS line legitimately lists the forbidden words)
2937
/^\+/ && !/^\+\+\+/ { if (f !~ /^\.githooks\//) print f "\t" substr($0,2) }
3038
' | grep -Ei "$PATTERNS" | grep -vEi "$ALLOW")
3139

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ __pycache__/
3939
# Stryker mutation testing
4040
.stryker-tmp/
4141
reports/
42+
43+
# Local-only pre-commit denylist (must never be committed — would leak private names)
44+
.githooks/deny-list.local

0 commit comments

Comments
 (0)