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
@@ -0,0 +1,341 @@
1
+ #!/bin/bash
2
+ # Tests for aup-retry-loop-guard.sh
3
+ HOOK="$(dirname "$0")/../examples/aup-retry-loop-guard.sh"
4
+ PASS=0
5
+ FAIL=0
6
+
7
+ run_test() {
8
+ local desc="$1"
9
+ local result="$2"
10
+ if [ "$result" = "pass" ]; then
11
+ echo " PASS: $desc"
12
+ PASS=$((PASS + 1))
13
+ else
14
+ echo " FAIL: $desc"
15
+ FAIL=$((FAIL + 1))
16
+ fi
17
+ }
18
+
19
+ TMPDIR=$(mktemp -d)
20
+ trap 'rm -rf "$TMPDIR"' EXIT
21
+ LOG="$TMPDIR/aup-block.log"
22
+ STATE="$TMPDIR/state"
23
+
24
+ log_line() {
25
+ local seconds_ago="$1"
26
+ local tool="$2"
27
+ local kind="${3:-cyber-safeguards}"
28
+ local ts
29
+ ts=$(date -u -d "$seconds_ago seconds ago" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
30
+ || date -u -v "-${seconds_ago}S" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null)
31
+ printf '%s|claude-opus-4-7|%s|%s|excerpt\n' "$ts" "$tool" "$kind" >> "$LOG"
32
+ }
33
+
34
+ reset_state() {
35
+ rm -f "$LOG"
36
+ rm -rf "$STATE"
37
+ mkdir -p "$STATE"
38
+ unset CC_AUP_RETRY_LOOP_GUARD_DISABLE
39
+ unset CC_AUP_RETRY_LOOP_GUARD_QUIET
40
+ unset CC_AUP_RETRY_LOOP_GUARD_THRESHOLD
41
+ unset CC_AUP_RETRY_LOOP_GUARD_WINDOW_MIN
42
+ unset CC_AUP_RETRY_LOOP_GUARD_TARGET
43
+ }
44
+
45
+ echo "Testing aup-retry-loop-guard.sh"
46
+ echo "================================"
47
+
48
+ # Test 1: DISABLE=1 silences
49
+ reset_state
50
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
51
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_DISABLE=1 bash "$HOOK" 2>&1)
52
+ EXIT=$?
53
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
54
+ run_test "DISABLE=1 silences entirely" pass
55
+ else
56
+ run_test "DISABLE=1 (exit=$EXIT, out_len=${#OUT})" fail
57
+ fi
58
+
59
+ # Test 2: QUIET=1 silences
60
+ reset_state
61
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
62
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_QUIET=1 bash "$HOOK" 2>&1)
63
+ EXIT=$?
64
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
65
+ run_test "QUIET=1 silences" pass
66
+ else
67
+ run_test "QUIET=1 (exit=$EXIT, out_len=${#OUT})" fail
68
+ fi
69
+
70
+ # Test 3: Log missing → silent
71
+ reset_state
72
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
73
+ EXIT=$?
74
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
75
+ run_test "Log missing → silent" pass
76
+ else
77
+ run_test "Log missing (exit=$EXIT, out_len=${#OUT})" fail
78
+ fi
79
+
80
+ # Test 4: Log empty → silent
81
+ reset_state
82
+ : > "$LOG"
83
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
84
+ EXIT=$?
85
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
86
+ run_test "Log empty → silent" pass
87
+ else
88
+ run_test "Log empty (exit=$EXIT, out_len=${#OUT})" fail
89
+ fi
90
+
91
+ # Test 5: 1 block in window (below threshold) → silent
92
+ reset_state
93
+ log_line 60 "Bash"
94
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
95
+ EXIT=$?
96
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
97
+ run_test "1 block (below threshold 3) → silent" pass
98
+ else
99
+ run_test "1 block (exit=$EXIT, out_len=${#OUT})" fail
100
+ fi
101
+
102
+ # Test 6: 2 blocks in window (below threshold) → silent
103
+ reset_state
104
+ log_line 60 "Bash"; log_line 120 "Bash"
105
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
106
+ EXIT=$?
107
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
108
+ run_test "2 blocks (below threshold 3) → silent" pass
109
+ else
110
+ run_test "2 blocks (exit=$EXIT, out_len=${#OUT})" fail
111
+ fi
112
+
113
+ # Test 7: 3 blocks same tool in window → advisory emitted
114
+ reset_state
115
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
116
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
117
+ EXIT=$?
118
+ if [ "$EXIT" = "0" ] && echo "$OUT" | grep -q "Retry-loop pattern detected"; then
119
+ run_test "3 blocks same tool → advisory emitted" pass
120
+ else
121
+ run_test "3 blocks same tool (exit=$EXIT, OUT: ${OUT:0:120})" fail
122
+ fi
123
+
124
+ # Test 8: Multi-tool burst → silent (not a retry loop)
125
+ reset_state
126
+ log_line 60 "Bash"; log_line 120 "Edit"; log_line 180 "Read"
127
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
128
+ EXIT=$?
129
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
130
+ run_test "Multi-tool burst → silent (not retry loop)" pass
131
+ else
132
+ run_test "Multi-tool burst (exit=$EXIT, out_len=${#OUT})" fail
133
+ fi
134
+
135
+ # Test 9: Blocks outside window → silent (default window 5 min)
136
+ reset_state
137
+ log_line 600 "Bash"; log_line 700 "Bash"; log_line 800 "Bash"
138
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
139
+ EXIT=$?
140
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
141
+ run_test "Blocks outside window → silent" pass
142
+ else
143
+ run_test "Stale blocks (exit=$EXIT, out_len=${#OUT})" fail
144
+ fi
145
+
146
+ # Test 10: Custom THRESHOLD=2, 2 blocks same tool → advisory
147
+ reset_state
148
+ log_line 60 "Bash"; log_line 120 "Bash"
149
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_THRESHOLD=2 bash "$HOOK" 2>&1)
150
+ if echo "$OUT" | grep -q "2 Usage Policy block"; then
151
+ run_test "Custom THRESHOLD=2 → 2 blocks triggers advisory" pass
152
+ else
153
+ run_test "Custom threshold (OUT: ${OUT:0:120})" fail
154
+ fi
155
+
156
+ # Test 11: Custom WINDOW_MIN=1, 3 blocks within 1 min → advisory
157
+ reset_state
158
+ log_line 10 "Bash"; log_line 20 "Bash"; log_line 30 "Bash"
159
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_WINDOW_MIN=1 bash "$HOOK" 2>&1)
160
+ if echo "$OUT" | grep -q "Retry-loop pattern detected"; then
161
+ run_test "Custom WINDOW_MIN=1 → in-window blocks detected" pass
162
+ else
163
+ run_test "Custom window (OUT: ${OUT:0:120})" fail
164
+ fi
165
+
166
+ # Test 12: Custom WINDOW_MIN=1, blocks span 5 min → silent
167
+ reset_state
168
+ log_line 60 "Bash"; log_line 180 "Bash"; log_line 240 "Bash"
169
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_WINDOW_MIN=1 bash "$HOOK" 2>&1)
170
+ EXIT=$?
171
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
172
+ run_test "Custom WINDOW_MIN=1, blocks spread → silent" pass
173
+ else
174
+ run_test "Spread blocks with narrow window (exit=$EXIT, out_len=${#OUT})" fail
175
+ fi
176
+
177
+ # Test 13: Custom TARGET appears in advisory
178
+ reset_state
179
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
180
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_TARGET=claude-sonnet-4-6 bash "$HOOK" 2>&1)
181
+ if echo "$OUT" | grep -q "ANTHROPIC_MODEL=claude-sonnet-4-6"; then
182
+ run_test "Custom TARGET appears in advisory" pass
183
+ else
184
+ run_test "Custom target (OUT: ${OUT:0:120})" fail
185
+ fi
186
+
187
+ # Test 14: Advisory mentions /exit option
188
+ reset_state
189
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
190
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
191
+ if echo "$OUT" | grep -q "/exit"; then
192
+ run_test "Advisory recommends /exit cycle-break" pass
193
+ else
194
+ run_test "/exit recommendation (OUT: ${OUT:0:120})" fail
195
+ fi
196
+
197
+ # Test 15: Advisory references issue #61664 (the central retry-loop pain)
198
+ reset_state
199
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
200
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
201
+ if echo "$OUT" | grep -q "61664"; then
202
+ run_test "Advisory references issue #61664" pass
203
+ else
204
+ run_test "Issue #61664 reference (OUT: ${OUT:0:120})" fail
205
+ fi
206
+
207
+ # Test 16: Advisory references partner hooks
208
+ reset_state
209
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
210
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
211
+ if echo "$OUT" | grep -q "aup-false-positive-helper" && echo "$OUT" | grep -q "aup-block-pattern-logger" && echo "$OUT" | grep -q "model-swap-suggester"; then
212
+ run_test "Advisory references all three partner hooks" pass
213
+ else
214
+ run_test "Partner hook references (OUT: ${OUT:0:200})" fail
215
+ fi
216
+
217
+ # Test 17: One-shot per session — second invocation silent with same SESSION_ID
218
+ reset_state
219
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
220
+ OUT1=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_SESSION_ID="test-session-A" bash "$HOOK" 2>&1)
221
+ OUT2=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_SESSION_ID="test-session-A" bash "$HOOK" 2>&1)
222
+ OUT3=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_SESSION_ID="test-session-B" bash "$HOOK" 2>&1)
223
+ if echo "$OUT1" | grep -q "Retry-loop pattern detected" && [ -z "$OUT2" ] && echo "$OUT3" | grep -q "Retry-loop pattern detected"; then
224
+ run_test "One-shot per session — same session silent, different session fires" pass
225
+ else
226
+ run_test "One-shot (OUT1_len=${#OUT1}, OUT2_len=${#OUT2}, OUT3_len=${#OUT3})" fail
227
+ fi
228
+
229
+ # Test 18: Garbage env vars fall back to defaults
230
+ reset_state
231
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
232
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" CC_AUP_RETRY_LOOP_GUARD_THRESHOLD=abc CC_AUP_RETRY_LOOP_GUARD_WINDOW_MIN=xyz bash "$HOOK" 2>&1)
233
+ if echo "$OUT" | grep -q "Retry-loop pattern detected"; then
234
+ run_test "Garbage env vars fall back to defaults" pass
235
+ else
236
+ run_test "Garbage env vars (OUT: ${OUT:0:120})" fail
237
+ fi
238
+
239
+ # Test 19: Unparseable timestamps skipped
240
+ reset_state
241
+ printf 'BAD-TS|claude-opus-4-7|Bash|cyber-safeguards|excerpt\n' >> "$LOG"
242
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
243
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
244
+ EXIT=$?
245
+ if [ "$EXIT" = "0" ] && echo "$OUT" | grep -q "Retry-loop pattern detected"; then
246
+ run_test "Unparseable timestamps skipped without crash" pass
247
+ else
248
+ run_test "Unparseable timestamps (exit=$EXIT, OUT: ${OUT:0:120})" fail
249
+ fi
250
+
251
+ # Test 20: Mix of in-window and out-of-window single-tool blocks — count only in-window
252
+ reset_state
253
+ log_line 60 "Bash"; log_line 120 "Bash" # 2 in-window
254
+ log_line 600 "Bash"; log_line 700 "Bash" # 2 stale (outside 5min default)
255
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
256
+ EXIT=$?
257
+ # Only 2 in-window blocks; threshold is 3 → silent
258
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
259
+ run_test "Mix in/out-of-window — only in-window counted" pass
260
+ else
261
+ run_test "Mix counting (exit=$EXIT, out_len=${#OUT})" fail
262
+ fi
263
+
264
+ # Test 21: Pattern kind reflected in advisory
265
+ reset_state
266
+ log_line 60 "Bash" "safety-guardrails"
267
+ log_line 120 "Bash" "safety-guardrails"
268
+ log_line 180 "Bash" "safety-guardrails"
269
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
270
+ if echo "$OUT" | grep -q "safety-guardrails"; then
271
+ run_test "Pattern kind included in advisory" pass
272
+ else
273
+ run_test "Pattern kind (OUT: ${OUT:0:120})" fail
274
+ fi
275
+
276
+ # Test 22: Tool name in advisory reflects log
277
+ reset_state
278
+ log_line 60 "Edit"; log_line 120 "Edit"; log_line 180 "Edit"
279
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
280
+ if echo "$OUT" | grep -q 'tool "Edit"'; then
281
+ run_test "Tool name reflected in advisory" pass
282
+ else
283
+ run_test "Tool name reflection (OUT: ${OUT:0:120})" fail
284
+ fi
285
+
286
+ # Test 23: Hook never blocks (exit 0 across all paths)
287
+ reset_state
288
+ EXIT_CODES=""
289
+ for case in "disable" "quiet" "no-log" "empty-log" "below-thresh" "above-thresh" "multi-tool"; do
290
+ reset_state
291
+ case "$case" in
292
+ "disable") OUT=$(CC_AUP_RETRY_LOOP_GUARD_DISABLE=1 bash "$HOOK" 2>&1); EXIT=$? ;;
293
+ "quiet") OUT=$(CC_AUP_RETRY_LOOP_GUARD_QUIET=1 bash "$HOOK" 2>&1); EXIT=$? ;;
294
+ "no-log") OUT=$(CC_AUP_BLOCK_LOG_PATH="$TMPDIR/none.log" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1); EXIT=$? ;;
295
+ "empty-log") : > "$LOG"; OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1); EXIT=$? ;;
296
+ "below-thresh") log_line 60 "Bash"; OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1); EXIT=$? ;;
297
+ "above-thresh") log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"; OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1); EXIT=$? ;;
298
+ "multi-tool") log_line 60 "Bash"; log_line 120 "Edit"; log_line 180 "Read"; OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1); EXIT=$? ;;
299
+ esac
300
+ EXIT_CODES="$EXIT_CODES $EXIT"
301
+ done
302
+ NONZERO=$(echo "$EXIT_CODES" | tr ' ' '\n' | grep -v "^$" | grep -v "^0$" | head -1)
303
+ if [ -z "$NONZERO" ]; then
304
+ run_test "Hook never blocks (7 paths all exit 0)" pass
305
+ else
306
+ run_test "Exit codes (got: $EXIT_CODES)" fail
307
+ fi
308
+
309
+ # Test 24: GitHub references present
310
+ reset_state
311
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
312
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
313
+ if echo "$OUT" | grep -q "github.com/anthropics/claude-code/issues/60366" && echo "$OUT" | grep -q "github.com/anthropics/claude-code/issues/61664"; then
314
+ run_test "Advisory includes both anchor issue references" pass
315
+ else
316
+ run_test "Issue references (OUT: ${OUT:0:200})" fail
317
+ fi
318
+
319
+ # Test 25: 5 blocks same tool still fires (count uses actual not threshold)
320
+ reset_state
321
+ for s in 30 60 90 120 180; do log_line "$s" "Bash"; done
322
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
323
+ if echo "$OUT" | grep -q "5 Usage Policy block"; then
324
+ run_test "Higher counts reported correctly (5 blocks)" pass
325
+ else
326
+ run_test "5 blocks count (OUT: ${OUT:0:120})" fail
327
+ fi
328
+
329
+ # Test 26: QUIET escape hatch documented
330
+ reset_state
331
+ log_line 60 "Bash"; log_line 120 "Bash"; log_line 180 "Bash"
332
+ OUT=$(CC_AUP_BLOCK_LOG_PATH="$LOG" CC_AUP_RETRY_LOOP_GUARD_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
333
+ if echo "$OUT" | grep -q "CC_AUP_RETRY_LOOP_GUARD_QUIET=1"; then
334
+ run_test "Advisory documents QUIET escape hatch" pass
335
+ else
336
+ run_test "QUIET escape hatch (OUT: ${OUT:0:120})" fail
337
+ fi
338
+
339
+ echo "================================"
340
+ echo "Results: $PASS passed, $FAIL failed"
341
+ [ "$FAIL" = "0" ] && exit 0 || exit 1
@@ -0,0 +1,303 @@
1
+ #!/bin/bash
2
+ # Tests for auth-expiry-reminder.sh
3
+ HOOK="$(dirname "$0")/../examples/auth-expiry-reminder.sh"
4
+ PASS=0
5
+ FAIL=0
6
+
7
+ run_test() {
8
+ local desc="$1"
9
+ local result="$2"
10
+ if [ "$result" = "pass" ]; then
11
+ echo " PASS: $desc"
12
+ PASS=$((PASS + 1))
13
+ else
14
+ echo " FAIL: $desc"
15
+ FAIL=$((FAIL + 1))
16
+ fi
17
+ }
18
+
19
+ TMPDIR=$(mktemp -d)
20
+ trap 'rm -rf "$TMPDIR"' EXIT
21
+ STATE="$TMPDIR/state"
22
+
23
+ reset_state() {
24
+ rm -rf "$STATE"
25
+ mkdir -p "$STATE"
26
+ unset CC_AUTH_EXPIRY_REMINDER_REMIND
27
+ unset CC_AUTH_EXPIRY_REMINDER_DISABLE
28
+ unset CC_AUTH_EXPIRY_REMINDER_QUIET
29
+ unset CC_AUTH_EXPIRY_REMINDER_DATE
30
+ }
31
+
32
+ echo "Testing auth-expiry-reminder.sh"
33
+ echo "================================"
34
+
35
+ # Test 1: Default (no env vars) → silent
36
+ reset_state
37
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" bash "$HOOK" 2>&1)
38
+ EXIT=$?
39
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
40
+ run_test "Default (no env vars) is silent" pass
41
+ else
42
+ run_test "Default (exit=$EXIT, out_len=${#OUT})" fail
43
+ fi
44
+
45
+ # Test 2: REMIND=1 fires on first invocation of the day
46
+ reset_state
47
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
48
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
49
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
50
+ bash "$HOOK" 2>&1)
51
+ EXIT=$?
52
+ if [ "$EXIT" = "0" ] && printf '%s' "$OUT" | grep -q "auth-expiry-reminder"; then
53
+ run_test "REMIND=1 fires on first invocation of the day" pass
54
+ else
55
+ run_test "First invocation (exit=$EXIT, out_len=${#OUT})" fail
56
+ fi
57
+
58
+ # Test 3: Second invocation on the same day is silent (one-shot per day)
59
+ reset_state
60
+ CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
61
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
62
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
63
+ bash "$HOOK" 2>/dev/null # First fire
64
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
65
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
66
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
67
+ bash "$HOOK" 2>&1)
68
+ EXIT=$?
69
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
70
+ run_test "Second invocation same day is silent (one-shot per day)" pass
71
+ else
72
+ run_test "Same-day repeat (exit=$EXIT, out_len=${#OUT})" fail
73
+ fi
74
+
75
+ # Test 4: Next day fires again
76
+ reset_state
77
+ CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
78
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
79
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
80
+ bash "$HOOK" 2>/dev/null # Day 1 fire
81
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
82
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
83
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-31" \
84
+ bash "$HOOK" 2>&1)
85
+ EXIT=$?
86
+ if [ "$EXIT" = "0" ] && printf '%s' "$OUT" | grep -q "auth-expiry-reminder"; then
87
+ run_test "Next day fires again" pass
88
+ else
89
+ run_test "Next day (exit=$EXIT, out_len=${#OUT})" fail
90
+ fi
91
+
92
+ # Test 5: DISABLE=1 silences even when REMIND=1
93
+ reset_state
94
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
95
+ CC_AUTH_EXPIRY_REMINDER_DISABLE=1 \
96
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
97
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
98
+ bash "$HOOK" 2>&1)
99
+ EXIT=$?
100
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
101
+ run_test "DISABLE=1 silences (overrides REMIND)" pass
102
+ else
103
+ run_test "DISABLE (exit=$EXIT, out_len=${#OUT})" fail
104
+ fi
105
+
106
+ # Test 6: QUIET=1 silences even when REMIND=1
107
+ reset_state
108
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
109
+ CC_AUTH_EXPIRY_REMINDER_QUIET=1 \
110
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
111
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
112
+ bash "$HOOK" 2>&1)
113
+ EXIT=$?
114
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
115
+ run_test "QUIET=1 silences (overrides REMIND)" pass
116
+ else
117
+ run_test "QUIET (exit=$EXIT, out_len=${#OUT})" fail
118
+ fi
119
+
120
+ # Test 7: REMIND=0 → silent
121
+ reset_state
122
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=0 \
123
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
124
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
125
+ bash "$HOOK" 2>&1)
126
+ EXIT=$?
127
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
128
+ run_test "REMIND=0 is silent" pass
129
+ else
130
+ run_test "REMIND=0 (exit=$EXIT, out_len=${#OUT})" fail
131
+ fi
132
+
133
+ # Test 8: Advisory includes today's date in the header
134
+ reset_state
135
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
136
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
137
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
138
+ bash "$HOOK" 2>&1)
139
+ if printf '%s' "$OUT" | grep -q "2026-05-30"; then
140
+ run_test "Advisory includes today's date" pass
141
+ else
142
+ run_test "Date in advisory (out_len=${#OUT})" fail
143
+ fi
144
+
145
+ # Test 9: Advisory names the two checkpoint commands
146
+ reset_state
147
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
148
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
149
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
150
+ bash "$HOOK" 2>&1)
151
+ HAS1=$(printf '%s' "$OUT" | grep -c "1) Anthropic auth surface")
152
+ HAS2=$(printf '%s' "$OUT" | grep -c "2) Third-party credential chains")
153
+ if [ "$HAS1" -ge "1" ] && [ "$HAS2" -ge "1" ]; then
154
+ run_test "Advisory names both checkpoint commands" pass
155
+ else
156
+ run_test "Two checkpoints (1=$HAS1 2=$HAS2)" fail
157
+ fi
158
+
159
+ # Test 10: Advisory cites the HIGH BLOCKER issue (#62354)
160
+ reset_state
161
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
162
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
163
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
164
+ bash "$HOOK" 2>&1)
165
+ if printf '%s' "$OUT" | grep -q "62354"; then
166
+ run_test "Advisory cites #62354 HIGH BLOCKER" pass
167
+ else
168
+ run_test "Cites #62354 (out_len=${#OUT})" fail
169
+ fi
170
+
171
+ # Test 11: Advisory cites the fresh issue (#63919) and the 3P SSO issue (#63185)
172
+ reset_state
173
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
174
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
175
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
176
+ bash "$HOOK" 2>&1)
177
+ if printf '%s' "$OUT" | grep -q "63919" && printf '%s' "$OUT" | grep -q "63185"; then
178
+ run_test "Advisory cites #63919 (fresh) and #63185 (3P SSO)" pass
179
+ else
180
+ run_test "Cites #63919 and #63185 (out_len=${#OUT})" fail
181
+ fi
182
+
183
+ # Test 12: State file is stamped with today's date
184
+ reset_state
185
+ CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
186
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
187
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
188
+ bash "$HOOK" 2>/dev/null
189
+ STAMP=$(head -1 "$STATE/auth-expiry-reminder.last" 2>/dev/null)
190
+ if [ "$STAMP" = "2026-05-30" ]; then
191
+ run_test "State file is stamped with today's date" pass
192
+ else
193
+ run_test "State stamp (stamp=$STAMP)" fail
194
+ fi
195
+
196
+ # Test 13: State dir auto-created when missing
197
+ reset_state
198
+ NEW_STATE="$TMPDIR/state-fresh"
199
+ [ -d "$NEW_STATE" ] && rmdir "$NEW_STATE"
200
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
201
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$NEW_STATE" \
202
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
203
+ bash "$HOOK" 2>&1)
204
+ EXIT=$?
205
+ if [ "$EXIT" = "0" ] && [ -d "$NEW_STATE" ] && [ -f "$NEW_STATE/auth-expiry-reminder.last" ]; then
206
+ run_test "State dir auto-created when missing" pass
207
+ else
208
+ run_test "Auto-create (exit=$EXIT, dir_exists=$([ -d "$NEW_STATE" ] && echo y || echo n))" fail
209
+ fi
210
+
211
+ # Test 14: Advisory references the field guide gist
212
+ reset_state
213
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
214
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
215
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
216
+ bash "$HOOK" 2>&1)
217
+ if printf '%s' "$OUT" | grep -q "gist.github.com"; then
218
+ run_test "Advisory references the field guide gist" pass
219
+ else
220
+ run_test "Field guide link (out_len=${#OUT})" fail
221
+ fi
222
+
223
+ # Test 15: Advisory cross-references companion hook (auth-status-checker)
224
+ reset_state
225
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
226
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
227
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
228
+ bash "$HOOK" 2>&1)
229
+ if printf '%s' "$OUT" | grep -q "auth-status-checker"; then
230
+ run_test "Advisory cross-references auth-status-checker companion hook" pass
231
+ else
232
+ run_test "Companion hook link (out_len=${#OUT})" fail
233
+ fi
234
+
235
+ # Test 16: Advisory explains how to disable
236
+ reset_state
237
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
238
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
239
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
240
+ bash "$HOOK" 2>&1)
241
+ if printf '%s' "$OUT" | grep -q "unset CC_AUTH_EXPIRY_REMINDER_REMIND" \
242
+ && printf '%s' "$OUT" | grep -q "export CC_AUTH_EXPIRY_REMINDER_QUIET=1"; then
243
+ run_test "Advisory explains how to disable" pass
244
+ else
245
+ run_test "Disable instructions (out_len=${#OUT})" fail
246
+ fi
247
+
248
+ # Test 17: Never blocks — exit 0 when firing
249
+ reset_state
250
+ CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
251
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
252
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
253
+ bash "$HOOK" 2>/dev/null
254
+ EXIT=$?
255
+ if [ "$EXIT" = "0" ]; then
256
+ run_test "Never blocks (exit=0 when firing)" pass
257
+ else
258
+ run_test "Exit on fire (exit=$EXIT)" fail
259
+ fi
260
+
261
+ # Test 18: Never blocks — exit 0 when silent
262
+ reset_state
263
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" bash "$HOOK" 2>/dev/null
264
+ EXIT=$?
265
+ if [ "$EXIT" = "0" ]; then
266
+ run_test "Never blocks (exit=0 when silent)" pass
267
+ else
268
+ run_test "Exit when silent (exit=$EXIT)" fail
269
+ fi
270
+
271
+ # Test 19: Calendar-day boundary across midnight (23:55 → 00:05)
272
+ reset_state
273
+ CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
274
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
275
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
276
+ bash "$HOOK" 2>/dev/null # 23:55 on day 1
277
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
278
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
279
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-31" \
280
+ bash "$HOOK" 2>&1) # 00:05 on day 2
281
+ EXIT=$?
282
+ if [ "$EXIT" = "0" ] && printf '%s' "$OUT" | grep -q "2026-05-31"; then
283
+ run_test "Calendar-day boundary fires next-day reminder" pass
284
+ else
285
+ run_test "Midnight boundary (exit=$EXIT, out_len=${#OUT})" fail
286
+ fi
287
+
288
+ # Test 20: Advisory mentions the calendar-day cadence
289
+ reset_state
290
+ OUT=$(CC_AUTH_EXPIRY_REMINDER_REMIND=1 \
291
+ CC_AUTH_EXPIRY_REMINDER_STATE_DIR="$STATE" \
292
+ CC_AUTH_EXPIRY_REMINDER_DATE="2026-05-30" \
293
+ bash "$HOOK" 2>&1)
294
+ if printf '%s' "$OUT" | grep -q "once per calendar day"; then
295
+ run_test "Advisory mentions once-per-calendar-day cadence" pass
296
+ else
297
+ run_test "Cadence framing (out_len=${#OUT})" fail
298
+ fi
299
+
300
+ echo "================================"
301
+ echo "PASS: $PASS"
302
+ echo "FAIL: $FAIL"
303
+ [ "$FAIL" = "0" ] && exit 0 || exit 1