Hook chain repairs (Group A):
- alignment-check.sh: read .prompt (was .user_prompt) — hook was dead
- block-dangerous.sh: jq instead of inline interpreter (RULE 0.2 + fail-open fix)
- destructive-guard.sh: explicit INPUT=cat + jq guard + exit 0 — was silent no-op
- numeric-claims-guard.sh: exit 1 -> exit 2 (Claude Code spec — was non-blocking)
comments updated 0.17 -> 0.18 (env var name kept)
- no-downgrade.sh: removed (?i) PCRE syntax — POSIX ERE matched literal text
- task-timer.sh: jq -nc instead of bare printf — JSON injection on quotes/backslashes
in description was corrupting RULE 0.18 evidence journal
- check-error-patterns.sh: replaced with no-op stub — had hardcoded /Users/denis/...
PATH LEAK in public kit, plus inline interpreter use
- post-commit-audit.sh: added trailing exit 0 — grep return code was hook exit code
- citation-verify.sh: ALLOW_REGEX accepts HOOK-BYPASS marker — bypass was documented
but never matched
- settings-snippet.json: agent-stub-scan moved PreToolUse:Agent -> PostToolUse:Agent
(RULE 0.16 enforcement was firing before transcript existed)
- check-error-patterns hook removed from settings-snippet.json
New defensive hooks (Group H):
- no-github-push.sh: PreToolUse:Bash hard deny on github.com push/create/sync/remote-add
(RULE 0.1 — patent IP protection; was missing from public kit)
- secrets-pre-guard.sh: PreToolUse:Edit|Write — token-pattern scan with allowlist (RULE 0.8)
- chat-numeric-prewarn.sh: UserPromptSubmit reminder when prompt mentions time/cost
(RULE 0.18 chat extension)
- chat-numeric-postflag.sh: Stop event scans last assistant message for naked numerics
without REAL/FROM-JOURNAL/ESTIMATE-HTC markers
Source: full Sonnet test-retest audit 2026-05-02 (3 parallel waves of 6 agents each)
identified hook chain bugs as HIGH severity in all 3 runs independently.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
86 lines
2.7 KiB
Bash
Executable file
86 lines
2.7 KiB
Bash
Executable file
#!/bin/sh
|
|
# no-github-push.sh — PreToolUse:Bash hard deny (RULE 0.1 NO GITHUB PUSH)
|
|
#
|
|
# Blocks any Bash command that would push code to github.com.
|
|
# KeiTech portfolio contains unfiled patent IP — a public push destroys
|
|
# priority date and trade secrets. Irrecoverable.
|
|
#
|
|
# Exit codes:
|
|
# 0 = pass (command is safe)
|
|
# 2 = block (Claude Code aborts the tool call)
|
|
#
|
|
# Bypass: set KEI_NO_GITHUB_PUSH_BYPASS=1 in the calling environment.
|
|
# Even with bypass, the rule is logged to stderr.
|
|
|
|
set -u
|
|
|
|
# Bypass check (must be explicit env, not embedded in command string)
|
|
if [ "${KEI_NO_GITHUB_PUSH_BYPASS:-0}" = "1" ]; then
|
|
printf '[no-github-push] BYPASS active (KEI_NO_GITHUB_PUSH_BYPASS=1). Proceeding.\n' >&2
|
|
exit 0
|
|
fi
|
|
|
|
# jq is required to parse the Claude Code hook input
|
|
if ! command -v jq > /dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
|
|
INPUT=$(cat)
|
|
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
|
|
[ -z "$COMMAND" ] && exit 0
|
|
|
|
# --- Pattern matching -------------------------------------------------------
|
|
# Match any of the forbidden surfaces (case-sensitive; github URLs are
|
|
# always lowercase in practice, but we anchor on the protocol/domain).
|
|
|
|
BLOCKED=0
|
|
|
|
# git push to github.com (HTTPS or SSH)
|
|
if printf '%s' "$COMMAND" | grep -qE 'git[[:space:]]+push[^|&;]*github\.com'; then
|
|
BLOCKED=1
|
|
fi
|
|
|
|
# git push to SSH shorthand git@github.com
|
|
if [ "$BLOCKED" -eq 0 ] && \
|
|
printf '%s' "$COMMAND" | grep -qE 'git[[:space:]]+push[^|&;]*git@github\.com'; then
|
|
BLOCKED=1
|
|
fi
|
|
|
|
# gh repo create (any visibility — creating a public repo leaks IP by default)
|
|
if [ "$BLOCKED" -eq 0 ] && \
|
|
printf '%s' "$COMMAND" | grep -qE 'gh[[:space:]]+repo[[:space:]]+create'; then
|
|
BLOCKED=1
|
|
fi
|
|
|
|
# gh repo sync (pushes local state to remote)
|
|
if [ "$BLOCKED" -eq 0 ] && \
|
|
printf '%s' "$COMMAND" | grep -qE 'gh[[:space:]]+repo[[:space:]]+sync'; then
|
|
BLOCKED=1
|
|
fi
|
|
|
|
# git remote add/set-url pointing at github.com
|
|
if [ "$BLOCKED" -eq 0 ] && \
|
|
printf '%s' "$COMMAND" | grep -qE 'git[[:space:]]+remote[[:space:]]+(add|set-url)[^|&;]*github\.com'; then
|
|
BLOCKED=1
|
|
fi
|
|
|
|
[ "$BLOCKED" -eq 0 ] && exit 0
|
|
|
|
# --- Block ------------------------------------------------------------------
|
|
cat >&2 <<'EOF'
|
|
[no-github-push] BLOCK — RULE 0.1 NO GITHUB PUSH
|
|
KeiTech portfolio contains unfiled patent IP. Public push destroys
|
|
priority date + trade secrets. Irrecoverable.
|
|
|
|
Use a private remote instead (Forgejo, Gitea, self-hosted):
|
|
git remote set-url origin ssh://git@<private-host>/<user>/<repo>.git
|
|
git push origin <branch>
|
|
|
|
Bypass (visible, per-call):
|
|
Set env KEI_NO_GITHUB_PUSH_BYPASS=1 before the command.
|
|
You must also add confirmation phrase: "yes, push patent code to github"
|
|
+ "confirm publication" in the session turn.
|
|
EOF
|
|
|
|
exit 2
|