cc-safe-setup 29.7.0 → 30.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1022) hide show
  1. package/.claude-plugin/marketplace.json +72 -19
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CONTRIBUTING.md +7 -2
  4. package/COOKBOOK.md +50 -46
  5. package/LICENSE +21 -0
  6. package/MIGRATION.md +8 -8
  7. package/README.md +419 -512
  8. package/SAFETY_CHECKLIST.md +15 -7
  9. package/SERVICES.md +194 -0
  10. package/SETTINGS_REFERENCE.md +236 -17
  11. package/SKILL.md +5 -5
  12. package/TROUBLESHOOTING.md +35 -14
  13. package/action.yml +12 -4
  14. package/audit/README.md +84 -0
  15. package/audit/audit-checklist.md +152 -0
  16. package/audit/boundary-selftest.sh +85 -0
  17. package/audit/boundary.sh +123 -0
  18. package/audit/count-hooks.py +42 -0
  19. package/audit/find-dead-hooks.sh +82 -0
  20. package/audit/find-unfirable-rules.sh +142 -0
  21. package/audit/fire.sh +97 -0
  22. package/audit/selftest.sh +42 -0
  23. package/audit/unfirable-selftest.sh +81 -0
  24. package/audit-web/index.html +9 -9
  25. package/examples/README.md +54 -17
  26. package/examples/account-billing-log.sh +98 -0
  27. package/examples/account-routing-preflight.sh +123 -0
  28. package/examples/agent-sdk-credit-pool-monitor.sh +145 -0
  29. package/examples/agent-view-quota-decrement.sh +32 -0
  30. package/examples/agent-view-quota-warn.sh +94 -0
  31. package/examples/agents-md-edit-drift-warner.sh +223 -0
  32. package/examples/agents-md-loader.sh +160 -0
  33. package/examples/agents-md-sync-checker.sh +102 -0
  34. package/examples/ai-slop-punctuation-arrest.sh +210 -0
  35. package/examples/allowlist.sh +70 -10
  36. package/examples/always-allow-pattern-suggester.sh +125 -0
  37. package/examples/ansible-vault-guard.sh +2 -1
  38. package/examples/anthropic-base-url-guard.sh +76 -0
  39. package/examples/api-busyloop-guard.sh +123 -0
  40. package/examples/api-endpoint-guard.sh +12 -0
  41. package/examples/api-key-in-url-guard.sh +17 -1
  42. package/examples/api-rate-limit-guard.sh +36 -1
  43. package/examples/api-rate-limit-tracker.sh +12 -0
  44. package/examples/articulated-scope-capture.sh +101 -0
  45. package/examples/askuserquestion-autonomy-gate.sh +102 -0
  46. package/examples/attachment-traversal-guard.sh +118 -0
  47. package/examples/aup-block-pattern-logger.sh +161 -0
  48. package/examples/aup-false-positive-helper.sh +124 -0
  49. package/examples/aup-large-tool-output-warner.sh +282 -0
  50. package/examples/aup-retry-loop-guard.sh +229 -0
  51. package/examples/auth-expiry-reminder.sh +157 -0
  52. package/examples/auth-macos-sleep-detector.sh +185 -0
  53. package/examples/auth-path-detector.sh +171 -0
  54. package/examples/auth-status-checker.sh +157 -0
  55. package/examples/authorized-reconfirmation-detector.sh +195 -0
  56. package/examples/auto-approve-build.sh +39 -0
  57. package/examples/auto-approve-cargo.sh +31 -1
  58. package/examples/auto-approve-docker.sh +35 -0
  59. package/examples/auto-approve-git-read.sh +37 -14
  60. package/examples/auto-approve-go.sh +30 -1
  61. package/examples/auto-approve-gradle.sh +29 -1
  62. package/examples/auto-approve-make.sh +29 -1
  63. package/examples/auto-approve-maven.sh +29 -1
  64. package/examples/auto-approve-python.sh +41 -1
  65. package/examples/auto-approve-readonly-tools.sh +1 -0
  66. package/examples/auto-approve-readonly.sh +110 -33
  67. package/examples/auto-approve-ssh.sh +30 -1
  68. package/examples/auto-approve-test.sh +44 -0
  69. package/examples/auto-checkpoint.sh +1 -1
  70. package/examples/auto-compact-prep.sh +0 -0
  71. package/examples/auto-git-checkpoint.sh +0 -0
  72. package/examples/auto-mode-safe-commands.sh +53 -1
  73. package/examples/auto-mode-safety-enforcer.sh +151 -4
  74. package/examples/auto-push-session-branch.sh +22 -0
  75. package/examples/aws-production-guard.sh +13 -1
  76. package/examples/aws-region-guard.sh +1 -1
  77. package/examples/background-cost-launch-guard.sh +82 -0
  78. package/examples/background-task-guard.sh +12 -0
  79. package/examples/backup-before-refactor.sh +0 -0
  80. package/examples/banned-command-guard.sh +12 -0
  81. package/examples/bash-allowlist-secondary-check.sh +157 -0
  82. package/examples/bash-domain-allowlist.sh +12 -0
  83. package/examples/bash-fanout-bounded-rewriter.sh +191 -0
  84. package/examples/bash-heuristic-approver.sh +112 -10
  85. package/examples/bash-project-fence.sh +194 -0
  86. package/examples/bash-safety-auto-deny.sh +12 -0
  87. package/examples/bash-secret-output-detector.sh +44 -3
  88. package/examples/bash-trace-guard.sh +12 -0
  89. package/examples/bashrc-safety-check.sh +0 -0
  90. package/examples/bg-permission-prompt-warner.sh +182 -0
  91. package/examples/bg-task-cooldown-guard.sh +12 -0
  92. package/examples/binary-read-detector.sh +135 -0
  93. package/examples/binary-upload-guard.sh +12 -0
  94. package/examples/block-database-wipe.sh +35 -10
  95. package/examples/branch-name-check.sh +8 -3
  96. package/examples/branch-naming-convention.sh +0 -0
  97. package/examples/broad-find-guard.sh +12 -0
  98. package/examples/broad-prefix-session-trap-warner.sh +106 -0
  99. package/examples/bulk-file-delete-guard.sh +45 -0
  100. package/examples/bypass-mode-effective-verifier.sh +203 -0
  101. package/examples/cache-creation-drift-detector.sh +120 -0
  102. package/examples/cache-residue-detector.sh +195 -0
  103. package/examples/cache-tier-logger.sh +70 -0
  104. package/examples/cache-ttl-eviction-detector.sh +149 -0
  105. package/examples/cargo-publish-guard.sh +14 -1
  106. package/examples/case-insensitive-path-guard.sh +21 -2
  107. package/examples/case-sensitive-guard.sh +23 -2
  108. package/examples/cch-cache-guard.sh +0 -0
  109. package/examples/cch-sentinel-precommit-guard.sh +47 -0
  110. package/examples/check-abort-controller.sh +1 -1
  111. package/examples/check-accessibility.sh +0 -0
  112. package/examples/check-aria-labels.sh +0 -0
  113. package/examples/check-before-act-enforcer.sh +12 -0
  114. package/examples/check-charset-meta.sh +0 -0
  115. package/examples/check-cookie-flags.sh +0 -0
  116. package/examples/check-cors-config.sh +0 -0
  117. package/examples/check-csp-headers.sh +0 -0
  118. package/examples/check-csrf-protection.sh +0 -0
  119. package/examples/check-debounce.sh +1 -1
  120. package/examples/check-dependency-age.sh +0 -0
  121. package/examples/check-dependency-license.sh +0 -0
  122. package/examples/check-dockerfile-best-practice.sh +0 -0
  123. package/examples/check-error-boundaries.sh +0 -0
  124. package/examples/check-error-class.sh +1 -1
  125. package/examples/check-error-handling.sh +0 -0
  126. package/examples/check-error-logging.sh +1 -1
  127. package/examples/check-error-message.sh +0 -0
  128. package/examples/check-error-stack.sh +0 -0
  129. package/examples/check-favicon.sh +0 -0
  130. package/examples/check-git-hooks-compat.sh +0 -0
  131. package/examples/check-gitattributes.sh +0 -0
  132. package/examples/check-https-redirect.sh +0 -0
  133. package/examples/check-input-validation.sh +0 -0
  134. package/examples/check-lang-attribute.sh +0 -0
  135. package/examples/check-npm-scripts-exist.sh +0 -0
  136. package/examples/check-package-size.sh +0 -0
  137. package/examples/check-port-availability.sh +0 -0
  138. package/examples/check-promise-all.sh +1 -1
  139. package/examples/check-rate-limiting.sh +0 -0
  140. package/examples/check-return-types.sh +0 -0
  141. package/examples/check-semantic-versioning.sh +0 -0
  142. package/examples/check-suspense-fallback.sh +1 -1
  143. package/examples/check-test-exists.sh +0 -0
  144. package/examples/check-test-naming.sh +0 -0
  145. package/examples/check-timeout-cleanup.sh +1 -1
  146. package/examples/check-tls-version.sh +0 -0
  147. package/examples/check-unsubscribe.sh +1 -1
  148. package/examples/check-viewport-meta.sh +0 -0
  149. package/examples/check-worker-terminate.sh +1 -1
  150. package/examples/checkpoint-tamper-guard.sh +12 -0
  151. package/examples/chmod-guard.sh +12 -0
  152. package/examples/chown-guard.sh +24 -0
  153. package/examples/ci-workflow-guard.sh +6 -1
  154. package/examples/claim-verify-detector.sh +109 -0
  155. package/examples/claim-vs-caveat-checker.sh +77 -0
  156. package/examples/classifier-fallback-allow.sh +114 -40
  157. package/examples/claude-cache-gc.sh +1 -0
  158. package/examples/claude-code-version-pin-advisor.sh +183 -0
  159. package/examples/claude-md-reinjector.sh +129 -0
  160. package/examples/claude-md-size-monitor.sh +66 -0
  161. package/examples/claude-update-budget-guard.sh +123 -0
  162. package/examples/claude-update-smart.sh +113 -0
  163. package/examples/claudeignore-enforce-guard.sh +12 -0
  164. package/examples/claudemd-enforcer.sh +0 -0
  165. package/examples/claudemd-tool-prohibition.sh +128 -0
  166. package/examples/clear-command-confirm-guard.sh +32 -15
  167. package/examples/cli-config-pinning-detector.sh +162 -0
  168. package/examples/cliff-countdown-advisor.sh +96 -0
  169. package/examples/clipboard-secret-guard.sh +12 -0
  170. package/examples/closure-word-verify-gate.sh +150 -0
  171. package/examples/cloud-cli-guard.sh +39 -2
  172. package/examples/commit-all-scope-guard.sh +44 -0
  173. package/examples/commit-message-check.sh +1 -1
  174. package/examples/commit-message-quality.sh +6 -1
  175. package/examples/commitment-carry-forward-arrest.sh +361 -0
  176. package/examples/compact-alert-notification.sh +0 -0
  177. package/examples/compact-circuit-breaker.sh +72 -0
  178. package/examples/compact-dispatch-watchdog.sh +149 -0
  179. package/examples/completion-claim-without-verification-detector.sh +207 -0
  180. package/examples/composer-guard.sh +12 -0
  181. package/examples/compound-bash-permission-resolver.sh +156 -0
  182. package/examples/compound-command-allow.sh +1 -1
  183. package/examples/compound-command-deny-enforcer.sh +183 -0
  184. package/examples/compound-inject-guard.sh +12 -0
  185. package/examples/concurrent-edit-lock.sh +12 -0
  186. package/examples/conflict-marker-guard.sh +12 -0
  187. package/examples/consecutive-error-breaker.sh +0 -0
  188. package/examples/console-log-count.sh +1 -0
  189. package/examples/context-compact-advisor.sh +29 -2
  190. package/examples/context-length-budget.sh +69 -0
  191. package/examples/context-threshold-alert.sh +12 -0
  192. package/examples/context-usage-drift-alert.sh +41 -13
  193. package/examples/conversation-history-guard.sh +12 -0
  194. package/examples/core-file-protect-guard.sh +12 -0
  195. package/examples/cors-star-warn.sh +0 -0
  196. package/examples/cost-incident-self-audit.sh +162 -0
  197. package/examples/cowork-claude-md-load-checker.sh +100 -0
  198. package/examples/cowork-fuse-staleness-watcher.sh +140 -0
  199. package/examples/cowork-hook-absence-warner.sh +167 -0
  200. package/examples/cowork-model-picker-advisor.sh +115 -0
  201. package/examples/credential-exfil-guard.sh +65 -4
  202. package/examples/credential-file-cat-guard.sh +17 -1
  203. package/examples/cron-create-receipt.sh +112 -0
  204. package/examples/cron-modification-guard.sh +12 -0
  205. package/examples/cross-product-mcp-spawn-detector.sh +178 -0
  206. package/examples/cwd-project-boundary-guard.sh +0 -0
  207. package/examples/daemon-zombie-worker-surfacer.sh +118 -0
  208. package/examples/daily-cost-guard.sh +164 -0
  209. package/examples/daily-usage-tracker.sh +0 -0
  210. package/examples/dangerous-pip-flag-guard.sh +12 -0
  211. package/examples/db-connect-guard.sh +13 -1
  212. package/examples/denied-action-retry-guard.sh +12 -0
  213. package/examples/deny-bypass-detector.sh +12 -0
  214. package/examples/deny-rule-integrity-verifier.sh +181 -0
  215. package/examples/dependency-install-guard.sh +12 -0
  216. package/examples/deploy-guard.sh +14 -2
  217. package/examples/deploy-path-verify-guard.sh +12 -0
  218. package/examples/deployment-readback-gate.sh +135 -0
  219. package/examples/deployment-readback-gh-adapter.sh +247 -0
  220. package/examples/deployment-verify-guard.sh +25 -2
  221. package/examples/destructive-db-script-write-guard.sh +166 -0
  222. package/examples/destructive-migration-write-guard.sh +163 -0
  223. package/examples/diff-size-guard.sh +12 -0
  224. package/examples/disabled-feature-toggle-advisor.sh +88 -0
  225. package/examples/disk-partition-guard.sh +12 -0
  226. package/examples/dispatch-allowlist-preflight.sh +301 -0
  227. package/examples/dispatch-liveness-watchdog.sh +216 -0
  228. package/examples/dispatch-receipt.sh +174 -0
  229. package/examples/django-migrate-guard.sh +12 -0
  230. package/examples/dns-config-guard.sh +12 -0
  231. package/examples/docker-dangerous-guard.sh +12 -0
  232. package/examples/docker-volume-guard.sh +0 -0
  233. package/examples/dockerfile-latest-guard.sh +1 -0
  234. package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
  235. package/examples/dotenv-commit-guard.sh +12 -0
  236. package/examples/dotenv-read-guard.sh +12 -0
  237. package/examples/dotfile-protection-guard.sh +12 -0
  238. package/examples/dotnet-build-on-edit.sh +1 -1
  239. package/examples/drizzle-migrate-guard.sh +27 -2
  240. package/examples/echo-probe-spam-detector.sh +176 -0
  241. package/examples/edit-counter-test-gate.sh +12 -0
  242. package/examples/edit-error-counter.sh +1 -1
  243. package/examples/edit-guard.sh +12 -0
  244. package/examples/edit-old-string-validator.sh +12 -0
  245. package/examples/edit-quote-ambiguity-guard.sh +97 -0
  246. package/examples/edit-retry-loop-guard.sh +0 -0
  247. package/examples/edit-verify.sh +0 -0
  248. package/examples/env-inline-secret-guard.sh +14 -2
  249. package/examples/env-naming-convention.sh +0 -0
  250. package/examples/env-prod-guard.sh +0 -0
  251. package/examples/env-required-check.sh +0 -0
  252. package/examples/env-source-guard.sh +12 -0
  253. package/examples/env-var-check.sh +24 -1
  254. package/examples/ephemeral-container-detector.sh +147 -0
  255. package/examples/error-memory-guard.sh +12 -0
  256. package/examples/evidence-claim-gate.sh +187 -0
  257. package/examples/exploration-budget-guard.sh +89 -0
  258. package/examples/expo-eject-guard.sh +13 -0
  259. package/examples/extended-thinking-loop-guard.sh +139 -0
  260. package/examples/extended-thinking-resume-warning.sh +119 -0
  261. package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
  262. package/examples/fabricated-command-detector.sh +145 -0
  263. package/examples/false-disk-full-guard.sh +63 -0
  264. package/examples/feature-deprecation-detector.sh +109 -0
  265. package/examples/file-change-tracker.sh +1 -1
  266. package/examples/file-change-undo-tracker.sh +0 -0
  267. package/examples/file-edit-backup.sh +63 -14
  268. package/examples/file-reference-check.sh +0 -0
  269. package/examples/file-size-limit.sh +12 -0
  270. package/examples/financial-operation-guard.sh +12 -0
  271. package/examples/firewall-guard.sh +12 -0
  272. package/examples/fish-shell-wrapper.sh +125 -7
  273. package/examples/five-hundred-milestone.sh +1 -0
  274. package/examples/flask-static-route-guard.sh +89 -0
  275. package/examples/forbidden-response-phrase-detector.sh +161 -0
  276. package/examples/gem-push-guard.sh +13 -0
  277. package/examples/gh-cli-destructive-guard.sh +13 -1
  278. package/examples/git-checkout-safety-guard.sh +12 -0
  279. package/examples/git-checkout-uncommitted-guard.sh +12 -0
  280. package/examples/git-config-guard.sh +12 -0
  281. package/examples/git-crypt-worktree-guard.sh +12 -0
  282. package/examples/git-filter-repo-guard.sh +56 -0
  283. package/examples/git-history-rewrite-guard.sh +12 -0
  284. package/examples/git-hook-bypass-guard.sh +0 -0
  285. package/examples/git-maintenance-guard.sh +83 -0
  286. package/examples/git-merge-conflict-prevent.sh +0 -0
  287. package/examples/git-message-length-check.sh +0 -0
  288. package/examples/git-message-length.sh +0 -0
  289. package/examples/git-operations-require-approval.sh +68 -14
  290. package/examples/git-pack-temp-cleanup-guard.sh +102 -0
  291. package/examples/git-push-blast-radius-guard.sh +218 -0
  292. package/examples/git-remote-guard.sh +24 -3
  293. package/examples/git-rm-orphan-wipe-guard.sh +85 -0
  294. package/examples/git-stash-before-checkout.sh +12 -0
  295. package/examples/git-stash-before-danger.sh +0 -0
  296. package/examples/git-submodule-guard.sh +69 -2
  297. package/examples/git-tag-guard.sh +12 -0
  298. package/examples/github-actions-secret-guard.sh +0 -0
  299. package/examples/gitignore-check.sh +0 -0
  300. package/examples/gitops-drift-guard.sh +12 -0
  301. package/examples/go-mod-tidy-warn.sh +1 -0
  302. package/examples/go-vet-after-edit.sh +12 -0
  303. package/examples/goal-iteration-limit-warner.sh +152 -0
  304. package/examples/grep-nul-false-negative-guard.sh +30 -0
  305. package/examples/growthbook-flag-monitor.sh +257 -0
  306. package/examples/hallucination-url-check.sh +1 -1
  307. package/examples/halt-signal-detector.sh +135 -0
  308. package/examples/handoff-on-clear.sh +65 -0
  309. package/examples/hardcoded-ip-guard.sh +1 -0
  310. package/examples/headless-empty-result-guard.sh +0 -0
  311. package/examples/headless-stop-guard.sh +0 -0
  312. package/examples/helm-install-guard.sh +2 -1
  313. package/examples/home-critical-bash-guard.sh +17 -1
  314. package/examples/hook-debug-wrapper.sh +6 -2
  315. package/examples/hook-permission-fixer.sh +0 -0
  316. package/examples/hook-self-disable-detector.sh +99 -0
  317. package/examples/hook-stdout-sanitizer.sh +6 -2
  318. package/examples/hook-tamper-guard.sh +12 -0
  319. package/examples/idle-session-cost-alert.sh +0 -0
  320. package/examples/image-dimension-guard.sh +109 -0
  321. package/examples/image-file-validator.sh +0 -0
  322. package/examples/iteration-quality-degradation-detector.sh +170 -0
  323. package/examples/java-compile-on-edit.sh +1 -1
  324. package/examples/json-syntax-check.sh +0 -0
  325. package/examples/k8s-production-guard.sh +13 -1
  326. package/examples/kill-process-guard.sh +12 -0
  327. package/examples/kubernetes-guard.sh +13 -1
  328. package/examples/laravel-artisan-guard.sh +13 -0
  329. package/examples/large-file-guard.sh +1 -1
  330. package/examples/log-level-guard.sh +0 -0
  331. package/examples/log-truncation-guard.sh +12 -0
  332. package/examples/long-session-malformed-tool-call-detector.sh +183 -0
  333. package/examples/loop-detector.sh +12 -0
  334. package/examples/magic-number-warn.sh +1 -0
  335. package/examples/main-branch-warn.sh +12 -0
  336. package/examples/markdown-link-check.sh +0 -0
  337. package/examples/max-concurrent-agents.sh +12 -0
  338. package/examples/max-edit-size-guard.sh +13 -0
  339. package/examples/max-file-count-guard.sh +0 -0
  340. package/examples/max-file-delete-count.sh +0 -0
  341. package/examples/max-function-length.sh +1 -0
  342. package/examples/max-import-count.sh +0 -0
  343. package/examples/max-subagent-count.sh +0 -0
  344. package/examples/mcp-config-freeze.sh +12 -0
  345. package/examples/mcp-config-poisoning-audit.sh +150 -0
  346. package/examples/mcp-data-boundary.sh +1 -1
  347. package/examples/mcp-misdiagnosis-arrest.sh +209 -0
  348. package/examples/mcp-orphan-leak-warner.sh +49 -0
  349. package/examples/mcp-permissions-ask-warner.sh +151 -0
  350. package/examples/mcp-routine-approval-detector.sh +154 -0
  351. package/examples/mcp-server-allowlist.sh +12 -0
  352. package/examples/mcp-server-guard.sh +12 -0
  353. package/examples/mcp-startup-bloat-detector.sh +87 -0
  354. package/examples/mcp-stdio-compatibility-test.sh +153 -0
  355. package/examples/mcp-tool-audit-log.sh +0 -0
  356. package/examples/mcp-tool-guard.sh +101 -1
  357. package/examples/mcp-warmup-wait.sh +0 -0
  358. package/examples/memory-chain-audit.sh +56 -0
  359. package/examples/memory-orphan-detector.sh +188 -0
  360. package/examples/memory-write-guard.sh +99 -17
  361. package/examples/migration-verify-guard.sh +12 -0
  362. package/examples/model-swap-suggester.sh +177 -0
  363. package/examples/model-version-alert.sh +5 -1
  364. package/examples/model-version-lock.sh +63 -0
  365. package/examples/move-delete-sequence-guard.sh +33 -2
  366. package/examples/multi-file-plan-routing-gate.sh +192 -0
  367. package/examples/multi-vendor-concurrent-warner.sh +108 -0
  368. package/examples/multi-window-auth-drift-detector.sh +183 -0
  369. package/examples/multiline-command-approver.sh +161 -23
  370. package/examples/nested-background-agent-guard.sh +109 -0
  371. package/examples/nested-spawn-inflight-guard.sh +178 -0
  372. package/examples/network-exfil-guard.sh +12 -0
  373. package/examples/network-guard.sh +12 -0
  374. package/examples/network-interface-guard.sh +12 -0
  375. package/examples/nextjs-env-guard.sh +1 -1
  376. package/examples/no-absolute-import.sh +0 -0
  377. package/examples/no-alert-confirm-prompt.sh +0 -0
  378. package/examples/no-anonymous-default-export.sh +0 -0
  379. package/examples/no-any-type.sh +0 -0
  380. package/examples/no-any-typescript.sh +1 -0
  381. package/examples/no-ask-human.sh +12 -0
  382. package/examples/no-assignment-in-condition.sh +0 -0
  383. package/examples/no-base64-exfil.sh +12 -0
  384. package/examples/no-callback-hell.sh +0 -0
  385. package/examples/no-circular-dependency.sh +0 -0
  386. package/examples/no-cleartext-storage.sh +0 -0
  387. package/examples/no-commented-code.sh +0 -0
  388. package/examples/no-commit-fixup.sh +0 -0
  389. package/examples/no-console-assert.sh +0 -0
  390. package/examples/no-console-error-swallow.sh +0 -0
  391. package/examples/no-console-in-prod.sh +0 -0
  392. package/examples/no-console-log-commit.sh +12 -0
  393. package/examples/no-console-log.sh +0 -0
  394. package/examples/no-console-time.sh +0 -0
  395. package/examples/no-cors-wildcard.sh +4 -1
  396. package/examples/no-curl-upload.sh +0 -0
  397. package/examples/no-dangerouslySetInnerHTML.sh +0 -0
  398. package/examples/no-dangling-await.sh +1 -0
  399. package/examples/no-debug-commit.sh +12 -0
  400. package/examples/no-debug-in-commit.sh +0 -0
  401. package/examples/no-deep-nesting.sh +0 -0
  402. package/examples/no-deep-relative-import.sh +1 -0
  403. package/examples/no-default-credentials.sh +0 -0
  404. package/examples/no-deploy-friday.sh +13 -1
  405. package/examples/no-disabled-test.sh +0 -0
  406. package/examples/no-document-write.sh +0 -0
  407. package/examples/no-empty-function.sh +0 -0
  408. package/examples/no-eval-in-template.sh +0 -0
  409. package/examples/no-eval-template.sh +3 -1
  410. package/examples/no-eval.sh +0 -0
  411. package/examples/no-exec-user-input.sh +0 -0
  412. package/examples/no-fixme-ship.sh +12 -0
  413. package/examples/no-floating-promises.sh +0 -0
  414. package/examples/no-force-flag.sh +22 -5
  415. package/examples/no-force-install.sh +0 -0
  416. package/examples/no-git-amend.sh +12 -0
  417. package/examples/no-git-rebase-public.sh +0 -0
  418. package/examples/no-global-install.sh +12 -0
  419. package/examples/no-global-state.sh +0 -0
  420. package/examples/no-hardcoded-port.sh +1 -0
  421. package/examples/no-hardcoded-url.sh +0 -0
  422. package/examples/no-helmet-missing.sh +0 -0
  423. package/examples/no-http-url.sh +1 -0
  424. package/examples/no-http-without-https.sh +0 -0
  425. package/examples/no-inline-style.sh +0 -0
  426. package/examples/no-inline-styles.sh +1 -0
  427. package/examples/no-innerhtml.sh +0 -0
  428. package/examples/no-install-global.sh +12 -0
  429. package/examples/no-jwt-in-url.sh +0 -0
  430. package/examples/no-large-commit.sh +0 -0
  431. package/examples/no-localhost-expose.sh +0 -0
  432. package/examples/no-magic-number.sh +0 -0
  433. package/examples/no-md5-sha1.sh +0 -0
  434. package/examples/no-mixed-line-endings.sh +8 -1
  435. package/examples/no-mutation-in-reducer.sh +0 -0
  436. package/examples/no-nested-ternary.sh +0 -0
  437. package/examples/no-network-exfil.sh +0 -0
  438. package/examples/no-open-redirect.sh +0 -0
  439. package/examples/no-output-truncation.sh +12 -0
  440. package/examples/no-package-downgrade.sh +0 -0
  441. package/examples/no-package-lock-edit.sh +12 -0
  442. package/examples/no-path-join-user-input.sh +0 -0
  443. package/examples/no-port-bind.sh +0 -0
  444. package/examples/no-process-exit.sh +0 -0
  445. package/examples/no-prototype-pollution.sh +0 -0
  446. package/examples/no-push-without-ci.sh +0 -0
  447. package/examples/no-push-without-tests.sh +12 -0
  448. package/examples/no-raw-password-in-url.sh +0 -0
  449. package/examples/no-root-user-docker.sh +1 -0
  450. package/examples/no-root-write.sh +12 -0
  451. package/examples/no-secrets-in-args.sh +4 -1
  452. package/examples/no-secrets-in-logs.sh +0 -0
  453. package/examples/no-sensitive-log.sh +0 -0
  454. package/examples/no-sleep-in-hooks.sh +0 -0
  455. package/examples/no-star-import-python.sh +1 -0
  456. package/examples/no-string-concat-sql.sh +0 -0
  457. package/examples/no-sudo-guard.sh +12 -0
  458. package/examples/no-sync-fs.sh +0 -0
  459. package/examples/no-todo-in-merge.sh +0 -0
  460. package/examples/no-todo-in-production.sh +1 -0
  461. package/examples/no-todo-without-issue.sh +0 -0
  462. package/examples/no-unused-import.sh +0 -0
  463. package/examples/no-var-keyword.sh +0 -0
  464. package/examples/no-verify-blocker.sh +12 -0
  465. package/examples/no-wget-piped-bash.sh +12 -0
  466. package/examples/no-wildcard-cors.sh +0 -0
  467. package/examples/no-wildcard-delete.sh +0 -0
  468. package/examples/no-wildcard-import.sh +0 -0
  469. package/examples/no-with-statement.sh +0 -0
  470. package/examples/no-write-outside-src.sh +0 -0
  471. package/examples/no-xml-external-entity.sh +0 -0
  472. package/examples/non-english-quality-warner.sh +156 -0
  473. package/examples/notify-waiting.sh +1 -1
  474. package/examples/npm-audit-warn.sh +0 -0
  475. package/examples/npm-global-install-guard.sh +12 -0
  476. package/examples/npm-publish-guard.sh +12 -0
  477. package/examples/npm-script-injection.sh +0 -0
  478. package/examples/npm-supply-chain-guard.sh +0 -0
  479. package/examples/nuxt-config-guard.sh +1 -0
  480. package/examples/oauth-refresh-monitor.sh +210 -0
  481. package/examples/opus-degradation-tracker.sh +187 -0
  482. package/examples/opus48-routine-task-warning.sh +196 -0
  483. package/examples/opus48-thinking-wedge-advisor.sh +143 -0
  484. package/examples/output-credential-scan.sh +1 -1
  485. package/examples/output-secret-mask.sh +31 -9
  486. package/examples/output-token-spike-detector.sh +145 -0
  487. package/examples/package-json-guard.sh +12 -0
  488. package/examples/package-lock-frozen.sh +12 -0
  489. package/examples/parallel-batch-size-limiter.sh +121 -0
  490. package/examples/parallel-cascade-detector.sh +116 -0
  491. package/examples/partial-view-claim-arrest.sh +174 -0
  492. package/examples/path-deny-bash-guard.sh +12 -0
  493. package/examples/path-traversal-guard.sh +12 -0
  494. package/examples/per-prompt-token-cap.sh +124 -0
  495. package/examples/permission-audit-log.sh +1 -1
  496. package/examples/permission-denial-enforcer.sh +12 -0
  497. package/examples/permission-entry-validator.sh +0 -0
  498. package/examples/persisted-1m-model-advisor.sh +88 -0
  499. package/examples/php-lint-on-edit.sh +1 -1
  500. package/examples/pii-upload-guard.sh +12 -0
  501. package/examples/pip-publish-guard.sh +13 -0
  502. package/examples/pip-requirements-guard.sh +12 -0
  503. package/examples/pip-venv-required.sh +12 -0
  504. package/examples/plan-mode-edit-guard.sh +12 -0
  505. package/examples/plan-mode-enforcer.sh +12 -0
  506. package/examples/plan-mode-strict-guard.sh +12 -0
  507. package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
  508. package/examples/plugin-process-cleanup.sh +0 -0
  509. package/examples/polyglot-rm-guard.sh +12 -0
  510. package/examples/post-compact-safety.sh +12 -0
  511. package/examples/post-edit-disk-verify.sh +152 -0
  512. package/examples/powershell-remove-item-guard.sh +85 -0
  513. package/examples/pr-description-check.sh +0 -0
  514. package/examples/pr-duplicate-guard.sh +13 -0
  515. package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
  516. package/examples/pre-compact-knowledge-save.sh +0 -0
  517. package/examples/pre-compact-transcript-backup.sh +0 -0
  518. package/examples/pre-execution-claim-detector.sh +179 -0
  519. package/examples/prefer-builtin-tools.sh +10 -1
  520. package/examples/prefer-const.sh +0 -0
  521. package/examples/prefer-dedicated-tools.sh +12 -0
  522. package/examples/prefer-optional-chaining.sh +0 -0
  523. package/examples/prisma-migrate-guard.sh +24 -7
  524. package/examples/production-port-kill-guard.sh +12 -0
  525. package/examples/prompt-injection-guard.sh +2 -1
  526. package/examples/prompt-usage-logger.sh +0 -0
  527. package/examples/protect-claudemd.sh +12 -0
  528. package/examples/protect-dotfiles.sh +12 -0
  529. package/examples/proxy-capture-suggester.sh +159 -0
  530. package/examples/public-artefact-socratic-narrowing.sh +232 -0
  531. package/examples/public-repo-push-guard.sh +12 -0
  532. package/examples/push-requires-test-pass-record.sh +0 -0
  533. package/examples/push-requires-test-pass.sh +12 -0
  534. package/examples/quota-anomaly-detector.sh +173 -0
  535. package/examples/quota-reset-audit.sh +58 -0
  536. package/examples/quoted-flag-approver.sh +99 -10
  537. package/examples/rails-migration-guard.sh +12 -0
  538. package/examples/rate-limit-guard.sh +0 -0
  539. package/examples/read-all-files-enforcer.sh +0 -0
  540. package/examples/read-budget-guard.sh +12 -0
  541. package/examples/read-loop-detector.sh +59 -0
  542. package/examples/read-once-guard.sh +96 -0
  543. package/examples/read-only-mode.sh +12 -0
  544. package/examples/readme-exists-check.sh +0 -0
  545. package/examples/record-read-coverage.sh +73 -0
  546. package/examples/redirect-fragment-warner.sh +149 -0
  547. package/examples/redis-flushall-guard.sh +13 -0
  548. package/examples/redundant-read-blocker.sh +132 -0
  549. package/examples/refusal-arrest-gate.sh +248 -0
  550. package/examples/registry-publish-guard.sh +13 -1
  551. package/examples/remote-control-billing-classifier.sh +135 -0
  552. package/examples/replace-all-guard.sh +12 -0
  553. package/examples/repo-visibility-guard.sh +12 -0
  554. package/examples/reroute-after-block-guard.sh +150 -0
  555. package/examples/response-budget-guard.sh +0 -0
  556. package/examples/resume-drift-watcher.sh +57 -0
  557. package/examples/rg-replace-flag-detector.sh +125 -0
  558. package/examples/rhetorical-verification-prompt-detector.sh +102 -0
  559. package/examples/ripgrep-permission-fix.sh +0 -0
  560. package/examples/rm-safety-net.sh +151 -8
  561. package/examples/role-tool-guard.sh +12 -0
  562. package/examples/route-handler-emptiness-gate.sh +324 -0
  563. package/examples/ruby-lint-on-edit.sh +1 -1
  564. package/examples/runtime-binary-change-detector.sh +102 -0
  565. package/examples/same-command-repeat-detector.sh +196 -0
  566. package/examples/same-correction-arrest.sh +169 -0
  567. package/examples/sandbox-denywrite-enforcer.sh +78 -0
  568. package/examples/sandbox-relative-path-audit.sh +83 -25
  569. package/examples/sandbox-write-verify.sh +12 -0
  570. package/examples/schema-migration-guard.sh +0 -0
  571. package/examples/scope-expansion-receipt.sh +178 -0
  572. package/examples/scope-guard.sh +88 -9
  573. package/examples/secret-file-read-guard.sh +12 -0
  574. package/examples/secret-file-write-guard.sh +150 -0
  575. package/examples/self-modify-bypass-guard.sh +0 -0
  576. package/examples/sensitive-file-read-guard.sh +23 -3
  577. package/examples/sensitive-log-guard.sh +1 -0
  578. package/examples/server-side-prompt-injection-detector.sh +69 -0
  579. package/examples/session-agent-cost-limiter.sh +12 -0
  580. package/examples/session-backup-on-start.sh +1 -1
  581. package/examples/session-cost-alert.sh +12 -0
  582. package/examples/session-drift-guard.sh +12 -0
  583. package/examples/session-duration-guard.sh +25 -2
  584. package/examples/session-end-logger.sh +0 -0
  585. package/examples/session-health-monitor.sh +0 -0
  586. package/examples/session-index-repair.sh +1 -1
  587. package/examples/session-memory-watchdog.sh +1 -0
  588. package/examples/session-permission-reset-guard.sh +12 -0
  589. package/examples/session-persistence-verifier.sh +93 -0
  590. package/examples/session-plugin-pin-watch.sh +68 -0
  591. package/examples/session-rate-monitor.sh +176 -0
  592. package/examples/session-resume-env-fix.sh +0 -0
  593. package/examples/session-start-quota-status.sh +193 -0
  594. package/examples/session-start-safety-check.sh +55 -3
  595. package/examples/session-state-saver.sh +0 -0
  596. package/examples/session-summary-stop.sh +1 -1
  597. package/examples/session-summary.sh +0 -0
  598. package/examples/session-token-counter.sh +1 -1
  599. package/examples/settings-hooks-key-restorer.sh +99 -0
  600. package/examples/settings-json-health-check.sh +57 -0
  601. package/examples/settings-json-model-guard.sh +0 -0
  602. package/examples/settings-regression-tester.sh +188 -0
  603. package/examples/shell-config-truncation-guard.sh +12 -0
  604. package/examples/shell-wrapper-guard.sh +12 -0
  605. package/examples/skill-cumulative-size-detector.sh +104 -0
  606. package/examples/skill-description-drop-detector.sh +148 -0
  607. package/examples/skill-gate.sh +0 -0
  608. package/examples/skill-truncation-detector.sh +154 -0
  609. package/examples/skills-context-recorder.sh +167 -0
  610. package/examples/skills-load-verifier.sh +96 -0
  611. package/examples/skills-settings-validator.sh +139 -0
  612. package/examples/sonnet-45-deprecation-helper.sh +85 -0
  613. package/examples/spec-file-scope-guard.sh +12 -0
  614. package/examples/spring-profile-guard.sh +1 -0
  615. package/examples/spurious-malformed-notice-detector.sh +247 -0
  616. package/examples/sql-bulk-delete-warn.sh +88 -0
  617. package/examples/sql-injection-detect.sh +0 -0
  618. package/examples/ssh-key-protect.sh +12 -0
  619. package/examples/staged-secret-scan.sh +22 -1
  620. package/examples/stale-temp-settings-detector.sh +86 -0
  621. package/examples/standing-rule-session-surfacer.sh +137 -0
  622. package/examples/stop-hook-sigterm-wrapper.sh +182 -0
  623. package/examples/stop-transcript-write-health.sh +64 -0
  624. package/examples/strict-allowlist.sh +57 -15
  625. package/examples/strip-coauthored-by.sh +50 -10
  626. package/examples/subagent-blast-radius-guard.sh +184 -0
  627. package/examples/subagent-boundary-precheck.sh +126 -0
  628. package/examples/subagent-budget-guard.sh +12 -0
  629. package/examples/subagent-claudemd-inject.sh +0 -0
  630. package/examples/subagent-closure-verify-gate.sh +164 -0
  631. package/examples/subagent-destructive-git-guard.sh +120 -0
  632. package/examples/subagent-error-detector.sh +0 -0
  633. package/examples/subagent-forged-system-reminder-guard.sh +156 -0
  634. package/examples/subagent-identity-leak-guard.sh +102 -0
  635. package/examples/subagent-identity-reassertion.sh +51 -0
  636. package/examples/subagent-inheritance-tester.sh +179 -0
  637. package/examples/subagent-permission-mode-guard.sh +110 -0
  638. package/examples/subagent-scope-guard.sh +12 -0
  639. package/examples/subagent-spawn-verification-enforcer.sh +102 -0
  640. package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
  641. package/examples/subagent-tool-call-limiter.sh +87 -15
  642. package/examples/subcommand-chain-guard.sh +12 -0
  643. package/examples/subscription-api-billing-warner.sh +160 -0
  644. package/examples/subscription-bypass-detector.sh +152 -0
  645. package/examples/svelte-lint-on-edit.sh +1 -0
  646. package/examples/swift-build-on-edit.sh +1 -1
  647. package/examples/symlink-guard.sh +27 -2
  648. package/examples/symlink-protect.sh +1 -0
  649. package/examples/system-dir-protection-guard.sh +73 -8
  650. package/examples/system-message-workaround.sh +38 -13
  651. package/examples/system-package-guard.sh +12 -0
  652. package/examples/systemd-service-guard.sh +12 -0
  653. package/examples/task-integrity-guard.sh +12 -0
  654. package/examples/temp-file-cleanup.sh +1 -1
  655. package/examples/temporal-suggestion-detector.sh +135 -0
  656. package/examples/terraform-guard.sh +27 -6
  657. package/examples/test-after-edit.sh +1 -1
  658. package/examples/test-before-push.sh +12 -0
  659. package/examples/test-coverage-reminder.sh +24 -1
  660. package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
  661. package/examples/thinking-stall-detector.sh +61 -0
  662. package/examples/timezone-guard.sh +0 -0
  663. package/examples/tmp-output-size-guard.sh +0 -0
  664. package/examples/todo-check.sh +1 -1
  665. package/examples/token-budget-guard.sh +12 -0
  666. package/examples/token-budget-per-task.sh +12 -0
  667. package/examples/token-usage-tracker.sh +7 -1
  668. package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
  669. package/examples/tokenizer-ratio-alert.sh +104 -0
  670. package/examples/tool-call-rate-limiter.sh +0 -0
  671. package/examples/tool-result-correlation-checker.sh +167 -0
  672. package/examples/tool-result-size-guard.sh +132 -0
  673. package/examples/tool-retry-budget-guard.sh +12 -0
  674. package/examples/transcript-contamination-detector.sh +138 -0
  675. package/examples/trustfall-mcp-injection-guard.sh +103 -0
  676. package/examples/ultrareview-large-diff-advisor.sh +184 -0
  677. package/examples/unbounded-output-guard.sh +94 -0
  678. package/examples/uncommitted-changes-stop.sh +1 -0
  679. package/examples/uncommitted-discard-guard.sh +23 -5
  680. package/examples/uncommitted-work-guard.sh +12 -0
  681. package/examples/usage-warn.sh +0 -0
  682. package/examples/user-account-guard.sh +12 -0
  683. package/examples/userprompt-submit-receipt.sh +123 -0
  684. package/examples/variable-expansion-guard.sh +12 -0
  685. package/examples/verify-after-publish-reminder.sh +93 -0
  686. package/examples/verify-before-commit.sh +12 -0
  687. package/examples/version-bump-detector.sh +156 -0
  688. package/examples/version-regression-warner.sh +144 -0
  689. package/examples/vue-lint-on-edit.sh +1 -0
  690. package/examples/warn-cron-cost-trap.sh +173 -0
  691. package/examples/webfetch-runaway-guard.sh +89 -0
  692. package/examples/wellness-break-reminder.sh +118 -0
  693. package/examples/windows-destructive-command-guard.sh +177 -0
  694. package/examples/windows-path-guard.sh +12 -0
  695. package/examples/windows-python-stub-detector.sh +63 -0
  696. package/examples/work-hours-guard.sh +12 -0
  697. package/examples/working-directory-fence.sh +12 -0
  698. package/examples/workspace-lease-guard.sh +205 -0
  699. package/examples/worktree-create-log.sh +1 -0
  700. package/examples/worktree-delete-guard.sh +12 -0
  701. package/examples/worktree-edit-boundary-guard.sh +127 -0
  702. package/examples/worktree-escape-write-guard.sh +114 -0
  703. package/examples/worktree-hook-linker.sh +0 -0
  704. package/examples/worktree-hooks-path-fix.sh +111 -0
  705. package/examples/worktree-parent-write-guard.sh +43 -0
  706. package/examples/worktree-project-unify.sh +2 -1
  707. package/examples/worktree-remove-uncommitted-guard.sh +13 -0
  708. package/examples/worktree-unmerged-guard.sh +7 -1
  709. package/examples/write-byte-integrity-verifier.sh +190 -0
  710. package/examples/write-empty-content-guard.sh +67 -0
  711. package/examples/write-nul-corruption-detector.sh +61 -0
  712. package/examples/write-overwrite-confirm.sh +160 -14
  713. package/examples/write-secret-guard.sh +27 -5
  714. package/examples/write-shrink-guard.sh +12 -0
  715. package/examples/write-test-ratio.sh +0 -0
  716. package/examples/wsl-host-disk-space-guard.sh +97 -0
  717. package/examples/xml-format-leak-detector.sh +266 -0
  718. package/examples/yaml-syntax-check.sh +12 -0
  719. package/hooks/hooks.json +6 -6
  720. package/index.mjs +1699 -183
  721. package/mission.md +2 -0
  722. package/package.json +4 -4
  723. package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
  724. package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
  725. package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
  726. package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
  727. package/scripts/agents-md-sync-setup.sh +156 -0
  728. package/scripts/autonomy-blocked-summary.sh +148 -0
  729. package/scripts/build-search-index.py +43 -0
  730. package/scripts/build-sitemap.py +119 -0
  731. package/scripts/cc-doctor.sh +192 -0
  732. package/scripts/check-hook-event-names.py +127 -0
  733. package/scripts/check-misfire-instrument.sh +64 -0
  734. package/scripts/claim-verify-audit.sh +467 -0
  735. package/scripts/cowork-claudemd-helper.sh +136 -0
  736. package/scripts/june-15-deprecated-model-scan.sh +111 -0
  737. package/scripts/measure-heredoc-shapes.sh +67 -0
  738. package/scripts/measure-literal-match-misfire.sh +110 -0
  739. package/scripts/probe-scope-guard-branches.sh +48 -0
  740. package/scripts/probe-skip-line-both-ways.sh +65 -0
  741. package/scripts/receipts-aggregate.py +199 -0
  742. package/scripts/session-forensic-audit.py +360 -0
  743. package/scripts.json +9 -9
  744. package/scripts.json.bak-2026-07-27-find +13 -0
  745. package/skills/safety-setup/SKILL.md +5 -5
  746. package/tests/approve-side-remaining-two.test.sh +129 -0
  747. package/tests/approver-list-granularity.test.sh +145 -0
  748. package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
  749. package/tests/audit-ci-gate.test.sh +87 -0
  750. package/tests/audit-cross-layer-claudemd.test.sh +170 -0
  751. package/tests/audit-fail-open-parse.test.sh +100 -0
  752. package/tests/auto-approve-compound-tail.test.sh +194 -0
  753. package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
  754. package/tests/auto-mode-quoted-targets.test.sh +127 -0
  755. package/tests/auto-mode-unquoted-targets.test.sh +112 -0
  756. package/tests/bash-secret-output-detector-detects.test.sh +102 -0
  757. package/tests/blindspots-cross-layer.test.sh +177 -0
  758. package/tests/block-database-wipe.test.sh +64 -0
  759. package/tests/bundled-short-flags-bypass.test.sh +85 -0
  760. package/tests/cd-git-allow-compound-tail.test.sh +67 -0
  761. package/tests/chown-guard-filesystem-root.test.sh +64 -0
  762. package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
  763. package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
  764. package/tests/core-scripts-parser-fallback.test.sh +140 -0
  765. package/tests/destructive-guard-bare-glob.test.sh +74 -0
  766. package/tests/destructive-guard-every-operand.test.sh +100 -0
  767. package/tests/destructive-guard-find-deletion.test.sh +114 -0
  768. package/tests/destructive-guard-flag-order.test.sh +106 -0
  769. package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
  770. package/tests/destructive-guard-quoted-target.test.sh +89 -0
  771. package/tests/destructive-guard-separators.test.sh +105 -0
  772. package/tests/destructive-guard-variable-target.test.sh +98 -0
  773. package/tests/destructive-guard-wrapped-command.test.sh +91 -0
  774. package/tests/doctor-hook-disabling-env.test.sh +92 -0
  775. package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
  776. package/tests/example-guards-wrapped-command.test.sh +169 -0
  777. package/tests/file-edit-backup.test.sh +93 -0
  778. package/tests/git-filter-repo-guard.test.sh +60 -0
  779. package/tests/git-global-options-bypass.test.sh +141 -0
  780. package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
  781. package/tests/git-maintenance-guard.test.sh +83 -0
  782. package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
  783. package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
  784. package/tests/git-submodule-guard.test.sh +50 -0
  785. package/tests/grep-pcre-portability.test.sh +155 -0
  786. package/tests/hook-registration-matches-input.test.sh +73 -0
  787. package/tests/hook-trigger-matches-envelope.test.sh +178 -0
  788. package/tests/install-does-not-claim-protection.test.sh +110 -0
  789. package/tests/install-example-standalone-tools.test.sh +139 -0
  790. package/tests/line-continuation-bypass.test.sh +114 -0
  791. package/tests/mcp-config-poisoning-audit.test.sh +106 -0
  792. package/tests/nested-background-agent-guard.test.sh +58 -0
  793. package/tests/no-unqualified-safety-claims.test.sh +114 -0
  794. package/tests/option-eating-grep-patterns.test.sh +130 -0
  795. package/tests/outdated-core-guards.test.sh +134 -0
  796. package/tests/outdated-report.test.sh +155 -0
  797. package/tests/output-secret-mask-warns.test.sh +73 -0
  798. package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
  799. package/tests/plugins-word-order.test.sh +126 -0
  800. package/tests/powershell-remove-item-guard.test.sh +85 -0
  801. package/tests/project-dir-naming.test.sh +103 -0
  802. package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
  803. package/tests/reroute-after-block-guard.test.sh +104 -0
  804. package/tests/secret-guard-documented-promises.test.sh +97 -0
  805. package/tests/session-plugin-pin-watch.test.sh +45 -0
  806. package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
  807. package/tests/shield-no-silent-adoption.test.py +110 -0
  808. package/tests/shield-no-silent-adoption.test.sh +46 -0
  809. package/tests/stop-transcript-write-health.test.sh +46 -0
  810. package/tests/system-dir-guard-root-erased.test.sh +66 -0
  811. package/tests/test-account-billing-log.sh +100 -0
  812. package/tests/test-account-routing-preflight.sh +77 -0
  813. package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
  814. package/tests/test-agent-view-quota-warn.sh +184 -0
  815. package/tests/test-agents-md-edit-drift-warner.sh +176 -0
  816. package/tests/test-agents-md-loader.sh +204 -0
  817. package/tests/test-agents-md-sync-checker.sh +125 -0
  818. package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
  819. package/tests/test-allowlist.sh +60 -0
  820. package/tests/test-always-allow-pattern-suggester.sh +147 -0
  821. package/tests/test-anthropic-base-url-guard.sh +88 -0
  822. package/tests/test-articulated-scope-capture.sh +139 -0
  823. package/tests/test-attachment-traversal-guard.sh +168 -0
  824. package/tests/test-aup-block-pattern-logger.sh +315 -0
  825. package/tests/test-aup-false-positive-helper.sh +188 -0
  826. package/tests/test-aup-large-tool-output-warner.sh +370 -0
  827. package/tests/test-aup-retry-loop-guard.sh +341 -0
  828. package/tests/test-auth-expiry-reminder.sh +303 -0
  829. package/tests/test-auth-macos-sleep-detector.sh +254 -0
  830. package/tests/test-auth-path-detector.sh +232 -0
  831. package/tests/test-auth-status-checker.sh +233 -0
  832. package/tests/test-authorized-reconfirmation-detector.sh +280 -0
  833. package/tests/test-background-cost-launch-guard.sh +62 -0
  834. package/tests/test-bash-allowlist-secondary-check.sh +143 -0
  835. package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
  836. package/tests/test-bash-project-fence.sh +127 -0
  837. package/tests/test-bg-permission-prompt-warner.sh +221 -0
  838. package/tests/test-binary-read-detector.sh +173 -0
  839. package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
  840. package/tests/test-bulk-delete-target-resolution.sh +49 -0
  841. package/tests/test-bypass-mode-effective-verifier.sh +179 -0
  842. package/tests/test-cache-creation-drift-detector.sh +244 -0
  843. package/tests/test-cache-residue-detector.sh +429 -0
  844. package/tests/test-cache-tier-logger.sh +59 -0
  845. package/tests/test-cache-ttl-eviction-detector.sh +282 -0
  846. package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
  847. package/tests/test-claim-verify-detector.sh +222 -0
  848. package/tests/test-claim-vs-caveat-checker.sh +134 -0
  849. package/tests/test-claude-code-version-pin-advisor.sh +353 -0
  850. package/tests/test-claude-md-reinjector.sh +173 -0
  851. package/tests/test-claude-md-size-monitor.sh +107 -0
  852. package/tests/test-claude-update-budget-guard.sh +132 -0
  853. package/tests/test-claude-update-smart.sh +91 -0
  854. package/tests/test-claudemd-tool-prohibition.sh +239 -0
  855. package/tests/test-cli-config-pinning-detector.sh +233 -0
  856. package/tests/test-cliff-countdown-advisor.sh +138 -0
  857. package/tests/test-closure-word-verify-gate.sh +158 -0
  858. package/tests/test-commit-all-scope-guard.sh +73 -0
  859. package/tests/test-commitment-carry-forward-arrest.sh +250 -0
  860. package/tests/test-compact-circuit-breaker.sh +134 -0
  861. package/tests/test-compact-dispatch-watchdog.sh +147 -0
  862. package/tests/test-completion-claim-without-verification-detector.sh +326 -0
  863. package/tests/test-compound-bash-permission-resolver.sh +264 -0
  864. package/tests/test-compound-command-deny-enforcer.sh +67 -0
  865. package/tests/test-context-length-budget.sh +68 -0
  866. package/tests/test-context-usage-drift-alert.sh +52 -22
  867. package/tests/test-cost-incident-self-audit.sh +94 -0
  868. package/tests/test-cowork-claude-md-load-checker.sh +257 -0
  869. package/tests/test-cowork-claudemd-helper.sh +141 -0
  870. package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
  871. package/tests/test-cowork-hook-absence-warner.sh +230 -0
  872. package/tests/test-cowork-model-picker-advisor.sh +317 -0
  873. package/tests/test-credential-exfil-guard.sh +62 -0
  874. package/tests/test-cron-create-receipt.sh +165 -0
  875. package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
  876. package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
  877. package/tests/test-daily-cost-guard.sh +131 -0
  878. package/tests/test-deny-rule-integrity-verifier.sh +288 -0
  879. package/tests/test-deployment-readback-gate.sh +92 -0
  880. package/tests/test-deployment-readback-gh-adapter.sh +163 -0
  881. package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
  882. package/tests/test-dispatch-allowlist-preflight.sh +385 -0
  883. package/tests/test-dispatch-liveness-watchdog.sh +319 -0
  884. package/tests/test-dispatch-receipt.sh +314 -0
  885. package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
  886. package/tests/test-echo-probe-spam-detector.sh +143 -0
  887. package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
  888. package/tests/test-ephemeral-container-detector.sh +251 -0
  889. package/tests/test-evidence-claim-gate.sh +291 -0
  890. package/tests/test-exploration-budget-guard.sh +164 -0
  891. package/tests/test-extended-thinking-loop-guard.sh +289 -0
  892. package/tests/test-extended-thinking-resume-warning.sh +240 -0
  893. package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
  894. package/tests/test-fabricated-command-detector.sh +296 -0
  895. package/tests/test-false-disk-full-guard.sh +36 -0
  896. package/tests/test-feature-deprecation-detector.sh +117 -0
  897. package/tests/test-forbidden-response-phrase-detector.sh +246 -0
  898. package/tests/test-git-operations-require-approval.sh +53 -0
  899. package/tests/test-git-push-blast-radius-guard.sh +115 -0
  900. package/tests/test-goal-iteration-limit-warner.sh +128 -0
  901. package/tests/test-growthbook-flag-monitor.sh +428 -0
  902. package/tests/test-halt-signal-detector.sh +120 -0
  903. package/tests/test-hook-self-disable-detector.sh +232 -0
  904. package/tests/test-iteration-quality-degradation-detector.sh +244 -0
  905. package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
  906. package/tests/test-marketplace-plugins.sh +193 -0
  907. package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
  908. package/tests/test-mcp-orphan-leak-warner.sh +71 -0
  909. package/tests/test-mcp-permissions-ask-warner.sh +207 -0
  910. package/tests/test-mcp-routine-approval-detector.sh +229 -0
  911. package/tests/test-mcp-startup-bloat-detector.sh +141 -0
  912. package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
  913. package/tests/test-memory-chain-audit.sh +59 -0
  914. package/tests/test-memory-orphan-detector.sh +227 -0
  915. package/tests/test-model-swap-suggester.sh +368 -0
  916. package/tests/test-model-version-lock.sh +83 -0
  917. package/tests/test-multi-file-plan-routing-gate.sh +277 -0
  918. package/tests/test-multi-window-auth-drift-detector.sh +262 -0
  919. package/tests/test-nested-spawn-inflight-guard.sh +281 -0
  920. package/tests/test-no-force-flag.sh +49 -0
  921. package/tests/test-non-english-quality-warner.sh +229 -0
  922. package/tests/test-oauth-refresh-monitor.sh +311 -0
  923. package/tests/test-opus-degradation-tracker.sh +274 -0
  924. package/tests/test-opus48-routine-task-warning.sh +201 -0
  925. package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
  926. package/tests/test-output-token-spike-detector.sh +315 -0
  927. package/tests/test-parallel-batch-size-limiter.sh +228 -0
  928. package/tests/test-parallel-cascade-detector.sh +191 -0
  929. package/tests/test-partial-view-claim-arrest.sh +272 -0
  930. package/tests/test-per-prompt-token-cap.sh +136 -0
  931. package/tests/test-persisted-1m-model-advisor.sh +71 -0
  932. package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
  933. package/tests/test-post-edit-disk-verify.sh +294 -0
  934. package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
  935. package/tests/test-pre-execution-claim-detector.sh +366 -0
  936. package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
  937. package/tests/test-proxy-capture-suggester.sh +214 -0
  938. package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
  939. package/tests/test-quota-anomaly-detector.sh +321 -0
  940. package/tests/test-quota-reset-audit.sh +81 -0
  941. package/tests/test-read-loop-detector.sh +137 -0
  942. package/tests/test-read-once-guard.sh +85 -0
  943. package/tests/test-receipts-aggregate.sh +143 -0
  944. package/tests/test-redirect-fragment-warner.sh +130 -0
  945. package/tests/test-redundant-read-blocker.sh +155 -0
  946. package/tests/test-refusal-arrest-gate.sh +303 -0
  947. package/tests/test-remote-control-billing-classifier.sh +125 -0
  948. package/tests/test-resume-drift-watcher.sh +65 -0
  949. package/tests/test-rg-replace-flag-detector.sh +175 -0
  950. package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
  951. package/tests/test-rm-safety-net.sh +115 -0
  952. package/tests/test-route-handler-emptiness-gate.sh +300 -0
  953. package/tests/test-runtime-binary-change-detector.sh +196 -0
  954. package/tests/test-same-command-repeat-detector.sh +165 -0
  955. package/tests/test-same-correction-arrest.sh +165 -0
  956. package/tests/test-scope-expansion-receipt.sh +207 -0
  957. package/tests/test-server-side-prompt-injection-detector.sh +181 -0
  958. package/tests/test-session-persistence-verifier.sh +128 -0
  959. package/tests/test-session-rate-monitor.sh +284 -0
  960. package/tests/test-session-start-quota-status.sh +210 -0
  961. package/tests/test-session-start-safety-check.sh +138 -0
  962. package/tests/test-settings-hooks-key-restorer.sh +257 -0
  963. package/tests/test-settings-json-health-check.sh +70 -0
  964. package/tests/test-settings-regression-tester.sh +197 -0
  965. package/tests/test-skill-cumulative-size-detector.sh +198 -0
  966. package/tests/test-skill-description-drop-detector.sh +236 -0
  967. package/tests/test-skill-truncation-detector.sh +263 -0
  968. package/tests/test-skills-context-recorder.sh +329 -0
  969. package/tests/test-skills-load-verifier.sh +184 -0
  970. package/tests/test-skills-settings-validator.sh +242 -0
  971. package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
  972. package/tests/test-spurious-malformed-notice-detector.sh +290 -0
  973. package/tests/test-sql-bulk-delete-warn.sh +123 -0
  974. package/tests/test-ssh-key-protect.sh +81 -0
  975. package/tests/test-stale-temp-settings-detector.sh +161 -0
  976. package/tests/test-standing-rule-session-surfacer.sh +215 -0
  977. package/tests/test-starter-hooks-manifest.sh +96 -0
  978. package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
  979. package/tests/test-strict-allowlist.sh +72 -0
  980. package/tests/test-subagent-boundary-precheck.sh +137 -0
  981. package/tests/test-subagent-closure-verify-gate.sh +193 -0
  982. package/tests/test-subagent-destructive-git-guard.sh +86 -0
  983. package/tests/test-subagent-identity-leak-guard.sh +62 -0
  984. package/tests/test-subagent-identity-reassertion.sh +61 -0
  985. package/tests/test-subagent-inheritance-tester.sh +319 -0
  986. package/tests/test-subagent-permission-mode-guard.sh +61 -0
  987. package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
  988. package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
  989. package/tests/test-subagent-tool-call-limiter.sh +97 -0
  990. package/tests/test-subscription-api-billing-warner.sh +138 -0
  991. package/tests/test-subscription-bypass-detector.sh +255 -0
  992. package/tests/test-temporal-suggestion-detector.sh +183 -0
  993. package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
  994. package/tests/test-thinking-stall-detector.sh +151 -0
  995. package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
  996. package/tests/test-tokenizer-ratio-alert.sh +93 -0
  997. package/tests/test-tool-result-correlation-checker.sh +264 -0
  998. package/tests/test-tool-result-size-guard.sh +121 -0
  999. package/tests/test-transcript-contamination-detector.sh +264 -0
  1000. package/tests/test-trigger-header-parsing.sh +151 -0
  1001. package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
  1002. package/tests/test-userprompt-submit-receipt.sh +181 -0
  1003. package/tests/test-verify-after-publish-reminder.sh +184 -0
  1004. package/tests/test-version-bump-detector.sh +212 -0
  1005. package/tests/test-version-regression-warner.sh +165 -0
  1006. package/tests/test-warn-cron-cost-trap.sh +82 -0
  1007. package/tests/test-webfetch-runaway-guard.sh +77 -0
  1008. package/tests/test-wellness-break-reminder.sh +138 -0
  1009. package/tests/test-windows-destructive-command-guard.sh +169 -0
  1010. package/tests/test-windows-python-stub-detector.sh +146 -0
  1011. package/tests/test-worktree-edit-boundary-guard.sh +219 -0
  1012. package/tests/test-write-byte-integrity-verifier.sh +192 -0
  1013. package/tests/test-xml-format-leak-detector.sh +299 -0
  1014. package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
  1015. package/tests/workspace-lease-guard.test.sh +144 -0
  1016. package/tests/worktree-escape-write-guard.test.sh +68 -0
  1017. package/tests/worktree-hooks-path-fix.test.sh +181 -0
  1018. package/tests/worktree-parent-write-guard.test.sh +51 -0
  1019. package/tests/write-empty-content-guard.test.sh +39 -0
  1020. package/tests/write-nul-corruption-detector.test.sh +29 -0
  1021. package/tests/write-overwrite-unread-content.test.sh +178 -0
  1022. package/tests/wsl-host-disk-space-guard.test.sh +55 -0
@@ -8,27 +8,64 @@
8
8
  # user approval. This hook enforces the restriction at process level.
9
9
  #
10
10
  # Blocks:
11
- # git commit, git push (including --force), git checkout -b,
12
- # git switch -c, git branch <name>
11
+ # git commit, git push (including --force and `git send-pack`),
12
+ # git checkout -b, git switch -c, git branch <name> - including when
13
+ # they arrive with git's own global options in front, such as
14
+ # `git -C <dir> push` or `git --git-dir=<path> commit` (#1117).
13
15
  #
14
16
  # Does NOT block:
15
17
  # git status, git log, git diff, git show, git branch (list),
16
18
  # git fetch, git stash, git add
17
19
  #
18
- # Handles compound commands (&&, ;, ||) by checking each segment.
20
+ # Handles compound commands (&&, ;, ||, |) by checking each segment.
19
21
  #
20
22
  # See: https://github.com/anthropics/claude-code/issues/40695
21
23
  #
22
24
  # TRIGGER: PreToolUse MATCHER: "Bash"
23
25
  # ================================================================
24
26
 
27
+ # Without jq, the parse below silently yields empty and this hook stops
28
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
29
+ # here: blocking would halt every tool call, and exiting 0 would change
30
+ # the behaviour of guards that do not depend on the parsed value.
31
+ if ! command -v jq >/dev/null 2>&1; then
32
+ _nojq_warned="/tmp/cc-nojq-warned-git-operations-require-approval-$PPID"
33
+ [ -f "$_nojq_warned" ] || {
34
+ echo "WARNING [git-operations-require-approval]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
35
+ : > "$_nojq_warned"
36
+ }
37
+ fi
38
+
25
39
  INPUT=$(cat)
26
40
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
27
41
 
28
42
  [ -z "$COMMAND" ] && exit 0
29
43
 
30
- # Skip if the command is inside echo/printf (not actual execution)
31
- echo "$COMMAND" | grep -qE '^\s*(echo|printf)\s' && exit 0
44
+ # git accepts global options between `git` and the subcommand, so matching the
45
+ # two as adjacent words misses every one of these real shapes (reported in #1117
46
+ # with four working examples):
47
+ # git -C /tmp/repo push --force origin main
48
+ # git --git-dir=/tmp/r/repo.d push origin main
49
+ # git -c user.name=x commit -m x
50
+ # git send-pack origin main
51
+ # GIT_OPT is the set of options git itself accepts before a subcommand.
52
+ GIT_OPT='(-[cC][[:space:]]+[^[:space:]]+|--(git-dir|work-tree|namespace|exec-path|config-env|attr-source|super-prefix)(=[^[:space:]]+|[[:space:]]+[^[:space:]]+)|-[pP]|--(paginate|no-pager|bare|no-replace-objects|literal-pathspecs|glob-pathspecs|noglob-pathspecs|icase-pathspecs|no-optional-locks|no-lazy-fetch|no-advice))'
53
+
54
+ # `git` at a command position, not the `git` inside a path. The old pattern
55
+ # matched `git --git-dir=/tmp/r/.git push` only because the *path* ended in
56
+ # `.git`, and let the same command through when the git-dir was named anything
57
+ # else (#1117). Quotes are allowed on purpose: `bash -c "git push ..."` runs.
58
+ GIT_HEAD='(^|[[:space:];&|(]|/|"|'"'"')git'
59
+
60
+ # Build "git [global options] <subcommand>" for one subcommand pattern.
61
+ git_re() {
62
+ printf '%s([[:space:]]+%s)*[[:space:]]+%s' "$GIT_HEAD" "$GIT_OPT" "$1"
63
+ }
64
+
65
+ # Read-only front halves that mention a command without running it.
66
+ # This list is a guess about how people write, not a rule - `sed -i` and any
67
+ # wrapper not named here will still be inspected.
68
+ READ_ONLY_RE='^[[:space:]]*(echo|printf|grep|rg|cat|less|head|tail)[[:space:]]'
32
69
 
33
70
  # Check each segment of compound commands
34
71
  check_segment() {
@@ -37,8 +74,12 @@ check_segment() {
37
74
  seg=$(echo "$seg" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
38
75
  [ -z "$seg" ] && return 0
39
76
 
77
+ # Exempt only THIS segment. Applying it to the whole command let
78
+ # `echo hi && git push origin main` through completely.
79
+ echo "$seg" | grep -qE "$READ_ONLY_RE" && return 0
80
+
40
81
  # git commit
41
- if echo "$seg" | grep -qE '\bgit\s+commit\b'; then
82
+ if echo "$seg" | grep -qE "$(git_re 'commit\b')|${GIT_HEAD}-commit\b"; then
42
83
  echo "BLOCKED: git commit requires explicit user approval." >&2
43
84
  echo "Command: $seg" >&2
44
85
  echo "" >&2
@@ -47,7 +88,7 @@ check_segment() {
47
88
  fi
48
89
 
49
90
  # git push (including force variants)
50
- if echo "$seg" | grep -qE '\bgit\s+push\b'; then
91
+ if echo "$seg" | grep -qE "$(git_re '(push|send-pack)\b')|${GIT_HEAD}-(push|send-pack)\b"; then
51
92
  echo "BLOCKED: git push requires explicit user approval." >&2
52
93
  echo "Command: $seg" >&2
53
94
  echo "" >&2
@@ -56,14 +97,14 @@ check_segment() {
56
97
  fi
57
98
 
58
99
  # git checkout -b (branch creation)
59
- if echo "$seg" | grep -qE '\bgit\s+checkout\s+(-b|--branch)\b'; then
100
+ if echo "$seg" | grep -qE "$(git_re 'checkout[[:space:]]+(-b|--branch)\b')"; then
60
101
  echo "BLOCKED: git branch creation requires explicit user approval." >&2
61
102
  echo "Command: $seg" >&2
62
103
  return 1
63
104
  fi
64
105
 
65
106
  # git switch -c / --create (branch creation)
66
- if echo "$seg" | grep -qE '\bgit\s+switch\s+(-c|--create)\b'; then
107
+ if echo "$seg" | grep -qE "$(git_re 'switch[[:space:]]+(-c|--create)\b')"; then
67
108
  echo "BLOCKED: git branch creation requires explicit user approval." >&2
68
109
  echo "Command: $seg" >&2
69
110
  return 1
@@ -71,14 +112,17 @@ check_segment() {
71
112
 
72
113
  # git branch <name> (creation, not listing)
73
114
  # git branch without flags or with only -a/-r/-l/--list is listing
74
- if echo "$seg" | grep -qE '\bgit\s+branch\s'; then
115
+ if echo "$seg" | grep -qE "$(git_re 'branch[[:space:]]')"; then
75
116
  # Allow listing flags
76
- if echo "$seg" | grep -qE '\bgit\s+branch\s+(-[arl]|--list|--merged|--no-merged|--contains|-v|--verbose|-d|--delete|-D)\b'; then
117
+ if echo "$seg" | grep -qE "$(git_re 'branch[[:space:]]+(-[arl]|--list|--merged|--no-merged|--contains|-v|--verbose|-d|--delete|-D)\b')"; then
77
118
  return 0
78
119
  fi
79
120
  # If it has a name argument after "git branch", it's creation
80
121
  local args
81
- args=$(echo "$seg" | sed 's/.*\bgit\s\+branch\s\+//')
122
+ # The old sed required `git` and `branch` to be adjacent; with a
123
+ # global option in between it stripped nothing and every listing form
124
+ # looked like a creation. Strip up to the subcommand instead.
125
+ args=$(echo "$seg" | sed -E 's/.*[[:space:]]branch[[:space:]]+//')
82
126
  if [ -n "$args" ] && ! echo "$args" | grep -qE '^\s*$'; then
83
127
  echo "BLOCKED: git branch creation requires explicit user approval." >&2
84
128
  echo "Command: $seg" >&2
@@ -89,11 +133,21 @@ check_segment() {
89
133
  return 0
90
134
  }
91
135
 
92
- # Split on && ; || and check each part
136
+ # Split on && ; || | and check each part.
137
+ #
138
+ # A single `|` is a separator too. Without it, a read-only command piped into
139
+ # a git write arrives as ONE segment whose first word is the reader, and
140
+ # READ_ONLY_RE above exempts that whole segment - so the git write on the
141
+ # right-hand side of the pipe is never examined. Measured on the published
142
+ # file 2026-09-15: four piped shapes exited 0 while the same git operations
143
+ # exited 2 when written plainly.
144
+ #
145
+ # `||` is already turned into newlines by the rule before this one, so the
146
+ # single-pipe rule only ever sees real single pipes.
93
147
  while IFS= read -r segment; do
94
148
  if ! check_segment "$segment"; then
95
149
  exit 2
96
150
  fi
97
- done < <(echo "$COMMAND" | sed 's/&&/\n/g; s/;/\n/g; s/||/\n/g')
151
+ done < <(echo "$COMMAND" | sed 's/&&/\n/g; s/;/\n/g; s/||/\n/g; s/|/\n/g')
98
152
 
99
153
  exit 0
@@ -0,0 +1,102 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # git-pack-temp-cleanup-guard.sh — Stop tmp_pack_* explosion
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Subagents and parallel git operations leave stale
7
+ # .git/objects/pack/tmp_pack_* files behind when git gc / repack
8
+ # fails or is interrupted. These accumulate without bound and can
9
+ # fill ext4.vhdx (observed: 1,350 files / 144 GB on a single repo).
10
+ #
11
+ # This hook runs before any git command. It removes tmp_pack_*
12
+ # files older than CC_GIT_PACK_AGE_MIN minutes, then checks the
13
+ # remaining total. Above thresholds, it warns or blocks.
14
+ #
15
+ # TRIGGER: PreToolUse MATCHER: "Bash"
16
+ #
17
+ # CONFIG:
18
+ # CC_GIT_PACK_AGE_MIN=60 minutes; older tmp_pack_* are removed
19
+ # CC_GIT_PACK_WARN_GB=1 warn at this many GiB remaining
20
+ # CC_GIT_PACK_STRONG_GB=5 strong warning at this many GiB
21
+ # CC_GIT_PACK_BLOCK_GB=10 block git command at this many GiB
22
+ # CC_GIT_PACK_DISABLE=1 set to disable this hook entirely
23
+ # ================================================================
24
+
25
+ # Without jq, the parse below silently yields empty and this hook stops
26
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
27
+ # here: blocking would halt every tool call, and exiting 0 would change
28
+ # the behaviour of guards that do not depend on the parsed value.
29
+ if ! command -v jq >/dev/null 2>&1; then
30
+ _nojq_warned="/tmp/cc-nojq-warned-git-pack-temp-cleanup-guard-$PPID"
31
+ [ -f "$_nojq_warned" ] || {
32
+ echo "WARNING [git-pack-temp-cleanup-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
33
+ : > "$_nojq_warned"
34
+ }
35
+ fi
36
+
37
+ [ "${CC_GIT_PACK_DISABLE:-0}" = "1" ] && exit 0
38
+
39
+ INPUT=$(cat)
40
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
41
+
42
+ [ -z "$COMMAND" ] && exit 0
43
+
44
+ # Only act on git commands. \bgit\b matches git as a whole word, so
45
+ # pathnames like /usr/bin/gitlab won't trigger.
46
+ echo "$COMMAND" | grep -qE '(^|[^a-zA-Z0-9._-])git([^a-zA-Z0-9._-]|$)' || exit 0
47
+
48
+ AGE_MIN="${CC_GIT_PACK_AGE_MIN:-60}"
49
+ WARN_GB="${CC_GIT_PACK_WARN_GB:-1}"
50
+ STRONG_GB="${CC_GIT_PACK_STRONG_GB:-5}"
51
+ BLOCK_GB="${CC_GIT_PACK_BLOCK_GB:-10}"
52
+
53
+ # Resolve the .git directory of the current repo. If we are outside a
54
+ # git repo, exit silently — the user's git command will fail on its own.
55
+ GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || exit 0
56
+ PACK_DIR="$GIT_DIR/objects/pack"
57
+
58
+ [ -d "$PACK_DIR" ] || exit 0
59
+
60
+ # Step 1: remove tmp_pack_* older than AGE_MIN minutes.
61
+ # Use -maxdepth 1 so we never recurse. Only match the literal prefix.
62
+ removed_count=0
63
+ removed_bytes=0
64
+ while IFS= read -r -d '' f; do
65
+ sz=$(stat -c '%s' "$f" 2>/dev/null || echo 0)
66
+ if rm -f "$f" 2>/dev/null; then
67
+ removed_count=$((removed_count + 1))
68
+ removed_bytes=$((removed_bytes + sz))
69
+ fi
70
+ done < <(find "$PACK_DIR" -maxdepth 1 -type f -name 'tmp_pack_*' -mmin "+$AGE_MIN" -print0 2>/dev/null)
71
+
72
+ if [ "$removed_count" -gt 0 ]; then
73
+ removed_mib=$((removed_bytes / 1024 / 1024))
74
+ echo "INFO: git-pack-temp-cleanup-guard removed $removed_count stale tmp_pack_* files (${removed_mib} MiB) older than ${AGE_MIN} min in $PACK_DIR" >&2
75
+ fi
76
+
77
+ # Step 2: compute remaining total size of tmp_pack_*.
78
+ remaining_bytes=0
79
+ while IFS= read -r -d '' f; do
80
+ sz=$(stat -c '%s' "$f" 2>/dev/null || echo 0)
81
+ remaining_bytes=$((remaining_bytes + sz))
82
+ done < <(find "$PACK_DIR" -maxdepth 1 -type f -name 'tmp_pack_*' -print0 2>/dev/null)
83
+
84
+ remaining_gb=$((remaining_bytes / 1024 / 1024 / 1024))
85
+
86
+ if [ "$remaining_gb" -ge "$BLOCK_GB" ]; then
87
+ echo "BLOCKED: tmp_pack_* total is ${remaining_gb} GiB in $PACK_DIR (threshold ${BLOCK_GB} GiB)." >&2
88
+ echo " Past incidents accumulated 144 GiB and filled ext4.vhdx." >&2
89
+ echo " Investigate before running more git commands. Inspect with:" >&2
90
+ echo " find \"$PACK_DIR\" -maxdepth 1 -name 'tmp_pack_*' -printf '%s %p\\n'" >&2
91
+ echo " Override (one shot) with: CC_GIT_PACK_DISABLE=1 git ..." >&2
92
+ exit 2
93
+ fi
94
+
95
+ if [ "$remaining_gb" -ge "$STRONG_GB" ]; then
96
+ echo "STRONG WARNING: tmp_pack_* total is ${remaining_gb} GiB in $PACK_DIR (strong threshold ${STRONG_GB} GiB)." >&2
97
+ echo " Investigate parallel git activity before this grows further." >&2
98
+ elif [ "$remaining_gb" -ge "$WARN_GB" ]; then
99
+ echo "WARNING: tmp_pack_* total is ${remaining_gb} GiB in $PACK_DIR (threshold ${WARN_GB} GiB)." >&2
100
+ fi
101
+
102
+ exit 0
@@ -0,0 +1,218 @@
1
+ #!/bin/bash
2
+ # git-push-blast-radius-guard.sh — Cap a runaway fan-out of git pushes that burns CI minutes
3
+ #
4
+ # Solves: When a bug touches many open PRs, the agent can "fix each branch
5
+ # individually" — cherry-pick the same change onto branch after branch and push
6
+ # each one. Every push to a distinct branch triggers the full CI suite, so the
7
+ # cost scales with the number of branches, not the size of the fix. In #65944 a
8
+ # 1-line lint fix was pushed to 13 PR branches across 3 rounds (~150+ workflow
9
+ # runs), exhausting the entire 2,000-minute monthly GitHub Actions allotment in
10
+ # under 3 hours and tripping an account-level Actions block. The operator's own
11
+ # root-cause note: the correct shape was "fix once on main, let PRs inherit it
12
+ # via rebase — 1 CI run instead of 150+."
13
+ #
14
+ # Existing hooks miss this exact shape:
15
+ # - git-operations-require-approval.sh blocks *every* git push (all-or-nothing,
16
+ # off by default); it never counts how many distinct branches a session has
17
+ # pushed, so it can't tell a normal 1-branch push from a 13-branch fan-out.
18
+ # - same-command-repeat-detector.sh keys on the *same* command repeating; a
19
+ # fan-out pushes a *different* branch each time, so it never matches (the
20
+ # same blind spot loop-detector.sh had before webfetch-runaway-guard.sh).
21
+ # - tool-call-rate-limiter.sh counts *all* tool calls in a short window; pushes
22
+ # spread across hours slip under it and it cannot see "distinct branches."
23
+ # - parallel-batch-size-limiter.sh measures *concurrent* batches, not sequential
24
+ # pushes to many branches across rounds.
25
+ #
26
+ # This counts the SET of distinct branches pushed in a rolling per-session window
27
+ # and, once that set crosses a threshold, surfaces the fix-on-main-then-rebase
28
+ # pattern and (by default) blocks the next branch push — the confirmation the
29
+ # operator wished for ("shouldn't push to more than 2-3 branches without
30
+ # confirmation"). The block is recoverable: raise the threshold, switch to warn,
31
+ # or set off. Re-pushing the *same* branch never inflates the count, so an
32
+ # ordinary edit-push-edit-push loop on one feature branch is untouched; only a
33
+ # genuine multi-branch fan-out trips it. `git push --all` / `--mirror` pushes
34
+ # every local branch at once (maximum blast radius) and is treated as a trip
35
+ # immediately.
36
+ #
37
+ # TRIGGER: PreToolUse MATCHER: "Bash"
38
+ # Config (all optional):
39
+ # CC_PUSH_BLAST_GUARD=block block | warn | off
40
+ # CC_PUSH_BLAST_BLOCK=6 block once this many distinct branches fall in the window
41
+ # CC_PUSH_BLAST_WARN=3 warn (stderr, non-blocking) at this many
42
+ # CC_PUSH_BLAST_WINDOW=3600 rolling window in seconds (default 1 hour)
43
+ # CC_PUSH_BLAST_DIR state dir (default: /tmp/cc-push-blast)
44
+ # Related: https://github.com/anthropics/claude-code/issues/65944
45
+
46
+ INPUT=$(cat)
47
+
48
+ MODE="${CC_PUSH_BLAST_GUARD:-block}"
49
+ [ "$MODE" = "off" ] && exit 0
50
+
51
+ # Only act on Bash. Fail open on anything unexpected.
52
+ TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
53
+ [ "$TOOL" != "Bash" ] && exit 0
54
+
55
+ COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
56
+ [ -z "$COMMAND" ] && exit 0
57
+
58
+ # git accepts global options between `git` and the subcommand, so `git push`
59
+ # as two adjacent words never sees `git -C <dir> push` - which is exactly how
60
+ # an agent pushes to branch after branch without changing directory. Reported
61
+ # in #1117. `git send-pack` is the plumbing form of the same operation.
62
+ GIT_OPT='(-[cC][[:space:]]+[^[:space:]]+|--(git-dir|work-tree|namespace|exec-path|config-env|attr-source|super-prefix)(=[^[:space:]]+|[[:space:]]+[^[:space:]]+)|-[pP]|--(paginate|no-pager|bare|no-replace-objects|literal-pathspecs|glob-pathspecs|noglob-pathspecs|icase-pathspecs|no-optional-locks|no-lazy-fetch|no-advice))'
63
+ GIT_HEAD='(^|[[:space:];&|(]|/|"|'"'"')git'
64
+ GIT_PUSH_RE="${GIT_HEAD}([[:space:]]+${GIT_OPT})*[[:space:]]+(push|send-pack)\\b|${GIT_HEAD}-(push|send-pack)\\b"
65
+
66
+ # Quick reject: nothing to do unless the command runs `git push` somewhere.
67
+ printf '%s' "$COMMAND" | grep -qE "$GIT_PUSH_RE" || exit 0
68
+
69
+ BLOCK_AT="${CC_PUSH_BLAST_BLOCK:-6}"
70
+ WARN_AT="${CC_PUSH_BLAST_WARN:-3}"
71
+ WINDOW="${CC_PUSH_BLAST_WINDOW:-3600}"
72
+ case "$BLOCK_AT" in ''|*[!0-9]*) exit 0;; esac
73
+ case "$WARN_AT" in ''|*[!0-9]*) exit 0;; esac
74
+ case "$WINDOW" in ''|*[!0-9]*) exit 0;; esac
75
+
76
+ # Key state per session so one session's work never trips another's guard.
77
+ SID=$(printf '%s' "$INPUT" | jq -r '.session_id // "default"' 2>/dev/null)
78
+ case "$SID" in ''|*[!A-Za-z0-9_-]*) SID="default";; esac
79
+
80
+ # ---- Work out which branch(es) this command pushes to --------------------
81
+ # A command may chain several segments (&&, ;, newline, |). Inspect each git
82
+ # push segment and collect the branch name(s) it targets. Unknown/odd shapes
83
+ # fail open (they simply contribute nothing rather than guessing wrong).
84
+ FANOUT=0 # set when --all/--mirror pushes every branch at once
85
+ declare -a BRANCHES=()
86
+
87
+ # Split into segments on shell separators so each `git push ...` is seen alone.
88
+ SEGMENTS=$(printf '%s' "$COMMAND" | tr '\n;|' '\n\n\n' | sed 's/&&/\n/g')
89
+
90
+ while IFS= read -r seg; do
91
+ printf '%s' "$seg" | grep -qE "$GIT_PUSH_RE" || continue
92
+
93
+ # Tokens after the subcommand. The old `sed 's/.*\bgit[[:space:]]+push//'`
94
+ # stripped nothing when a global option sat between `git` and `push`, so the
95
+ # whole command ended up parsed as if it were the argument list (#1117).
96
+ # Walking the tokens has no such failure mode.
97
+ # shellcheck disable=SC2206
98
+ _all=( $seg )
99
+ after=""
100
+ _i=0
101
+ while [ "$_i" -lt "${#_all[@]}" ]; do
102
+ case "${_all[$_i]}" in
103
+ push|send-pack) after="${_all[*]:$((_i + 1))}"; break ;;
104
+ esac
105
+ _i=$((_i + 1))
106
+ done
107
+
108
+ # Whole-repo fan-out: one command, every branch, maximum CI blast radius.
109
+ if printf '%s' "$after" | grep -qE '(^|[[:space:]])(--all|--mirror)([[:space:]]|$)'; then
110
+ FANOUT=1
111
+ continue
112
+ fi
113
+ # shellcheck disable=SC2206
114
+ toks=( $after )
115
+
116
+ refspecs=()
117
+ seen_remote=0
118
+ i=0
119
+ while [ "$i" -lt "${#toks[@]}" ]; do
120
+ t="${toks[$i]}"
121
+ i=$((i + 1))
122
+ case "$t" in
123
+ # Flags that take a separate value -> skip the value too.
124
+ --repo|-o|--push-option|--receive-pack|--exec)
125
+ i=$((i + 1)); continue ;;
126
+ -*) continue ;; # any other flag
127
+ esac
128
+ # First bare token is the remote (origin / upstream / a URL). After that,
129
+ # bare tokens are refspecs (branches).
130
+ if [ "$seen_remote" -eq 0 ]; then
131
+ seen_remote=1
132
+ continue
133
+ fi
134
+ refspecs+=("$t")
135
+ done
136
+
137
+ if [ "${#refspecs[@]}" -eq 0 ]; then
138
+ # `git push` / `git push origin` with no refspec -> current branch.
139
+ cur=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
140
+ [ -n "$cur" ] && [ "$cur" != "HEAD" ] && BRANCHES+=("$cur")
141
+ continue
142
+ fi
143
+
144
+ for r in "${refspecs[@]}"; do
145
+ # Strip a leading '+' (force) and take the destination side of any colon.
146
+ r="${r#+}"
147
+ dst="${r##*:}"
148
+ # Ignore tag/ref deletions and empty sources.
149
+ [ -z "$dst" ] && continue
150
+ case "$dst" in
151
+ HEAD) cur=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
152
+ [ -n "$cur" ] && [ "$cur" != "HEAD" ] && BRANCHES+=("$cur"); continue ;;
153
+ esac
154
+ BRANCHES+=("$dst")
155
+ done
156
+ done <<EOF
157
+ $SEGMENTS
158
+ EOF
159
+
160
+ # Nothing identifiable and not a fan-out: fail open.
161
+ if [ "$FANOUT" -eq 0 ] && [ "${#BRANCHES[@]}" -eq 0 ]; then
162
+ exit 0
163
+ fi
164
+
165
+ # ---- Record into the rolling per-session window --------------------------
166
+ STATE_DIR="${CC_PUSH_BLAST_DIR:-/tmp/cc-push-blast}"
167
+ mkdir -p "$STATE_DIR" 2>/dev/null || exit 0
168
+ STATE="$STATE_DIR/$SID"
169
+
170
+ NOW=$(date +%s)
171
+ CUTOFF=$((NOW - WINDOW))
172
+
173
+ # Append "<ts>\t<branch>" for every branch this command pushes.
174
+ for b in "${BRANCHES[@]}"; do
175
+ # Sanitise tab/newline out of the branch name for the state file.
176
+ safe=$(printf '%s' "$b" | tr -d '\t\n')
177
+ [ -n "$safe" ] && printf '%s\t%s\n' "$NOW" "$safe" >> "$STATE" 2>/dev/null
178
+ done
179
+
180
+ # Prune entries older than the window.
181
+ if [ -f "$STATE" ]; then
182
+ awk -F'\t' -v c="$CUTOFF" '$1 ~ /^[0-9]+$/ && $1 >= c' "$STATE" > "$STATE.tmp" 2>/dev/null && mv "$STATE.tmp" "$STATE" 2>/dev/null
183
+ fi
184
+
185
+ # Count DISTINCT branches inside the window.
186
+ if [ -f "$STATE" ]; then
187
+ DISTINCT=$(awk -F'\t' '{print $2}' "$STATE" 2>/dev/null | sort -u | grep -c .)
188
+ else
189
+ DISTINCT=0
190
+ fi
191
+ case "$DISTINCT" in ''|*[!0-9]*) DISTINCT=0;; esac
192
+
193
+ # A whole-repo fan-out is an immediate trip regardless of the counter.
194
+ TRIP=0
195
+ [ "$FANOUT" -eq 1 ] && TRIP=1
196
+ [ "$DISTINCT" -ge "$BLOCK_AT" ] && TRIP=1
197
+
198
+ MINS=$((WINDOW / 60))
199
+ if [ "$FANOUT" -eq 1 ]; then
200
+ SUBJECT="This 'git push --all/--mirror' pushes every local branch at once"
201
+ else
202
+ SUBJECT="This makes ${DISTINCT} distinct branches pushed within ${MINS} min"
203
+ fi
204
+ MSG="${SUBJECT}. Each branch push triggers the full CI suite, so cost scales with branch count: in #65944 a 1-line fix pushed across 13 branches ran ~150+ workflow runs and burned the entire 2,000-minute monthly GitHub Actions allotment in under 3 hours. If you are applying one fix to many branches, stop and use the cheap shape instead: commit the fix once on main (or a single branch), merge it, and let the other branches inherit it via rebase/merge — 1 CI run instead of one per branch. To proceed anyway, raise CC_PUSH_BLAST_BLOCK, set CC_PUSH_BLAST_GUARD=warn to only warn, or =off to disable. State resets after ${WINDOW}s of no pushes: ${STATE}"
205
+
206
+ if [ "$TRIP" -eq 1 ]; then
207
+ if [ "$MODE" = "warn" ]; then
208
+ echo "git-push-blast-radius-guard: $MSG" >&2
209
+ exit 0
210
+ fi
211
+ # block (default): structured decision so the model sees the reason.
212
+ jq -n --arg r "$MSG" '{decision: "block", reason: $r}'
213
+ exit 0
214
+ elif [ "$DISTINCT" -ge "$WARN_AT" ]; then
215
+ echo "git-push-blast-radius-guard: ${DISTINCT} distinct branches pushed within ${MINS} min — each push triggers CI; consider fix-on-main + rebase if applying one change to many branches (#65944). Blocks at ${BLOCK_AT}." >&2
216
+ fi
217
+
218
+ exit 0
@@ -20,9 +20,30 @@ if echo "$COMMAND" | grep -qE '\bgit\s+remote\s+add\b'; then
20
20
  echo "Verify this is a trusted repository." >&2
21
21
  fi
22
22
 
23
- # Check for push to non-origin remote
24
- if echo "$COMMAND" | grep -qE '\bgit\s+push\s+(?!origin\b)\w'; then
25
- REMOTE=$(echo "$COMMAND" | grep -oE 'git\s+push\s+(\S+)' | awk '{print $3}')
23
+ # Check for push to a remote that is not origin.
24
+ #
25
+ # The previous version used `(?!origin\b)`, a lookahead that ERE does not have:
26
+ # grep -E rejected the pattern, returned 2, and the `if` was never true. The
27
+ # warning below could not fire on any input. Deciding "is it origin?" in the
28
+ # shell instead of the pattern removes the need for a lookahead entirely.
29
+ #
30
+ # `git` also accepts global options before the subcommand, so `git -C <dir>
31
+ # push upstream main` has to be matched as well (#1117).
32
+ GIT_OPT='(-[cC][[:space:]]+[^[:space:]]+|--(git-dir|work-tree|namespace|exec-path|config-env|attr-source|super-prefix)(=[^[:space:]]+|[[:space:]]+[^[:space:]]+)|-[pP]|--(paginate|no-pager|bare|no-replace-objects|literal-pathspecs|glob-pathspecs|noglob-pathspecs|icase-pathspecs|no-optional-locks|no-lazy-fetch|no-advice))'
33
+ GIT_HEAD='(^|[[:space:];&|(]|/|"|'"'"')git'
34
+ GIT_PUSH_RE="${GIT_HEAD}([[:space:]]+${GIT_OPT})*[[:space:]]+push([[:space:]]|$)"
35
+
36
+ if echo "$COMMAND" | grep -qE "$GIT_PUSH_RE"; then
37
+ # First bare word after `push` is the remote (flags and their values are
38
+ # skipped). No remote at all means the default one, which is fine.
39
+ REMOTE=$(echo "$COMMAND" | awk '{
40
+ for (i = 1; i <= NF; i++) {
41
+ if ($i == "push") { seen = 1; continue }
42
+ if (!seen) continue
43
+ if ($i ~ /^-/) { continue }
44
+ print $i; exit
45
+ }
46
+ }')
26
47
  if [ -n "$REMOTE" ] && [ "$REMOTE" != "origin" ]; then
27
48
  echo "WARNING: Pushing to non-origin remote: $REMOTE" >&2
28
49
  echo "Verify this remote is trusted." >&2
@@ -0,0 +1,85 @@
1
+ #!/bin/bash
2
+ # git-rm-orphan-wipe-guard.sh — Block whole-working-tree deletion via git
3
+ #
4
+ # Solves: Claude Code (or a careless one-liner it runs) wiping an entire
5
+ # working tree — and its recovery path — with git itself, slipping
6
+ # past the rm-based guards.
7
+ #
8
+ # The #70687 pattern (real loss of 3 years of work + .git history):
9
+ # git checkout --orphan wipe && git rm -rf . --quiet
10
+ # 1. "git checkout --orphan" starts a branch with NO parent commit, so
11
+ # there is no prior commit to restore the files from afterwards.
12
+ # 2. "git rm -rf ." then removes every tracked file from the index AND
13
+ # the working tree.
14
+ # Together the project is gone with no commit to recover from.
15
+ #
16
+ # Why existing guards miss it:
17
+ # - rm-safety-net.sh only fires on a command that STARTS with "rm"
18
+ # (^rm). "git rm ..." starts with "git", so it slips through.
19
+ # - git-checkout-safety-guard.sh Check 1 matches "checkout <letter>";
20
+ # "git checkout --orphan" starts with "-", so it is not matched.
21
+ # - bulk-file-delete-guard.sh only blocks "git rm -rf ." when the file
22
+ # count crosses its threshold, so a small-but-total wipe passes.
23
+ #
24
+ # Detects:
25
+ # git checkout --orphan <name> (detaches from all history)
26
+ # git switch --orphan <name> (same, newer syntax)
27
+ # git rm -r / -rf / --recursive (recursive removal of the tree)
28
+ # git rm . / git rm * (whole-tree target)
29
+ #
30
+ # Does NOT block (no on-disk data loss / normal use):
31
+ # git rm <file> (single tracked file)
32
+ # git rm --cached ... (untracks only; disk files survive)
33
+ # git checkout <branch> / -- file (covered by git-checkout-safety-guard)
34
+ #
35
+ # TRIGGER: PreToolUse MATCHER: "Bash"
36
+
37
+ # Without jq, the parse below silently yields empty and this hook stops
38
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
39
+ # here: blocking would halt every tool call, and exiting 0 would change
40
+ # the behaviour of guards that do not depend on the parsed value.
41
+ if ! command -v jq >/dev/null 2>&1; then
42
+ _nojq_warned="/tmp/cc-nojq-warned-git-rm-orphan-wipe-guard-$PPID"
43
+ [ -f "$_nojq_warned" ] || {
44
+ echo "WARNING [git-rm-orphan-wipe-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
45
+ : > "$_nojq_warned"
46
+ }
47
+ fi
48
+
49
+ INPUT=$(cat)
50
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
51
+
52
+ [ -z "$COMMAND" ] && exit 0
53
+
54
+ # === Check 1: git checkout/switch --orphan (removes the recovery path) ===
55
+ if echo "$COMMAND" | grep -qE '\bgit\s+(checkout|switch)\b[^|;&]*--orphan\b'; then
56
+ echo "BLOCKED: git checkout --orphan starts a branch with no parent commit." >&2
57
+ echo " Followed by 'git rm -rf .' this leaves no commit to recover from (#70687)." >&2
58
+ echo " If you really need an orphan branch, run it yourself outside the agent." >&2
59
+ exit 2
60
+ fi
61
+
62
+ # === git rm handling: only the destructive (whole-tree) forms ===
63
+ if echo "$COMMAND" | grep -qE '\bgit\s+rm\b'; then
64
+ # --cached removes from the index only; working-tree files survive. Safe.
65
+ if echo "$COMMAND" | grep -qE '\bgit\s+rm\b[^|;&]*--cached\b'; then
66
+ exit 0
67
+ fi
68
+
69
+ # Check 2: recursive removal (-r / -R / -rf / --recursive)
70
+ if echo "$COMMAND" | grep -qE '\bgit\s+rm\s+(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)\b'; then
71
+ echo "BLOCKED: git rm -r removes every tracked file in the tree from disk." >&2
72
+ echo " rm-safety-net does not catch this (the command starts with 'git', not 'rm')." >&2
73
+ echo " Delete specific files by name, or use 'git rm --cached' to untrack only." >&2
74
+ exit 2
75
+ fi
76
+
77
+ # Check 3: whole-tree target ( . or * ) even without -r
78
+ if echo "$COMMAND" | grep -qE '\bgit\s+rm\b[^|;&]*(\s\.(\s|$)|\s\./(\s|$)|\s\*(\s|$))'; then
79
+ echo "BLOCKED: git rm targeting '.' or '*' removes the whole working tree." >&2
80
+ echo " Delete specific files by name, or use 'git rm --cached' to untrack only." >&2
81
+ exit 2
82
+ fi
83
+ fi
84
+
85
+ exit 0
@@ -28,6 +28,18 @@
28
28
  # }
29
29
  # ================================================================
30
30
 
31
+ # Without jq, the parse below silently yields empty and this hook stops
32
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
33
+ # here: blocking would halt every tool call, and exiting 0 would change
34
+ # the behaviour of guards that do not depend on the parsed value.
35
+ if ! command -v jq >/dev/null 2>&1; then
36
+ _nojq_warned="/tmp/cc-nojq-warned-git-stash-before-checkout-$PPID"
37
+ [ -f "$_nojq_warned" ] || {
38
+ echo "WARNING [git-stash-before-checkout]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
39
+ : > "$_nojq_warned"
40
+ }
41
+ fi
42
+
31
43
  INPUT=$(cat)
32
44
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
33
45
  [ -z "$COMMAND" ] && exit 0
File without changes