summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-11 14:47:10 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-11 15:01:57 +0200
commit42b02c47be9b285099203e44a2570636d4ca6f03 (patch)
tree82bcb9e19bd886f36e1ca7b2d94a204c988f1fd1 /scripts
downloadkrino-42b02c47be9b285099203e44a2570636d4ca6f03.tar.gz
krino-42b02c47be9b285099203e44a2570636d4ca6f03.zip
krino: foundation — sexp reader, config language, init/new/check
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/hooks/pre-commit4
-rwxr-xr-xscripts/leak-check70
2 files changed, 74 insertions, 0 deletions
diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit
new file mode 100755
index 0000000..ec9f507
--- /dev/null
+++ b/scripts/hooks/pre-commit
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Installed by `make install-hooks`: refuse commits that carry personal data.
+exec "$(git rev-parse --show-toplevel)/scripts/leak-check"
diff --git a/scripts/leak-check b/scripts/leak-check
new file mode 100755
index 0000000..fbbd5d5
--- /dev/null
+++ b/scripts/leak-check
@@ -0,0 +1,70 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# leak-check: refuse personal data in the files git would commit.
+#
+# Scans every staged file (the index, not the working tree), and the names
+# of staged files against the private list, for:
+# - the current user's home directory, e.g. /home/alice;
+# - email addresses (LICENSE is exempt);
+# - a private pattern list: one extended regular expression per line,
+# blank lines and lines starting with # ignored, matched ignoring case.
+# Its path is set per clone with: git config krino.leakpatterns FILE
+# Keep that file outside the repository so the list is never published.
+#
+# A line matching the regex in `git config krino.leakallow` is never
+# reported (for example a public contact address in the README).
+#
+# Prints file:line for each hit, never the matched text, so a hit on a
+# private pattern does not echo the secret. Exits 0 when clean, 1 when
+# something matched, 2 when the private list is configured but missing.
+
+set -eu
+
+cd "$(git rev-parse --show-toplevel)"
+
+allow=$(git config --get krino.leakallow || true)
+hits=0
+
+# check LABEL GREP-ARGS...: report staged lines that match, as file:line.
+check() {
+ label=$1
+ shift
+ out=$(git grep --cached -n -I "$@" | { if [ -n "$allow" ]; then grep -v -E -i -e "$allow"; else cat; fi; } | cut -d: -f1,2 || true)
+ if [ -n "$out" ]; then
+ printf 'leak-check: %s:\n%s\n' "$label" "$out" | sed '2,$s/^/ /' >&2
+ hits=1
+ fi
+}
+
+home=${HOME%/} # a HOME of / becomes empty and is skipped
+if [ -n "$home" ]; then
+ check "your home directory ($home)" -F -e "$home" -- .
+fi
+
+check "an email address" -E -e '[[:alnum:]._%+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}' -- . ':(exclude)LICENSE'
+
+list=$(git config --type=path --get krino.leakpatterns || true)
+if [ -z "$list" ]; then
+ echo "leak-check: no private pattern list (git config krino.leakpatterns FILE); built-in checks only" >&2
+elif [ ! -r "$list" ]; then
+ echo "leak-check: private pattern list $list is configured but cannot be read" >&2
+ exit 2
+else
+ patterns=$(mktemp)
+ trap 'rm -f "$patterns"' EXIT
+ grep -v -e '^[[:space:]]*#' -e '^[[:space:]]*$' "$list" > "$patterns" || true
+ if [ -s "$patterns" ]; then
+ check "a private pattern from $list" -i -E -f "$patterns" -- .
+ named=$(git ls-files --cached | grep -i -E -f "$patterns" || true)
+ if [ -n "$named" ]; then
+ printf 'leak-check: a file name matching a private pattern:\n%s\n' "$named" | sed '2,$s/^/ /' >&2
+ hits=1
+ fi
+ fi
+fi
+
+if [ "$hits" -ne 0 ]; then
+ echo "leak-check: remove the data above before committing; for a false positive, narrow the pattern or set krino.leakallow" >&2
+ exit 1
+fi