igneum/tools/ci/founder-strings-check.sh
igneum-labs ff0d0dde61 Scrub: the founder list leaves the repository in every encoding; the never-push founder check decodes base64, hex and .b64 blobs too (7 October 2026, 21:4x UK)
tools/ci/founder-strings.b64 was the founder check's pattern list base64-encoded: a grep could not read it, any reader of the public host could (git.igneum.network was public from 21:26 UK; read off at 21:36). The list now lives only in a private file (~/.config/igneum/founder-strings on the Mac, /srv/discord-hooks/founder-strings on build-1 for the Discord guard; $IGNEUM_FOUNDER_STRINGS overrides) and site/forbidden-strings.txt carries no encoded copy. Readers: founder-strings-check.sh (skips with a line where the file is absent; the Mac's hook is the guard), site/scrub.mjs and launch-gates-check.mjs (the private file's patterns added where it exists), discord-hooks.mjs (three locations; the test writes a fixture list and loads the module after it), fresh-repo.sh (the private file; drops tools/ci/founder-strings.b64 from every commit; rewrites the base64 of every list regex out of every blob and scans for it).

The check's second pass (main's addition): every base64 literal of 24 characters or more, every hex literal of 24 or more and every *.b64 file is decoded and scanned, so no encoding hides a term again; the self-test plants each fixture sample in plain text, in a .b64 file, as a base64 literal and as a hex literal, each caught and named, and a tree without the list skips with its line.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 20:40:36 +00:00

84 lines
6.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# No founder name, personal login, earlier business or personal address in any tracked text file, in plain text OR in an encoding
# (the pre-public scrub, 7 October 2026; a never-push class since 20:5x UK: every push, every branch). The identity check
# (tools/ci/identity-check.sh) reads the public EXPORT list; this one reads EVERY tracked file, because the repository itself
# is public (git.igneum.network).
#
# The patterns are NOT in the repository in any form. They live in a private file, ~/.config/igneum/founder-strings
# ($IGNEUM_FOUNDER_STRINGS overrides; one row per pattern: perl regex, a tab, a sample the self-test plants; # comments), on the
# Mac that pushes. A base64 copy in the tree (tools/ci/founder-strings.b64, 19:5x to 21:3x UK) was a disclosure to any reader of
# the public host and is gone from every commit. Where the file is absent (a hosted CI runner, a box) the check prints a skip
# line and passes; the Mac's pre-push hook, which has the file, is the guard.
#
# Two passes over every tracked text file: the plain text, then every encoded blob decoded and scanned (base64 literals of 24
# characters or more, every *.b64 file whole, hex literals of 24 characters or more), so an encoding never hides a term again.
#
# tools/ci/founder-strings-check.sh # exit 1 with file:line for every hit (decoded hits say so); exit 0 with a skip line without the list
# tools/ci/founder-strings-check.sh --self-test # with a FIXTURE list of made-up names (never the real file): a clean tree passes; each
# # sample planted in plain text, in a .b64 file, as a base64 literal and as a hex literal is
# # caught and names its file; a tree without the list skips with the line
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
LIST="${IGNEUM_FOUNDER_STRINGS:-$HOME/.config/igneum/founder-strings}"
REPO="${FOUNDER_CHECK_REPO:-$(cd "$HERE/../.." && pwd)}"
rows() { grep -vE '^\s*(#|$)' "$LIST"; } # the live rows
scan() { # <repo> <list>: plain pass, then the decoded pass; prints "file:line:text" or "file:line:(decoded <kind>) text"; exit 1 on any hit
local repo="$1" list="$2" pats hits
pats="$(mktemp)"; chmod 600 "$pats"; grep -vE '^\s*(#|$)' "$list" | cut -f1 > "$pats"
hits="$(cd "$repo" && git ls-files -z -- . ':!*.png' ':!*.jpg' ':!*.jpeg' ':!*.gif' ':!*.ico' ':!*.woff' ':!*.woff2' ':!*.ttf' ':!*.pdf' ':!*.zip' ':!*.bin' \
| xargs -0 perl -e '
use MIME::Base64 qw(decode_base64);
my $pf = shift @ARGV; open(my $ph, "<", $pf) or die; my @pats = map { chomp; qr/$_/i } grep { /\S/ } <$ph>; close $ph;
sub hit { my ($t) = @_; for my $p (@pats) { return 1 if $t =~ $p } 0 }
for my $f (@ARGV) {
next unless -f $f && -T $f; open(my $h, "<", $f) or next; my $n = 0; my $whole = "";
while (my $l = <$h>) {
$n++; $whole .= $l;
if (hit($l)) { chomp $l; print "$f:$n:" . substr($l, 0, 160) . "\n"; next }
# the encoded pass on this line: base64 literals and hex literals of 24 characters or more
while ($l =~ /([A-Za-z0-9+\/]{24,}={0,2})/g) { my $d = decode_base64($1); next unless length $d; if (hit($d)) { print "$f:$n:(decoded base64) " . substr($d =~ s/[^\x20-\x7e]/./gr, 0, 120) . "\n"; last } }
while ($l =~ /\b([0-9a-fA-F]{24,})\b/g) { my $x = $1; next if length($x) % 2; my $d = pack("H*", $x); if (hit($d)) { print "$f:$n:(decoded hex) " . substr($d =~ s/[^\x20-\x7e]/./gr, 0, 120) . "\n"; last } }
}
close $h;
# a .b64 file as one blob
if ($f =~ /\.b64$/) { (my $b = $whole) =~ s/\s+//g; my $d = decode_base64($b); if (length $d && hit($d)) { print "$f:1:(decoded .b64 file) " . substr($d =~ s/[^\x20-\x7e]/./gr, 0, 120) . "\n" } }
}
' "$pats" 2>/dev/null || true)"
rm -f "$pats"
if [ -n "$hits" ]; then printf '%s\n' "$hits" | sed 's/^/founder-strings: /' >&2; return 1; fi
return 0
}
if [ "${1:-}" = "--self-test" ]; then
top="$(mktemp -d)"; trap 'rm -rf "$top"' EXIT; fx="$top/repo"; mkdir -p "$fx"
fixture="$top/list"; printf '# fixture\n\\bfoundername\\b\tfoundername\n\\bsurnamex\\b\tSurnamex\n\\bbiznamez\\b\tbiznamez\n' > "$fixture"
( cd "$fx" && git init -q -b master . ); mkdir -p "$fx/docs" "$fx/tools/ci" "$fx/site"
printf 'Commit as igneum-labs. The founder decided on 5 October 2026. Igneum Labs LTD, DIFC.\n' > "$fx/docs/clean.md"
printf 'aGVsbG8gd29ybGQsIG5vdGhpbmcgaGVyZQ==\n' > "$fx/tools/ci/clean.b64" # "hello world, nothing here"
( cd "$fx" && git add -A && git -c user.name=t -c user.email=t@t commit -q -m c )
fails=0
scan "$fx" "$fixture" >/dev/null 2>&1 || { echo "self-test failed: a clean tree (with a harmless .b64) was reported"; fails=1; }
i=0
while IFS=$'\t' read -r re sample; do
i=$((i + 1)); [ -n "$sample" ] || continue
for kind in plain b64file base64 hex; do
case "$kind" in
plain) f="docs/hit-$i.md"; printf 'a line that names %s in passing\n' "$sample" > "$fx/$f" ;;
b64file) f="tools/ci/hit-$i.b64"; printf 'a line that names %s in passing\n' "$sample" | base64 > "$fx/$f" ;;
base64) f="site/hit-$i.mjs"; printf 'const X = "%s";\n' "$(printf 'a line that names %s in passing' "$sample" | base64 | tr -d '\n')" > "$fx/$f" ;;
hex) f="site/hit-$i-hex.mjs"; printf 'const H = "%s";\n' "$(printf 'a line that names %s in passing' "$sample" | xxd -p | tr -d '\n')" > "$fx/$f" ;;
esac
( cd "$fx" && git add -A && git -c user.name=t -c user.email=t@t commit -q -m "h" )
if out="$(scan "$fx" "$fixture" 2>&1)"; then echo "self-test failed: pattern $i was not caught as $kind"; fails=1
else case "$out" in *"$f"*) ;; *) echo "self-test failed: the $kind hit for pattern $i did not name $f: $out"; fails=1 ;; esac; fi
rm -f "$fx/$f"; ( cd "$fx" && git add -A && git -c user.name=t -c user.email=t@t commit -q -m "r" )
done
done < <(grep -vE '^\s*(#|$)' "$fixture")
# without a list: the skip line, exit 0
out="$(IGNEUM_FOUNDER_STRINGS="$fx/no-such-list" FOUNDER_CHECK_REPO="$fx" bash "$0" 2>&1)" && case "$out" in *"skipped, no private list"*) ;; *) echo "self-test failed: no skip line without the list: $out"; fails=1 ;; esac || { echo "self-test failed: a tree without the list did not pass with a skip line"; fails=1; }
[ "$fails" = 0 ] && echo "self-test passed: a clean tree passes; every fixture pattern is caught in plain text, in a .b64 file, as a base64 literal and as a hex literal, each naming its file; without the private list the check skips with its line"
exit $fails
fi
if [ ! -s "$LIST" ]; then echo "founder-strings: skipped, no private list at $LIST (the Mac's pre-push hook carries the list and is the guard; a runner or box has none)"; exit 0; fi
scan "$REPO" "$LIST" && echo "founder-strings: no founder name, personal login, earlier business or personal address in any tracked text file, plain or encoded ($(rows | wc -l | tr -d ' ') patterns from the private list)"