cc-safe-setup 29.8.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 (1017) 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-dispatch-watchdog.sh +149 -0
  178. package/examples/completion-claim-without-verification-detector.sh +207 -0
  179. package/examples/composer-guard.sh +12 -0
  180. package/examples/compound-bash-permission-resolver.sh +156 -0
  181. package/examples/compound-command-allow.sh +1 -1
  182. package/examples/compound-command-deny-enforcer.sh +183 -0
  183. package/examples/compound-inject-guard.sh +12 -0
  184. package/examples/concurrent-edit-lock.sh +12 -0
  185. package/examples/conflict-marker-guard.sh +12 -0
  186. package/examples/consecutive-error-breaker.sh +0 -0
  187. package/examples/console-log-count.sh +1 -0
  188. package/examples/context-compact-advisor.sh +29 -2
  189. package/examples/context-length-budget.sh +69 -0
  190. package/examples/context-threshold-alert.sh +12 -0
  191. package/examples/context-usage-drift-alert.sh +41 -13
  192. package/examples/conversation-history-guard.sh +12 -0
  193. package/examples/core-file-protect-guard.sh +12 -0
  194. package/examples/cors-star-warn.sh +0 -0
  195. package/examples/cost-incident-self-audit.sh +162 -0
  196. package/examples/cowork-claude-md-load-checker.sh +100 -0
  197. package/examples/cowork-fuse-staleness-watcher.sh +140 -0
  198. package/examples/cowork-hook-absence-warner.sh +167 -0
  199. package/examples/cowork-model-picker-advisor.sh +115 -0
  200. package/examples/credential-exfil-guard.sh +65 -4
  201. package/examples/credential-file-cat-guard.sh +17 -1
  202. package/examples/cron-create-receipt.sh +112 -0
  203. package/examples/cron-modification-guard.sh +12 -0
  204. package/examples/cross-product-mcp-spawn-detector.sh +178 -0
  205. package/examples/cwd-project-boundary-guard.sh +0 -0
  206. package/examples/daemon-zombie-worker-surfacer.sh +118 -0
  207. package/examples/daily-cost-guard.sh +164 -0
  208. package/examples/daily-usage-tracker.sh +0 -0
  209. package/examples/dangerous-pip-flag-guard.sh +12 -0
  210. package/examples/db-connect-guard.sh +13 -1
  211. package/examples/denied-action-retry-guard.sh +12 -0
  212. package/examples/deny-bypass-detector.sh +12 -0
  213. package/examples/deny-rule-integrity-verifier.sh +181 -0
  214. package/examples/dependency-install-guard.sh +12 -0
  215. package/examples/deploy-guard.sh +14 -2
  216. package/examples/deploy-path-verify-guard.sh +12 -0
  217. package/examples/deployment-readback-gate.sh +135 -0
  218. package/examples/deployment-readback-gh-adapter.sh +247 -0
  219. package/examples/deployment-verify-guard.sh +25 -2
  220. package/examples/destructive-db-script-write-guard.sh +166 -0
  221. package/examples/destructive-migration-write-guard.sh +163 -0
  222. package/examples/diff-size-guard.sh +12 -0
  223. package/examples/disabled-feature-toggle-advisor.sh +88 -0
  224. package/examples/disk-partition-guard.sh +12 -0
  225. package/examples/dispatch-allowlist-preflight.sh +301 -0
  226. package/examples/dispatch-liveness-watchdog.sh +216 -0
  227. package/examples/dispatch-receipt.sh +174 -0
  228. package/examples/django-migrate-guard.sh +12 -0
  229. package/examples/dns-config-guard.sh +12 -0
  230. package/examples/docker-dangerous-guard.sh +12 -0
  231. package/examples/docker-volume-guard.sh +0 -0
  232. package/examples/dockerfile-latest-guard.sh +1 -0
  233. package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
  234. package/examples/dotenv-commit-guard.sh +12 -0
  235. package/examples/dotenv-read-guard.sh +12 -0
  236. package/examples/dotfile-protection-guard.sh +12 -0
  237. package/examples/dotnet-build-on-edit.sh +1 -1
  238. package/examples/drizzle-migrate-guard.sh +27 -2
  239. package/examples/echo-probe-spam-detector.sh +176 -0
  240. package/examples/edit-counter-test-gate.sh +12 -0
  241. package/examples/edit-error-counter.sh +1 -1
  242. package/examples/edit-guard.sh +12 -0
  243. package/examples/edit-old-string-validator.sh +12 -0
  244. package/examples/edit-quote-ambiguity-guard.sh +97 -0
  245. package/examples/edit-retry-loop-guard.sh +0 -0
  246. package/examples/edit-verify.sh +0 -0
  247. package/examples/env-inline-secret-guard.sh +14 -2
  248. package/examples/env-naming-convention.sh +0 -0
  249. package/examples/env-prod-guard.sh +0 -0
  250. package/examples/env-required-check.sh +0 -0
  251. package/examples/env-source-guard.sh +12 -0
  252. package/examples/env-var-check.sh +24 -1
  253. package/examples/ephemeral-container-detector.sh +147 -0
  254. package/examples/error-memory-guard.sh +12 -0
  255. package/examples/evidence-claim-gate.sh +187 -0
  256. package/examples/exploration-budget-guard.sh +12 -0
  257. package/examples/expo-eject-guard.sh +13 -0
  258. package/examples/extended-thinking-loop-guard.sh +139 -0
  259. package/examples/extended-thinking-resume-warning.sh +119 -0
  260. package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
  261. package/examples/fabricated-command-detector.sh +145 -0
  262. package/examples/false-disk-full-guard.sh +63 -0
  263. package/examples/feature-deprecation-detector.sh +109 -0
  264. package/examples/file-change-tracker.sh +1 -1
  265. package/examples/file-change-undo-tracker.sh +0 -0
  266. package/examples/file-edit-backup.sh +63 -14
  267. package/examples/file-reference-check.sh +0 -0
  268. package/examples/file-size-limit.sh +12 -0
  269. package/examples/financial-operation-guard.sh +12 -0
  270. package/examples/firewall-guard.sh +12 -0
  271. package/examples/fish-shell-wrapper.sh +125 -7
  272. package/examples/five-hundred-milestone.sh +1 -0
  273. package/examples/flask-static-route-guard.sh +89 -0
  274. package/examples/forbidden-response-phrase-detector.sh +161 -0
  275. package/examples/gem-push-guard.sh +13 -0
  276. package/examples/gh-cli-destructive-guard.sh +13 -1
  277. package/examples/git-checkout-safety-guard.sh +12 -0
  278. package/examples/git-checkout-uncommitted-guard.sh +12 -0
  279. package/examples/git-config-guard.sh +12 -0
  280. package/examples/git-crypt-worktree-guard.sh +12 -0
  281. package/examples/git-filter-repo-guard.sh +56 -0
  282. package/examples/git-history-rewrite-guard.sh +12 -0
  283. package/examples/git-hook-bypass-guard.sh +0 -0
  284. package/examples/git-maintenance-guard.sh +83 -0
  285. package/examples/git-merge-conflict-prevent.sh +0 -0
  286. package/examples/git-message-length-check.sh +0 -0
  287. package/examples/git-message-length.sh +0 -0
  288. package/examples/git-operations-require-approval.sh +68 -14
  289. package/examples/git-pack-temp-cleanup-guard.sh +102 -0
  290. package/examples/git-push-blast-radius-guard.sh +218 -0
  291. package/examples/git-remote-guard.sh +24 -3
  292. package/examples/git-rm-orphan-wipe-guard.sh +85 -0
  293. package/examples/git-stash-before-checkout.sh +12 -0
  294. package/examples/git-stash-before-danger.sh +0 -0
  295. package/examples/git-submodule-guard.sh +69 -2
  296. package/examples/git-tag-guard.sh +12 -0
  297. package/examples/github-actions-secret-guard.sh +0 -0
  298. package/examples/gitignore-check.sh +0 -0
  299. package/examples/gitops-drift-guard.sh +12 -0
  300. package/examples/go-mod-tidy-warn.sh +1 -0
  301. package/examples/go-vet-after-edit.sh +12 -0
  302. package/examples/goal-iteration-limit-warner.sh +152 -0
  303. package/examples/grep-nul-false-negative-guard.sh +30 -0
  304. package/examples/growthbook-flag-monitor.sh +257 -0
  305. package/examples/hallucination-url-check.sh +1 -1
  306. package/examples/halt-signal-detector.sh +135 -0
  307. package/examples/handoff-on-clear.sh +65 -0
  308. package/examples/hardcoded-ip-guard.sh +1 -0
  309. package/examples/headless-empty-result-guard.sh +0 -0
  310. package/examples/headless-stop-guard.sh +0 -0
  311. package/examples/helm-install-guard.sh +2 -1
  312. package/examples/home-critical-bash-guard.sh +17 -1
  313. package/examples/hook-debug-wrapper.sh +6 -2
  314. package/examples/hook-permission-fixer.sh +0 -0
  315. package/examples/hook-self-disable-detector.sh +99 -0
  316. package/examples/hook-stdout-sanitizer.sh +6 -2
  317. package/examples/hook-tamper-guard.sh +12 -0
  318. package/examples/idle-session-cost-alert.sh +0 -0
  319. package/examples/image-dimension-guard.sh +109 -0
  320. package/examples/image-file-validator.sh +0 -0
  321. package/examples/iteration-quality-degradation-detector.sh +170 -0
  322. package/examples/java-compile-on-edit.sh +1 -1
  323. package/examples/json-syntax-check.sh +0 -0
  324. package/examples/k8s-production-guard.sh +13 -1
  325. package/examples/kill-process-guard.sh +12 -0
  326. package/examples/kubernetes-guard.sh +13 -1
  327. package/examples/laravel-artisan-guard.sh +13 -0
  328. package/examples/large-file-guard.sh +1 -1
  329. package/examples/log-level-guard.sh +0 -0
  330. package/examples/log-truncation-guard.sh +12 -0
  331. package/examples/long-session-malformed-tool-call-detector.sh +183 -0
  332. package/examples/loop-detector.sh +12 -0
  333. package/examples/magic-number-warn.sh +1 -0
  334. package/examples/main-branch-warn.sh +12 -0
  335. package/examples/markdown-link-check.sh +0 -0
  336. package/examples/max-concurrent-agents.sh +12 -0
  337. package/examples/max-edit-size-guard.sh +13 -0
  338. package/examples/max-file-count-guard.sh +0 -0
  339. package/examples/max-file-delete-count.sh +0 -0
  340. package/examples/max-function-length.sh +1 -0
  341. package/examples/max-import-count.sh +0 -0
  342. package/examples/max-subagent-count.sh +0 -0
  343. package/examples/mcp-config-freeze.sh +12 -0
  344. package/examples/mcp-config-poisoning-audit.sh +150 -0
  345. package/examples/mcp-data-boundary.sh +1 -1
  346. package/examples/mcp-misdiagnosis-arrest.sh +209 -0
  347. package/examples/mcp-orphan-leak-warner.sh +49 -0
  348. package/examples/mcp-permissions-ask-warner.sh +151 -0
  349. package/examples/mcp-routine-approval-detector.sh +154 -0
  350. package/examples/mcp-server-allowlist.sh +12 -0
  351. package/examples/mcp-server-guard.sh +12 -0
  352. package/examples/mcp-startup-bloat-detector.sh +87 -0
  353. package/examples/mcp-stdio-compatibility-test.sh +153 -0
  354. package/examples/mcp-tool-audit-log.sh +0 -0
  355. package/examples/mcp-tool-guard.sh +101 -1
  356. package/examples/mcp-warmup-wait.sh +0 -0
  357. package/examples/memory-chain-audit.sh +56 -0
  358. package/examples/memory-orphan-detector.sh +188 -0
  359. package/examples/memory-write-guard.sh +99 -17
  360. package/examples/migration-verify-guard.sh +12 -0
  361. package/examples/model-swap-suggester.sh +177 -0
  362. package/examples/model-version-alert.sh +5 -1
  363. package/examples/model-version-lock.sh +63 -0
  364. package/examples/move-delete-sequence-guard.sh +33 -2
  365. package/examples/multi-file-plan-routing-gate.sh +192 -0
  366. package/examples/multi-vendor-concurrent-warner.sh +108 -0
  367. package/examples/multi-window-auth-drift-detector.sh +183 -0
  368. package/examples/multiline-command-approver.sh +161 -23
  369. package/examples/nested-background-agent-guard.sh +109 -0
  370. package/examples/nested-spawn-inflight-guard.sh +178 -0
  371. package/examples/network-exfil-guard.sh +12 -0
  372. package/examples/network-guard.sh +12 -0
  373. package/examples/network-interface-guard.sh +12 -0
  374. package/examples/nextjs-env-guard.sh +1 -1
  375. package/examples/no-absolute-import.sh +0 -0
  376. package/examples/no-alert-confirm-prompt.sh +0 -0
  377. package/examples/no-anonymous-default-export.sh +0 -0
  378. package/examples/no-any-type.sh +0 -0
  379. package/examples/no-any-typescript.sh +1 -0
  380. package/examples/no-ask-human.sh +12 -0
  381. package/examples/no-assignment-in-condition.sh +0 -0
  382. package/examples/no-base64-exfil.sh +12 -0
  383. package/examples/no-callback-hell.sh +0 -0
  384. package/examples/no-circular-dependency.sh +0 -0
  385. package/examples/no-cleartext-storage.sh +0 -0
  386. package/examples/no-commented-code.sh +0 -0
  387. package/examples/no-commit-fixup.sh +0 -0
  388. package/examples/no-console-assert.sh +0 -0
  389. package/examples/no-console-error-swallow.sh +0 -0
  390. package/examples/no-console-in-prod.sh +0 -0
  391. package/examples/no-console-log-commit.sh +12 -0
  392. package/examples/no-console-log.sh +0 -0
  393. package/examples/no-console-time.sh +0 -0
  394. package/examples/no-cors-wildcard.sh +4 -1
  395. package/examples/no-curl-upload.sh +0 -0
  396. package/examples/no-dangerouslySetInnerHTML.sh +0 -0
  397. package/examples/no-dangling-await.sh +1 -0
  398. package/examples/no-debug-commit.sh +12 -0
  399. package/examples/no-debug-in-commit.sh +0 -0
  400. package/examples/no-deep-nesting.sh +0 -0
  401. package/examples/no-deep-relative-import.sh +1 -0
  402. package/examples/no-default-credentials.sh +0 -0
  403. package/examples/no-deploy-friday.sh +13 -1
  404. package/examples/no-disabled-test.sh +0 -0
  405. package/examples/no-document-write.sh +0 -0
  406. package/examples/no-empty-function.sh +0 -0
  407. package/examples/no-eval-in-template.sh +0 -0
  408. package/examples/no-eval-template.sh +3 -1
  409. package/examples/no-eval.sh +0 -0
  410. package/examples/no-exec-user-input.sh +0 -0
  411. package/examples/no-fixme-ship.sh +12 -0
  412. package/examples/no-floating-promises.sh +0 -0
  413. package/examples/no-force-flag.sh +22 -5
  414. package/examples/no-force-install.sh +0 -0
  415. package/examples/no-git-amend.sh +12 -0
  416. package/examples/no-git-rebase-public.sh +0 -0
  417. package/examples/no-global-install.sh +12 -0
  418. package/examples/no-global-state.sh +0 -0
  419. package/examples/no-hardcoded-port.sh +1 -0
  420. package/examples/no-hardcoded-url.sh +0 -0
  421. package/examples/no-helmet-missing.sh +0 -0
  422. package/examples/no-http-url.sh +1 -0
  423. package/examples/no-http-without-https.sh +0 -0
  424. package/examples/no-inline-style.sh +0 -0
  425. package/examples/no-inline-styles.sh +1 -0
  426. package/examples/no-innerhtml.sh +0 -0
  427. package/examples/no-install-global.sh +12 -0
  428. package/examples/no-jwt-in-url.sh +0 -0
  429. package/examples/no-large-commit.sh +0 -0
  430. package/examples/no-localhost-expose.sh +0 -0
  431. package/examples/no-magic-number.sh +0 -0
  432. package/examples/no-md5-sha1.sh +0 -0
  433. package/examples/no-mixed-line-endings.sh +8 -1
  434. package/examples/no-mutation-in-reducer.sh +0 -0
  435. package/examples/no-nested-ternary.sh +0 -0
  436. package/examples/no-network-exfil.sh +0 -0
  437. package/examples/no-open-redirect.sh +0 -0
  438. package/examples/no-output-truncation.sh +12 -0
  439. package/examples/no-package-downgrade.sh +0 -0
  440. package/examples/no-package-lock-edit.sh +12 -0
  441. package/examples/no-path-join-user-input.sh +0 -0
  442. package/examples/no-port-bind.sh +0 -0
  443. package/examples/no-process-exit.sh +0 -0
  444. package/examples/no-prototype-pollution.sh +0 -0
  445. package/examples/no-push-without-ci.sh +0 -0
  446. package/examples/no-push-without-tests.sh +12 -0
  447. package/examples/no-raw-password-in-url.sh +0 -0
  448. package/examples/no-root-user-docker.sh +1 -0
  449. package/examples/no-root-write.sh +12 -0
  450. package/examples/no-secrets-in-args.sh +4 -1
  451. package/examples/no-secrets-in-logs.sh +0 -0
  452. package/examples/no-sensitive-log.sh +0 -0
  453. package/examples/no-sleep-in-hooks.sh +0 -0
  454. package/examples/no-star-import-python.sh +1 -0
  455. package/examples/no-string-concat-sql.sh +0 -0
  456. package/examples/no-sudo-guard.sh +12 -0
  457. package/examples/no-sync-fs.sh +0 -0
  458. package/examples/no-todo-in-merge.sh +0 -0
  459. package/examples/no-todo-in-production.sh +1 -0
  460. package/examples/no-todo-without-issue.sh +0 -0
  461. package/examples/no-unused-import.sh +0 -0
  462. package/examples/no-var-keyword.sh +0 -0
  463. package/examples/no-verify-blocker.sh +12 -0
  464. package/examples/no-wget-piped-bash.sh +12 -0
  465. package/examples/no-wildcard-cors.sh +0 -0
  466. package/examples/no-wildcard-delete.sh +0 -0
  467. package/examples/no-wildcard-import.sh +0 -0
  468. package/examples/no-with-statement.sh +0 -0
  469. package/examples/no-write-outside-src.sh +0 -0
  470. package/examples/no-xml-external-entity.sh +0 -0
  471. package/examples/non-english-quality-warner.sh +156 -0
  472. package/examples/notify-waiting.sh +1 -1
  473. package/examples/npm-audit-warn.sh +0 -0
  474. package/examples/npm-global-install-guard.sh +12 -0
  475. package/examples/npm-publish-guard.sh +12 -0
  476. package/examples/npm-script-injection.sh +0 -0
  477. package/examples/npm-supply-chain-guard.sh +0 -0
  478. package/examples/nuxt-config-guard.sh +1 -0
  479. package/examples/oauth-refresh-monitor.sh +210 -0
  480. package/examples/opus-degradation-tracker.sh +187 -0
  481. package/examples/opus48-routine-task-warning.sh +196 -0
  482. package/examples/opus48-thinking-wedge-advisor.sh +143 -0
  483. package/examples/output-credential-scan.sh +1 -1
  484. package/examples/output-secret-mask.sh +31 -9
  485. package/examples/output-token-spike-detector.sh +145 -0
  486. package/examples/package-json-guard.sh +12 -0
  487. package/examples/package-lock-frozen.sh +12 -0
  488. package/examples/parallel-batch-size-limiter.sh +121 -0
  489. package/examples/parallel-cascade-detector.sh +116 -0
  490. package/examples/partial-view-claim-arrest.sh +174 -0
  491. package/examples/path-deny-bash-guard.sh +12 -0
  492. package/examples/path-traversal-guard.sh +12 -0
  493. package/examples/per-prompt-token-cap.sh +124 -0
  494. package/examples/permission-audit-log.sh +1 -1
  495. package/examples/permission-denial-enforcer.sh +12 -0
  496. package/examples/permission-entry-validator.sh +0 -0
  497. package/examples/persisted-1m-model-advisor.sh +88 -0
  498. package/examples/php-lint-on-edit.sh +1 -1
  499. package/examples/pii-upload-guard.sh +12 -0
  500. package/examples/pip-publish-guard.sh +13 -0
  501. package/examples/pip-requirements-guard.sh +12 -0
  502. package/examples/pip-venv-required.sh +12 -0
  503. package/examples/plan-mode-edit-guard.sh +12 -0
  504. package/examples/plan-mode-enforcer.sh +12 -0
  505. package/examples/plan-mode-strict-guard.sh +12 -0
  506. package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
  507. package/examples/plugin-process-cleanup.sh +0 -0
  508. package/examples/polyglot-rm-guard.sh +12 -0
  509. package/examples/post-compact-safety.sh +12 -0
  510. package/examples/post-edit-disk-verify.sh +152 -0
  511. package/examples/powershell-remove-item-guard.sh +85 -0
  512. package/examples/pr-description-check.sh +0 -0
  513. package/examples/pr-duplicate-guard.sh +13 -0
  514. package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
  515. package/examples/pre-compact-knowledge-save.sh +0 -0
  516. package/examples/pre-compact-transcript-backup.sh +0 -0
  517. package/examples/pre-execution-claim-detector.sh +179 -0
  518. package/examples/prefer-builtin-tools.sh +10 -1
  519. package/examples/prefer-const.sh +0 -0
  520. package/examples/prefer-dedicated-tools.sh +12 -0
  521. package/examples/prefer-optional-chaining.sh +0 -0
  522. package/examples/prisma-migrate-guard.sh +24 -7
  523. package/examples/production-port-kill-guard.sh +12 -0
  524. package/examples/prompt-injection-guard.sh +2 -1
  525. package/examples/prompt-usage-logger.sh +0 -0
  526. package/examples/protect-claudemd.sh +12 -0
  527. package/examples/protect-dotfiles.sh +12 -0
  528. package/examples/proxy-capture-suggester.sh +159 -0
  529. package/examples/public-artefact-socratic-narrowing.sh +232 -0
  530. package/examples/public-repo-push-guard.sh +12 -0
  531. package/examples/push-requires-test-pass-record.sh +0 -0
  532. package/examples/push-requires-test-pass.sh +12 -0
  533. package/examples/quota-anomaly-detector.sh +173 -0
  534. package/examples/quota-reset-audit.sh +58 -0
  535. package/examples/quoted-flag-approver.sh +99 -10
  536. package/examples/rails-migration-guard.sh +12 -0
  537. package/examples/rate-limit-guard.sh +0 -0
  538. package/examples/read-all-files-enforcer.sh +0 -0
  539. package/examples/read-budget-guard.sh +12 -0
  540. package/examples/read-loop-detector.sh +59 -0
  541. package/examples/read-once-guard.sh +96 -0
  542. package/examples/read-only-mode.sh +12 -0
  543. package/examples/readme-exists-check.sh +0 -0
  544. package/examples/record-read-coverage.sh +73 -0
  545. package/examples/redirect-fragment-warner.sh +149 -0
  546. package/examples/redis-flushall-guard.sh +13 -0
  547. package/examples/redundant-read-blocker.sh +132 -0
  548. package/examples/refusal-arrest-gate.sh +248 -0
  549. package/examples/registry-publish-guard.sh +13 -1
  550. package/examples/remote-control-billing-classifier.sh +135 -0
  551. package/examples/replace-all-guard.sh +12 -0
  552. package/examples/repo-visibility-guard.sh +12 -0
  553. package/examples/reroute-after-block-guard.sh +150 -0
  554. package/examples/response-budget-guard.sh +0 -0
  555. package/examples/resume-drift-watcher.sh +57 -0
  556. package/examples/rg-replace-flag-detector.sh +125 -0
  557. package/examples/rhetorical-verification-prompt-detector.sh +102 -0
  558. package/examples/ripgrep-permission-fix.sh +0 -0
  559. package/examples/rm-safety-net.sh +151 -8
  560. package/examples/role-tool-guard.sh +12 -0
  561. package/examples/route-handler-emptiness-gate.sh +324 -0
  562. package/examples/ruby-lint-on-edit.sh +1 -1
  563. package/examples/runtime-binary-change-detector.sh +102 -0
  564. package/examples/same-command-repeat-detector.sh +196 -0
  565. package/examples/same-correction-arrest.sh +169 -0
  566. package/examples/sandbox-denywrite-enforcer.sh +78 -0
  567. package/examples/sandbox-relative-path-audit.sh +83 -25
  568. package/examples/sandbox-write-verify.sh +12 -0
  569. package/examples/schema-migration-guard.sh +0 -0
  570. package/examples/scope-expansion-receipt.sh +178 -0
  571. package/examples/scope-guard.sh +88 -9
  572. package/examples/secret-file-read-guard.sh +12 -0
  573. package/examples/secret-file-write-guard.sh +150 -0
  574. package/examples/self-modify-bypass-guard.sh +0 -0
  575. package/examples/sensitive-file-read-guard.sh +23 -3
  576. package/examples/sensitive-log-guard.sh +1 -0
  577. package/examples/server-side-prompt-injection-detector.sh +69 -0
  578. package/examples/session-agent-cost-limiter.sh +12 -0
  579. package/examples/session-backup-on-start.sh +1 -1
  580. package/examples/session-cost-alert.sh +12 -0
  581. package/examples/session-drift-guard.sh +12 -0
  582. package/examples/session-duration-guard.sh +25 -2
  583. package/examples/session-end-logger.sh +0 -0
  584. package/examples/session-health-monitor.sh +0 -0
  585. package/examples/session-index-repair.sh +1 -1
  586. package/examples/session-memory-watchdog.sh +1 -0
  587. package/examples/session-permission-reset-guard.sh +12 -0
  588. package/examples/session-persistence-verifier.sh +93 -0
  589. package/examples/session-plugin-pin-watch.sh +68 -0
  590. package/examples/session-rate-monitor.sh +176 -0
  591. package/examples/session-resume-env-fix.sh +0 -0
  592. package/examples/session-start-quota-status.sh +193 -0
  593. package/examples/session-start-safety-check.sh +55 -3
  594. package/examples/session-state-saver.sh +0 -0
  595. package/examples/session-summary-stop.sh +1 -1
  596. package/examples/session-summary.sh +0 -0
  597. package/examples/session-token-counter.sh +1 -1
  598. package/examples/settings-hooks-key-restorer.sh +99 -0
  599. package/examples/settings-json-health-check.sh +57 -0
  600. package/examples/settings-json-model-guard.sh +0 -0
  601. package/examples/settings-regression-tester.sh +188 -0
  602. package/examples/shell-config-truncation-guard.sh +12 -0
  603. package/examples/shell-wrapper-guard.sh +12 -0
  604. package/examples/skill-cumulative-size-detector.sh +104 -0
  605. package/examples/skill-description-drop-detector.sh +148 -0
  606. package/examples/skill-gate.sh +0 -0
  607. package/examples/skill-truncation-detector.sh +154 -0
  608. package/examples/skills-context-recorder.sh +167 -0
  609. package/examples/skills-load-verifier.sh +96 -0
  610. package/examples/skills-settings-validator.sh +139 -0
  611. package/examples/sonnet-45-deprecation-helper.sh +85 -0
  612. package/examples/spec-file-scope-guard.sh +12 -0
  613. package/examples/spring-profile-guard.sh +1 -0
  614. package/examples/spurious-malformed-notice-detector.sh +247 -0
  615. package/examples/sql-bulk-delete-warn.sh +88 -0
  616. package/examples/sql-injection-detect.sh +0 -0
  617. package/examples/ssh-key-protect.sh +12 -0
  618. package/examples/staged-secret-scan.sh +22 -1
  619. package/examples/stale-temp-settings-detector.sh +86 -0
  620. package/examples/standing-rule-session-surfacer.sh +137 -0
  621. package/examples/stop-hook-sigterm-wrapper.sh +182 -0
  622. package/examples/stop-transcript-write-health.sh +64 -0
  623. package/examples/strict-allowlist.sh +57 -15
  624. package/examples/strip-coauthored-by.sh +50 -10
  625. package/examples/subagent-blast-radius-guard.sh +184 -0
  626. package/examples/subagent-boundary-precheck.sh +126 -0
  627. package/examples/subagent-budget-guard.sh +12 -0
  628. package/examples/subagent-claudemd-inject.sh +0 -0
  629. package/examples/subagent-closure-verify-gate.sh +164 -0
  630. package/examples/subagent-destructive-git-guard.sh +120 -0
  631. package/examples/subagent-error-detector.sh +0 -0
  632. package/examples/subagent-forged-system-reminder-guard.sh +156 -0
  633. package/examples/subagent-identity-leak-guard.sh +102 -0
  634. package/examples/subagent-identity-reassertion.sh +51 -0
  635. package/examples/subagent-inheritance-tester.sh +179 -0
  636. package/examples/subagent-permission-mode-guard.sh +110 -0
  637. package/examples/subagent-scope-guard.sh +12 -0
  638. package/examples/subagent-spawn-verification-enforcer.sh +102 -0
  639. package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
  640. package/examples/subagent-tool-call-limiter.sh +87 -15
  641. package/examples/subcommand-chain-guard.sh +12 -0
  642. package/examples/subscription-api-billing-warner.sh +160 -0
  643. package/examples/subscription-bypass-detector.sh +152 -0
  644. package/examples/svelte-lint-on-edit.sh +1 -0
  645. package/examples/swift-build-on-edit.sh +1 -1
  646. package/examples/symlink-guard.sh +27 -2
  647. package/examples/symlink-protect.sh +1 -0
  648. package/examples/system-dir-protection-guard.sh +73 -8
  649. package/examples/system-message-workaround.sh +38 -13
  650. package/examples/system-package-guard.sh +12 -0
  651. package/examples/systemd-service-guard.sh +12 -0
  652. package/examples/task-integrity-guard.sh +12 -0
  653. package/examples/temp-file-cleanup.sh +1 -1
  654. package/examples/temporal-suggestion-detector.sh +135 -0
  655. package/examples/terraform-guard.sh +27 -6
  656. package/examples/test-after-edit.sh +1 -1
  657. package/examples/test-before-push.sh +12 -0
  658. package/examples/test-coverage-reminder.sh +24 -1
  659. package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
  660. package/examples/timezone-guard.sh +0 -0
  661. package/examples/tmp-output-size-guard.sh +0 -0
  662. package/examples/todo-check.sh +1 -1
  663. package/examples/token-budget-guard.sh +12 -0
  664. package/examples/token-budget-per-task.sh +12 -0
  665. package/examples/token-usage-tracker.sh +7 -1
  666. package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
  667. package/examples/tokenizer-ratio-alert.sh +104 -0
  668. package/examples/tool-call-rate-limiter.sh +0 -0
  669. package/examples/tool-result-correlation-checker.sh +167 -0
  670. package/examples/tool-result-size-guard.sh +132 -0
  671. package/examples/tool-retry-budget-guard.sh +12 -0
  672. package/examples/transcript-contamination-detector.sh +138 -0
  673. package/examples/trustfall-mcp-injection-guard.sh +103 -0
  674. package/examples/ultrareview-large-diff-advisor.sh +184 -0
  675. package/examples/unbounded-output-guard.sh +94 -0
  676. package/examples/uncommitted-changes-stop.sh +1 -0
  677. package/examples/uncommitted-discard-guard.sh +23 -5
  678. package/examples/uncommitted-work-guard.sh +12 -0
  679. package/examples/usage-warn.sh +0 -0
  680. package/examples/user-account-guard.sh +12 -0
  681. package/examples/userprompt-submit-receipt.sh +123 -0
  682. package/examples/variable-expansion-guard.sh +12 -0
  683. package/examples/verify-after-publish-reminder.sh +93 -0
  684. package/examples/verify-before-commit.sh +12 -0
  685. package/examples/version-bump-detector.sh +156 -0
  686. package/examples/version-regression-warner.sh +144 -0
  687. package/examples/vue-lint-on-edit.sh +1 -0
  688. package/examples/warn-cron-cost-trap.sh +173 -0
  689. package/examples/webfetch-runaway-guard.sh +89 -0
  690. package/examples/wellness-break-reminder.sh +118 -0
  691. package/examples/windows-destructive-command-guard.sh +177 -0
  692. package/examples/windows-path-guard.sh +12 -0
  693. package/examples/windows-python-stub-detector.sh +63 -0
  694. package/examples/work-hours-guard.sh +12 -0
  695. package/examples/working-directory-fence.sh +12 -0
  696. package/examples/workspace-lease-guard.sh +205 -0
  697. package/examples/worktree-create-log.sh +1 -0
  698. package/examples/worktree-delete-guard.sh +12 -0
  699. package/examples/worktree-edit-boundary-guard.sh +127 -0
  700. package/examples/worktree-escape-write-guard.sh +114 -0
  701. package/examples/worktree-hook-linker.sh +0 -0
  702. package/examples/worktree-hooks-path-fix.sh +111 -0
  703. package/examples/worktree-parent-write-guard.sh +43 -0
  704. package/examples/worktree-project-unify.sh +2 -1
  705. package/examples/worktree-remove-uncommitted-guard.sh +13 -0
  706. package/examples/worktree-unmerged-guard.sh +7 -1
  707. package/examples/write-byte-integrity-verifier.sh +190 -0
  708. package/examples/write-empty-content-guard.sh +67 -0
  709. package/examples/write-nul-corruption-detector.sh +61 -0
  710. package/examples/write-overwrite-confirm.sh +160 -14
  711. package/examples/write-secret-guard.sh +27 -5
  712. package/examples/write-shrink-guard.sh +12 -0
  713. package/examples/write-test-ratio.sh +0 -0
  714. package/examples/wsl-host-disk-space-guard.sh +97 -0
  715. package/examples/xml-format-leak-detector.sh +266 -0
  716. package/examples/yaml-syntax-check.sh +12 -0
  717. package/hooks/hooks.json +6 -6
  718. package/index.mjs +1699 -183
  719. package/mission.md +2 -0
  720. package/package.json +4 -4
  721. package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
  722. package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
  723. package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
  724. package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
  725. package/scripts/agents-md-sync-setup.sh +156 -0
  726. package/scripts/autonomy-blocked-summary.sh +148 -0
  727. package/scripts/build-search-index.py +43 -0
  728. package/scripts/build-sitemap.py +119 -0
  729. package/scripts/cc-doctor.sh +192 -0
  730. package/scripts/check-hook-event-names.py +127 -0
  731. package/scripts/check-misfire-instrument.sh +64 -0
  732. package/scripts/claim-verify-audit.sh +467 -0
  733. package/scripts/cowork-claudemd-helper.sh +136 -0
  734. package/scripts/june-15-deprecated-model-scan.sh +111 -0
  735. package/scripts/measure-heredoc-shapes.sh +67 -0
  736. package/scripts/measure-literal-match-misfire.sh +110 -0
  737. package/scripts/probe-scope-guard-branches.sh +48 -0
  738. package/scripts/probe-skip-line-both-ways.sh +65 -0
  739. package/scripts/receipts-aggregate.py +199 -0
  740. package/scripts/session-forensic-audit.py +360 -0
  741. package/scripts.json +9 -9
  742. package/scripts.json.bak-2026-07-27-find +13 -0
  743. package/skills/safety-setup/SKILL.md +5 -5
  744. package/tests/approve-side-remaining-two.test.sh +129 -0
  745. package/tests/approver-list-granularity.test.sh +145 -0
  746. package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
  747. package/tests/audit-ci-gate.test.sh +87 -0
  748. package/tests/audit-cross-layer-claudemd.test.sh +170 -0
  749. package/tests/audit-fail-open-parse.test.sh +100 -0
  750. package/tests/auto-approve-compound-tail.test.sh +194 -0
  751. package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
  752. package/tests/auto-mode-quoted-targets.test.sh +127 -0
  753. package/tests/auto-mode-unquoted-targets.test.sh +112 -0
  754. package/tests/bash-secret-output-detector-detects.test.sh +102 -0
  755. package/tests/blindspots-cross-layer.test.sh +177 -0
  756. package/tests/block-database-wipe.test.sh +64 -0
  757. package/tests/bundled-short-flags-bypass.test.sh +85 -0
  758. package/tests/cd-git-allow-compound-tail.test.sh +67 -0
  759. package/tests/chown-guard-filesystem-root.test.sh +64 -0
  760. package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
  761. package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
  762. package/tests/core-scripts-parser-fallback.test.sh +140 -0
  763. package/tests/destructive-guard-bare-glob.test.sh +74 -0
  764. package/tests/destructive-guard-every-operand.test.sh +100 -0
  765. package/tests/destructive-guard-find-deletion.test.sh +114 -0
  766. package/tests/destructive-guard-flag-order.test.sh +106 -0
  767. package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
  768. package/tests/destructive-guard-quoted-target.test.sh +89 -0
  769. package/tests/destructive-guard-separators.test.sh +105 -0
  770. package/tests/destructive-guard-variable-target.test.sh +98 -0
  771. package/tests/destructive-guard-wrapped-command.test.sh +91 -0
  772. package/tests/doctor-hook-disabling-env.test.sh +92 -0
  773. package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
  774. package/tests/example-guards-wrapped-command.test.sh +169 -0
  775. package/tests/file-edit-backup.test.sh +93 -0
  776. package/tests/git-filter-repo-guard.test.sh +60 -0
  777. package/tests/git-global-options-bypass.test.sh +141 -0
  778. package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
  779. package/tests/git-maintenance-guard.test.sh +83 -0
  780. package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
  781. package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
  782. package/tests/git-submodule-guard.test.sh +50 -0
  783. package/tests/grep-pcre-portability.test.sh +155 -0
  784. package/tests/hook-registration-matches-input.test.sh +73 -0
  785. package/tests/hook-trigger-matches-envelope.test.sh +178 -0
  786. package/tests/install-does-not-claim-protection.test.sh +110 -0
  787. package/tests/install-example-standalone-tools.test.sh +139 -0
  788. package/tests/line-continuation-bypass.test.sh +114 -0
  789. package/tests/mcp-config-poisoning-audit.test.sh +106 -0
  790. package/tests/nested-background-agent-guard.test.sh +58 -0
  791. package/tests/no-unqualified-safety-claims.test.sh +114 -0
  792. package/tests/option-eating-grep-patterns.test.sh +130 -0
  793. package/tests/outdated-core-guards.test.sh +134 -0
  794. package/tests/outdated-report.test.sh +155 -0
  795. package/tests/output-secret-mask-warns.test.sh +73 -0
  796. package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
  797. package/tests/plugins-word-order.test.sh +126 -0
  798. package/tests/powershell-remove-item-guard.test.sh +85 -0
  799. package/tests/project-dir-naming.test.sh +103 -0
  800. package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
  801. package/tests/reroute-after-block-guard.test.sh +104 -0
  802. package/tests/secret-guard-documented-promises.test.sh +97 -0
  803. package/tests/session-plugin-pin-watch.test.sh +45 -0
  804. package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
  805. package/tests/shield-no-silent-adoption.test.py +110 -0
  806. package/tests/shield-no-silent-adoption.test.sh +46 -0
  807. package/tests/stop-transcript-write-health.test.sh +46 -0
  808. package/tests/system-dir-guard-root-erased.test.sh +66 -0
  809. package/tests/test-account-billing-log.sh +100 -0
  810. package/tests/test-account-routing-preflight.sh +77 -0
  811. package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
  812. package/tests/test-agent-view-quota-warn.sh +184 -0
  813. package/tests/test-agents-md-edit-drift-warner.sh +176 -0
  814. package/tests/test-agents-md-loader.sh +204 -0
  815. package/tests/test-agents-md-sync-checker.sh +125 -0
  816. package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
  817. package/tests/test-allowlist.sh +60 -0
  818. package/tests/test-always-allow-pattern-suggester.sh +147 -0
  819. package/tests/test-anthropic-base-url-guard.sh +88 -0
  820. package/tests/test-articulated-scope-capture.sh +139 -0
  821. package/tests/test-attachment-traversal-guard.sh +168 -0
  822. package/tests/test-aup-block-pattern-logger.sh +315 -0
  823. package/tests/test-aup-false-positive-helper.sh +188 -0
  824. package/tests/test-aup-large-tool-output-warner.sh +370 -0
  825. package/tests/test-aup-retry-loop-guard.sh +341 -0
  826. package/tests/test-auth-expiry-reminder.sh +303 -0
  827. package/tests/test-auth-macos-sleep-detector.sh +254 -0
  828. package/tests/test-auth-path-detector.sh +232 -0
  829. package/tests/test-auth-status-checker.sh +233 -0
  830. package/tests/test-authorized-reconfirmation-detector.sh +280 -0
  831. package/tests/test-background-cost-launch-guard.sh +62 -0
  832. package/tests/test-bash-allowlist-secondary-check.sh +143 -0
  833. package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
  834. package/tests/test-bash-project-fence.sh +127 -0
  835. package/tests/test-bg-permission-prompt-warner.sh +221 -0
  836. package/tests/test-binary-read-detector.sh +173 -0
  837. package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
  838. package/tests/test-bulk-delete-target-resolution.sh +49 -0
  839. package/tests/test-bypass-mode-effective-verifier.sh +179 -0
  840. package/tests/test-cache-creation-drift-detector.sh +244 -0
  841. package/tests/test-cache-residue-detector.sh +429 -0
  842. package/tests/test-cache-tier-logger.sh +59 -0
  843. package/tests/test-cache-ttl-eviction-detector.sh +282 -0
  844. package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
  845. package/tests/test-claim-verify-detector.sh +222 -0
  846. package/tests/test-claim-vs-caveat-checker.sh +134 -0
  847. package/tests/test-claude-code-version-pin-advisor.sh +353 -0
  848. package/tests/test-claude-md-reinjector.sh +173 -0
  849. package/tests/test-claude-md-size-monitor.sh +107 -0
  850. package/tests/test-claude-update-budget-guard.sh +132 -0
  851. package/tests/test-claude-update-smart.sh +91 -0
  852. package/tests/test-claudemd-tool-prohibition.sh +239 -0
  853. package/tests/test-cli-config-pinning-detector.sh +233 -0
  854. package/tests/test-cliff-countdown-advisor.sh +138 -0
  855. package/tests/test-closure-word-verify-gate.sh +158 -0
  856. package/tests/test-commit-all-scope-guard.sh +73 -0
  857. package/tests/test-commitment-carry-forward-arrest.sh +250 -0
  858. package/tests/test-compact-dispatch-watchdog.sh +147 -0
  859. package/tests/test-completion-claim-without-verification-detector.sh +326 -0
  860. package/tests/test-compound-bash-permission-resolver.sh +264 -0
  861. package/tests/test-compound-command-deny-enforcer.sh +67 -0
  862. package/tests/test-context-length-budget.sh +68 -0
  863. package/tests/test-context-usage-drift-alert.sh +52 -22
  864. package/tests/test-cost-incident-self-audit.sh +94 -0
  865. package/tests/test-cowork-claude-md-load-checker.sh +257 -0
  866. package/tests/test-cowork-claudemd-helper.sh +141 -0
  867. package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
  868. package/tests/test-cowork-hook-absence-warner.sh +230 -0
  869. package/tests/test-cowork-model-picker-advisor.sh +317 -0
  870. package/tests/test-credential-exfil-guard.sh +62 -0
  871. package/tests/test-cron-create-receipt.sh +165 -0
  872. package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
  873. package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
  874. package/tests/test-daily-cost-guard.sh +131 -0
  875. package/tests/test-deny-rule-integrity-verifier.sh +288 -0
  876. package/tests/test-deployment-readback-gate.sh +92 -0
  877. package/tests/test-deployment-readback-gh-adapter.sh +163 -0
  878. package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
  879. package/tests/test-dispatch-allowlist-preflight.sh +385 -0
  880. package/tests/test-dispatch-liveness-watchdog.sh +319 -0
  881. package/tests/test-dispatch-receipt.sh +314 -0
  882. package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
  883. package/tests/test-echo-probe-spam-detector.sh +143 -0
  884. package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
  885. package/tests/test-ephemeral-container-detector.sh +251 -0
  886. package/tests/test-evidence-claim-gate.sh +291 -0
  887. package/tests/test-extended-thinking-loop-guard.sh +289 -0
  888. package/tests/test-extended-thinking-resume-warning.sh +240 -0
  889. package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
  890. package/tests/test-fabricated-command-detector.sh +296 -0
  891. package/tests/test-false-disk-full-guard.sh +36 -0
  892. package/tests/test-feature-deprecation-detector.sh +117 -0
  893. package/tests/test-forbidden-response-phrase-detector.sh +246 -0
  894. package/tests/test-git-operations-require-approval.sh +53 -0
  895. package/tests/test-git-push-blast-radius-guard.sh +115 -0
  896. package/tests/test-goal-iteration-limit-warner.sh +128 -0
  897. package/tests/test-growthbook-flag-monitor.sh +428 -0
  898. package/tests/test-halt-signal-detector.sh +120 -0
  899. package/tests/test-hook-self-disable-detector.sh +232 -0
  900. package/tests/test-iteration-quality-degradation-detector.sh +244 -0
  901. package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
  902. package/tests/test-marketplace-plugins.sh +193 -0
  903. package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
  904. package/tests/test-mcp-orphan-leak-warner.sh +71 -0
  905. package/tests/test-mcp-permissions-ask-warner.sh +207 -0
  906. package/tests/test-mcp-routine-approval-detector.sh +229 -0
  907. package/tests/test-mcp-startup-bloat-detector.sh +141 -0
  908. package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
  909. package/tests/test-memory-chain-audit.sh +59 -0
  910. package/tests/test-memory-orphan-detector.sh +227 -0
  911. package/tests/test-model-swap-suggester.sh +368 -0
  912. package/tests/test-model-version-lock.sh +83 -0
  913. package/tests/test-multi-file-plan-routing-gate.sh +277 -0
  914. package/tests/test-multi-window-auth-drift-detector.sh +262 -0
  915. package/tests/test-nested-spawn-inflight-guard.sh +281 -0
  916. package/tests/test-no-force-flag.sh +49 -0
  917. package/tests/test-non-english-quality-warner.sh +229 -0
  918. package/tests/test-oauth-refresh-monitor.sh +311 -0
  919. package/tests/test-opus-degradation-tracker.sh +274 -0
  920. package/tests/test-opus48-routine-task-warning.sh +201 -0
  921. package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
  922. package/tests/test-output-token-spike-detector.sh +315 -0
  923. package/tests/test-parallel-batch-size-limiter.sh +228 -0
  924. package/tests/test-parallel-cascade-detector.sh +191 -0
  925. package/tests/test-partial-view-claim-arrest.sh +272 -0
  926. package/tests/test-per-prompt-token-cap.sh +136 -0
  927. package/tests/test-persisted-1m-model-advisor.sh +71 -0
  928. package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
  929. package/tests/test-post-edit-disk-verify.sh +294 -0
  930. package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
  931. package/tests/test-pre-execution-claim-detector.sh +366 -0
  932. package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
  933. package/tests/test-proxy-capture-suggester.sh +214 -0
  934. package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
  935. package/tests/test-quota-anomaly-detector.sh +321 -0
  936. package/tests/test-quota-reset-audit.sh +81 -0
  937. package/tests/test-read-loop-detector.sh +137 -0
  938. package/tests/test-read-once-guard.sh +85 -0
  939. package/tests/test-receipts-aggregate.sh +143 -0
  940. package/tests/test-redirect-fragment-warner.sh +130 -0
  941. package/tests/test-redundant-read-blocker.sh +155 -0
  942. package/tests/test-refusal-arrest-gate.sh +303 -0
  943. package/tests/test-remote-control-billing-classifier.sh +125 -0
  944. package/tests/test-resume-drift-watcher.sh +65 -0
  945. package/tests/test-rg-replace-flag-detector.sh +175 -0
  946. package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
  947. package/tests/test-rm-safety-net.sh +115 -0
  948. package/tests/test-route-handler-emptiness-gate.sh +300 -0
  949. package/tests/test-runtime-binary-change-detector.sh +196 -0
  950. package/tests/test-same-command-repeat-detector.sh +165 -0
  951. package/tests/test-same-correction-arrest.sh +165 -0
  952. package/tests/test-scope-expansion-receipt.sh +207 -0
  953. package/tests/test-server-side-prompt-injection-detector.sh +181 -0
  954. package/tests/test-session-persistence-verifier.sh +128 -0
  955. package/tests/test-session-rate-monitor.sh +284 -0
  956. package/tests/test-session-start-quota-status.sh +210 -0
  957. package/tests/test-session-start-safety-check.sh +138 -0
  958. package/tests/test-settings-hooks-key-restorer.sh +257 -0
  959. package/tests/test-settings-json-health-check.sh +70 -0
  960. package/tests/test-settings-regression-tester.sh +197 -0
  961. package/tests/test-skill-cumulative-size-detector.sh +198 -0
  962. package/tests/test-skill-description-drop-detector.sh +236 -0
  963. package/tests/test-skill-truncation-detector.sh +263 -0
  964. package/tests/test-skills-context-recorder.sh +329 -0
  965. package/tests/test-skills-load-verifier.sh +184 -0
  966. package/tests/test-skills-settings-validator.sh +242 -0
  967. package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
  968. package/tests/test-spurious-malformed-notice-detector.sh +290 -0
  969. package/tests/test-sql-bulk-delete-warn.sh +123 -0
  970. package/tests/test-ssh-key-protect.sh +81 -0
  971. package/tests/test-stale-temp-settings-detector.sh +161 -0
  972. package/tests/test-standing-rule-session-surfacer.sh +215 -0
  973. package/tests/test-starter-hooks-manifest.sh +96 -0
  974. package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
  975. package/tests/test-strict-allowlist.sh +72 -0
  976. package/tests/test-subagent-boundary-precheck.sh +137 -0
  977. package/tests/test-subagent-closure-verify-gate.sh +193 -0
  978. package/tests/test-subagent-destructive-git-guard.sh +86 -0
  979. package/tests/test-subagent-identity-leak-guard.sh +62 -0
  980. package/tests/test-subagent-identity-reassertion.sh +61 -0
  981. package/tests/test-subagent-inheritance-tester.sh +319 -0
  982. package/tests/test-subagent-permission-mode-guard.sh +61 -0
  983. package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
  984. package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
  985. package/tests/test-subagent-tool-call-limiter.sh +97 -0
  986. package/tests/test-subscription-api-billing-warner.sh +138 -0
  987. package/tests/test-subscription-bypass-detector.sh +255 -0
  988. package/tests/test-temporal-suggestion-detector.sh +183 -0
  989. package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
  990. package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
  991. package/tests/test-tokenizer-ratio-alert.sh +93 -0
  992. package/tests/test-tool-result-correlation-checker.sh +264 -0
  993. package/tests/test-tool-result-size-guard.sh +121 -0
  994. package/tests/test-transcript-contamination-detector.sh +264 -0
  995. package/tests/test-trigger-header-parsing.sh +151 -0
  996. package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
  997. package/tests/test-userprompt-submit-receipt.sh +181 -0
  998. package/tests/test-verify-after-publish-reminder.sh +184 -0
  999. package/tests/test-version-bump-detector.sh +212 -0
  1000. package/tests/test-version-regression-warner.sh +165 -0
  1001. package/tests/test-warn-cron-cost-trap.sh +82 -0
  1002. package/tests/test-webfetch-runaway-guard.sh +77 -0
  1003. package/tests/test-wellness-break-reminder.sh +138 -0
  1004. package/tests/test-windows-destructive-command-guard.sh +169 -0
  1005. package/tests/test-windows-python-stub-detector.sh +146 -0
  1006. package/tests/test-worktree-edit-boundary-guard.sh +219 -0
  1007. package/tests/test-write-byte-integrity-verifier.sh +192 -0
  1008. package/tests/test-xml-format-leak-detector.sh +299 -0
  1009. package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
  1010. package/tests/workspace-lease-guard.test.sh +144 -0
  1011. package/tests/worktree-escape-write-guard.test.sh +68 -0
  1012. package/tests/worktree-hooks-path-fix.test.sh +181 -0
  1013. package/tests/worktree-parent-write-guard.test.sh +51 -0
  1014. package/tests/write-empty-content-guard.test.sh +39 -0
  1015. package/tests/write-nul-corruption-detector.test.sh +29 -0
  1016. package/tests/write-overwrite-unread-content.test.sh +178 -0
  1017. package/tests/wsl-host-disk-space-guard.test.sh +55 -0
@@ -0,0 +1,160 @@
1
+ #!/bin/bash
2
+ # Tests for dotenv-anthropic-key-billing-guard.sh
3
+
4
+ # 絶対パスにする。テスト20はcd後にhookを実行するため、相対パスだと解決できずfalse negativeになる
5
+ HOOK="$(cd "$(dirname "$0")/.." && pwd)/examples/dotenv-anthropic-key-billing-guard.sh"
6
+ PASS=0 FAIL=0
7
+
8
+ # Use a unique tmpdir per test run
9
+ TMPROOT="$(mktemp -d -t cc-dotenv-ak-test.XXXXXX)"
10
+ trap 'rm -rf "$TMPROOT"' EXIT
11
+
12
+ run_test() {
13
+ local desc="$1" expected_exit="$2" envfile="$3" content="$4" extra_env="$5"
14
+ local dir="$TMPROOT/$RANDOM-$RANDOM"
15
+ mkdir -p "$dir"
16
+ if [ -n "$envfile" ]; then
17
+ printf '%s' "$content" > "$dir/$envfile"
18
+ fi
19
+ local logfile="$dir/log"
20
+ local actual_exit
21
+ if [ -n "$extra_env" ]; then
22
+ env CLAUDE_PROJECT_DIR="$dir" CC_DOTENV_AK_LOG="$logfile" $extra_env bash "$HOOK" >/dev/null 2>/dev/null
23
+ else
24
+ env CLAUDE_PROJECT_DIR="$dir" CC_DOTENV_AK_LOG="$logfile" bash "$HOOK" >/dev/null 2>/dev/null
25
+ fi
26
+ actual_exit=$?
27
+ if [ "$actual_exit" -eq "$expected_exit" ]; then
28
+ echo " PASS: $desc"
29
+ PASS=$((PASS+1))
30
+ else
31
+ echo " FAIL: $desc (expected exit $expected_exit, got $actual_exit)"
32
+ FAIL=$((FAIL+1))
33
+ fi
34
+ }
35
+
36
+ echo "Testing dotenv-anthropic-key-billing-guard.sh"
37
+ echo "=============================================="
38
+
39
+ # 1. No .env file at all — should pass silently
40
+ run_test "no .env files passes silently" 0 "" ""
41
+
42
+ # 2. .env without ANTHROPIC_API_KEY — pass
43
+ run_test ".env without ANTHROPIC_API_KEY passes" 0 ".env" "FOO=bar
44
+ DATABASE_URL=postgres://x"
45
+
46
+ # 3. .env with ANTHROPIC_API_KEY assigned a value — warn (exit 0 default)
47
+ run_test ".env with key (default warn) exits 0" 0 ".env" "ANTHROPIC_API_KEY=sk-ant-real-key"
48
+
49
+ # 4. .env with ANTHROPIC_API_KEY in block mode — exit 2
50
+ run_test ".env with key in block mode exits 2" 2 ".env" "ANTHROPIC_API_KEY=sk-ant-real-key" "CC_DOTENV_AK_ACTION=block"
51
+
52
+ # 5. .env with key inside quotes
53
+ run_test '.env with quoted key triggers warn' 0 ".env" 'ANTHROPIC_API_KEY="sk-ant-quoted"'
54
+
55
+ # 6. .env with key inside single-quotes
56
+ run_test ".env with single-quoted key triggers warn" 0 ".env" "ANTHROPIC_API_KEY='sk-ant-singlequoted'"
57
+
58
+ # 7. .env with export prefix
59
+ run_test ".env with export prefix triggers warn" 0 ".env" "export ANTHROPIC_API_KEY=sk-ant-exported"
60
+
61
+ # 8. .env with leading whitespace
62
+ run_test ".env with leading whitespace triggers warn" 0 ".env" " ANTHROPIC_API_KEY=sk-ant-indented"
63
+
64
+ # 9. .env with commented-out key — should NOT trigger
65
+ run_test ".env with commented key passes silently" 0 ".env" "# ANTHROPIC_API_KEY=sk-ant-commented
66
+ FOO=bar"
67
+
68
+ # 10. .env with empty value (intentional override) — should NOT trigger
69
+ run_test ".env with empty key value passes" 0 ".env" "ANTHROPIC_API_KEY="
70
+
71
+ # 11. .env with empty quoted value — should NOT trigger
72
+ run_test '.env with empty quoted value passes' 0 ".env" 'ANTHROPIC_API_KEY=""'
73
+
74
+ # 12. .env.local with key — triggers
75
+ run_test ".env.local with key triggers warn" 0 ".env.local" "ANTHROPIC_API_KEY=sk-ant-local"
76
+
77
+ # 13. .env.production with key — triggers
78
+ run_test ".env.production with key triggers warn" 0 ".env.production" "ANTHROPIC_API_KEY=sk-ant-prod"
79
+
80
+ # 14. .env.development with key — triggers
81
+ run_test ".env.development with key triggers warn" 0 ".env.development" "ANTHROPIC_API_KEY=sk-ant-dev"
82
+
83
+ # 15. Unsupported file (.env.staging) ignored by default
84
+ run_test ".env.staging ignored by default" 0 ".env.staging" "ANTHROPIC_API_KEY=sk-ant-staging"
85
+
86
+ # 16. Custom CC_DOTENV_AK_FILES picks up .env.staging
87
+ run_test "custom file list picks up .env.staging" 0 ".env.staging" "ANTHROPIC_API_KEY=sk-ant-staging" "CC_DOTENV_AK_FILES=.env.staging"
88
+
89
+ # 17. Warn message goes to stderr
90
+ DIR="$TMPROOT/output-test"
91
+ mkdir -p "$DIR"
92
+ echo "ANTHROPIC_API_KEY=sk-ant-real" > "$DIR/.env"
93
+ OUTPUT=$(env CLAUDE_PROJECT_DIR="$DIR" bash "$HOOK" 2>&1 >/dev/null)
94
+ if echo "$OUTPUT" | grep -q "ANTHROPIC_API_KEY detected"; then
95
+ echo " PASS: warn message printed to stderr"
96
+ PASS=$((PASS+1))
97
+ else
98
+ echo " FAIL: warn message missing from stderr"
99
+ FAIL=$((FAIL+1))
100
+ fi
101
+
102
+ # 18. Stdout stays empty (so SessionStart payload is not corrupted)
103
+ DIR="$TMPROOT/stdout-test"
104
+ mkdir -p "$DIR"
105
+ echo "ANTHROPIC_API_KEY=sk-ant-real" > "$DIR/.env"
106
+ STDOUT=$(env CLAUDE_PROJECT_DIR="$DIR" bash "$HOOK" 2>/dev/null)
107
+ if [ -z "$STDOUT" ]; then
108
+ echo " PASS: stdout is empty"
109
+ PASS=$((PASS+1))
110
+ else
111
+ echo " FAIL: stdout is non-empty: $STDOUT"
112
+ FAIL=$((FAIL+1))
113
+ fi
114
+
115
+ # 19. Log file is created and contains the path
116
+ DIR="$TMPROOT/log-test"
117
+ mkdir -p "$DIR"
118
+ echo "ANTHROPIC_API_KEY=sk-ant-real" > "$DIR/.env"
119
+ LOG="$TMPROOT/test.log"
120
+ env CLAUDE_PROJECT_DIR="$DIR" CC_DOTENV_AK_LOG="$LOG" bash "$HOOK" >/dev/null 2>/dev/null
121
+ if [ -f "$LOG" ] && grep -q "$DIR/.env" "$LOG"; then
122
+ echo " PASS: log file written"
123
+ PASS=$((PASS+1))
124
+ else
125
+ echo " FAIL: log file missing or empty"
126
+ FAIL=$((FAIL+1))
127
+ fi
128
+
129
+ # 20. Falls back to PWD when CLAUDE_PROJECT_DIR unset
130
+ DIR="$TMPROOT/pwd-test"
131
+ mkdir -p "$DIR"
132
+ echo "ANTHROPIC_API_KEY=sk-ant-real" > "$DIR/.env"
133
+ LOG="$DIR/log"
134
+ ( cd "$DIR" && env -u CLAUDE_PROJECT_DIR CC_DOTENV_AK_LOG="$LOG" bash "$HOOK" >/dev/null 2>/dev/null )
135
+ if [ -f "$LOG" ] && grep -q "$DIR/.env" "$LOG"; then
136
+ echo " PASS: PWD fallback works when CLAUDE_PROJECT_DIR unset"
137
+ PASS=$((PASS+1))
138
+ else
139
+ echo " FAIL: PWD fallback did not detect"
140
+ FAIL=$((FAIL+1))
141
+ fi
142
+
143
+ # 21. Multiple .env files all detected (log has both lines)
144
+ DIR="$TMPROOT/multi-test"
145
+ mkdir -p "$DIR"
146
+ echo "ANTHROPIC_API_KEY=sk-ant-1" > "$DIR/.env"
147
+ echo "ANTHROPIC_API_KEY=sk-ant-2" > "$DIR/.env.local"
148
+ LOG="$DIR/log"
149
+ env CLAUDE_PROJECT_DIR="$DIR" CC_DOTENV_AK_LOG="$LOG" bash "$HOOK" >/dev/null 2>/dev/null
150
+ if [ -f "$LOG" ] && [ "$(grep -c 'ANTHROPIC_API_KEY' "$LOG")" -eq 2 ]; then
151
+ echo " PASS: multiple .env files all logged"
152
+ PASS=$((PASS+1))
153
+ else
154
+ echo " FAIL: multiple .env files not all logged (got $(wc -l < "$LOG" 2>/dev/null) lines)"
155
+ FAIL=$((FAIL+1))
156
+ fi
157
+
158
+ echo "=============================================="
159
+ echo "Result: PASS=$PASS FAIL=$FAIL"
160
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,143 @@
1
+ #!/bin/bash
2
+ # Tests for echo-probe-spam-detector.sh
3
+ HOOK="examples/echo-probe-spam-detector.sh"
4
+ PASS=0 FAIL=0
5
+ TMPDIR=$(mktemp -d)
6
+ trap "rm -rf $TMPDIR" EXIT
7
+
8
+ assert_contains() { if echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected '$3', got: $2)"; fi; }
9
+ assert_not_contains() { if ! echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (unexpected '$3', got: $2)"; fi; }
10
+ assert_exit() { if [ "$2" = "$3" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected exit $3, got $2)"; fi; }
11
+
12
+ HOOK_ABS="$PWD/$HOOK"
13
+
14
+ # Isolate state per test via unique TMPDIR + session ID
15
+ run_hook() {
16
+ local sid="$1"
17
+ local cmd="$2"
18
+ local extra_env="${3:-}"
19
+ local input='{"tool_input": {"command": '"$(printf '%s' "$cmd" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')"'}}'
20
+ # shellcheck disable=SC2086
21
+ env TMPDIR="$TMPDIR" CLAUDE_SESSION_ID="$sid" $extra_env bash "$HOOK_ABS" 2>&1 <<< "$input"
22
+ }
23
+ run_hook_with_rc() {
24
+ local sid="$1"
25
+ local cmd="$2"
26
+ local extra_env="${3:-}"
27
+ local input='{"tool_input": {"command": '"$(printf '%s' "$cmd" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')"'}}'
28
+ env TMPDIR="$TMPDIR" CLAUDE_SESSION_ID="$sid" $extra_env bash "$HOOK_ABS" 2>&1 <<< "$input"
29
+ return $?
30
+ }
31
+
32
+ # Test 1: Non-probe command exits 0 silently (no counter increment)
33
+ OUT=$(run_hook "s1" "ls -la"); RC=$?
34
+ assert_not_contains "non-probe no notice" "$OUT" "NOTICE"
35
+ assert_not_contains "non-probe no block" "$OUT" "BLOCKED"
36
+ assert_exit "non-probe exit 0" "$RC" "0"
37
+
38
+ # Test 2: First echo s1 → NOTICE, exit 0
39
+ OUT=$(run_hook "s2" "echo s1"); RC=$?
40
+ assert_contains "echo s1 notice" "$OUT" "NOTICE"
41
+ assert_contains "echo s1 mentions 1/3" "$OUT" "1/3"
42
+ assert_exit "echo s1 first exit 0" "$RC" "0"
43
+
44
+ # Test 3: Second echo s2 → NOTICE 2/3, exit 0
45
+ OUT=$(run_hook "s2" "echo s2"); RC=$?
46
+ assert_contains "echo s2 notice 2" "$OUT" "2/3"
47
+ assert_exit "echo s2 second exit 0" "$RC" "0"
48
+
49
+ # Test 4: Third echo s3 → BLOCKED, exit 2
50
+ OUT=$(run_hook "s2" "echo s3"); RC=$?
51
+ assert_contains "echo s3 blocked" "$OUT" "BLOCKED"
52
+ assert_exit "echo s3 third exit 2" "$RC" "2"
53
+
54
+ # Test 5: Non-probe in middle resets counter
55
+ OUT=$(run_hook "s3" "echo s1"); _=$? # 1
56
+ OUT=$(run_hook "s3" "ls"); _=$? # reset
57
+ OUT=$(run_hook "s3" "echo s1"); RC=$? # back to 1
58
+ assert_contains "after reset count 1" "$OUT" "1/3"
59
+ assert_exit "after reset exit 0" "$RC" "0"
60
+
61
+ # Test 6: CC_ECHO_PROBE_DISABLE=1 → never warn or block
62
+ OUT=$(run_hook "s4" "echo s1" "CC_ECHO_PROBE_DISABLE=1"); RC=$?
63
+ assert_not_contains "DISABLE no notice" "$OUT" "NOTICE"
64
+ assert_exit "DISABLE exit 0" "$RC" "0"
65
+ OUT=$(run_hook "s4" "echo s2" "CC_ECHO_PROBE_DISABLE=1"); _=$?
66
+ OUT=$(run_hook "s4" "echo s3" "CC_ECHO_PROBE_DISABLE=1"); RC=$?
67
+ assert_not_contains "DISABLE no block" "$OUT" "BLOCKED"
68
+ assert_exit "DISABLE 3rd exit 0" "$RC" "0"
69
+
70
+ # Test 7: CC_ECHO_PROBE_QUIET=1 → silent but still blocks
71
+ OUT=$(run_hook "s5" "echo s1" "CC_ECHO_PROBE_QUIET=1"); RC=$?
72
+ assert_not_contains "QUIET no notice 1" "$OUT" "NOTICE"
73
+ assert_exit "QUIET 1st exit 0" "$RC" "0"
74
+ OUT=$(run_hook "s5" "echo s2" "CC_ECHO_PROBE_QUIET=1"); _=$?
75
+ OUT=$(run_hook "s5" "echo s3" "CC_ECHO_PROBE_QUIET=1"); RC=$?
76
+ assert_not_contains "QUIET no block message" "$OUT" "BLOCKED"
77
+ assert_exit "QUIET 3rd exit 2" "$RC" "2"
78
+
79
+ # Test 8: CC_ECHO_PROBE_THRESHOLD=2 → block at 2
80
+ OUT=$(run_hook "s6" "echo s1" "CC_ECHO_PROBE_THRESHOLD=2"); RC=$?
81
+ assert_contains "T=2 first 1/2" "$OUT" "1/2"
82
+ assert_exit "T=2 first exit 0" "$RC" "0"
83
+ OUT=$(run_hook "s6" "echo s2" "CC_ECHO_PROBE_THRESHOLD=2"); RC=$?
84
+ assert_contains "T=2 second blocks" "$OUT" "BLOCKED"
85
+ assert_exit "T=2 second exit 2" "$RC" "2"
86
+
87
+ # Test 9: Short echo args (1-3 chars) detected
88
+ OUT=$(run_hook "s7" "echo x"); RC=$?
89
+ assert_contains "short arg detected" "$OUT" "NOTICE"
90
+ assert_exit "short arg exit 0" "$RC" "0"
91
+
92
+ # Test 10: Real echo with longer message NOT detected
93
+ OUT=$(run_hook "s8" 'echo "Build successful"'); RC=$?
94
+ assert_not_contains "real echo no notice" "$OUT" "NOTICE"
95
+ assert_exit "real echo exit 0" "$RC" "0"
96
+
97
+ # Test 11: sleep N; echo X detected
98
+ OUT=$(run_hook "s9" "sleep 1; echo flush"); RC=$?
99
+ assert_contains "sleep+echo detected" "$OUT" "NOTICE"
100
+ assert_exit "sleep+echo exit 0" "$RC" "0"
101
+
102
+ # Test 12: # RESET ECHO PROBE marker clears state
103
+ OUT=$(run_hook "s10" "echo s1"); _=$? # 1
104
+ OUT=$(run_hook "s10" "echo s2"); _=$? # 2
105
+ OUT=$(run_hook "s10" "ls # RESET ECHO PROBE"); RC=$?
106
+ assert_exit "RESET marker exit 0" "$RC" "0"
107
+ OUT=$(run_hook "s10" "echo s1"); RC=$?
108
+ assert_contains "after RESET count 1" "$OUT" "1/3"
109
+
110
+ # Test 13: Empty input → exit 0
111
+ OUT=$(env TMPDIR="$TMPDIR" CLAUDE_SESSION_ID="s11" bash "$HOOK_ABS" 2>&1 < /dev/null); RC=$?
112
+ assert_exit "empty input exit 0" "$RC" "0"
113
+
114
+ # Test 14: Missing tool_input.command → exit 0
115
+ OUT=$(env TMPDIR="$TMPDIR" CLAUDE_SESSION_ID="s12" bash "$HOOK_ABS" 2>&1 <<< '{}'); RC=$?
116
+ assert_exit "missing command exit 0" "$RC" "0"
117
+
118
+ # Test 15: Different session IDs have independent counters
119
+ OUT=$(run_hook "sess-A" "echo s1"); _=$?
120
+ OUT=$(run_hook "sess-A" "echo s2"); _=$?
121
+ OUT=$(run_hook "sess-B" "echo s1"); RC=$?
122
+ assert_contains "session B count 1" "$OUT" "1/3"
123
+
124
+ # Test 16: Block message includes anchor issue + Gist reference
125
+ run_hook "s13" "echo s1" > /dev/null
126
+ run_hook "s13" "echo s2" > /dev/null
127
+ OUT=$(run_hook "s13" "echo s3"); RC=$?
128
+ assert_contains "block mentions issue 63887" "$OUT" "63887"
129
+ assert_contains "block mentions Gist" "$OUT" "5881286479969d5bac0323511dc33ab2"
130
+
131
+ # Test 17: 4-char echo argument NOT detected (above threshold)
132
+ OUT=$(run_hook "s14" "echo abcd"); RC=$?
133
+ assert_not_contains "4-char echo not detected" "$OUT" "NOTICE"
134
+ assert_exit "4-char echo exit 0" "$RC" "0"
135
+
136
+ # Test 18: echo without arg NOT detected (non-probe shape)
137
+ OUT=$(run_hook "s15" "echo"); RC=$?
138
+ assert_not_contains "bare echo not detected" "$OUT" "NOTICE"
139
+ assert_exit "bare echo exit 0" "$RC" "0"
140
+
141
+ echo ""
142
+ echo "echo-probe-spam-detector tests: $PASS passed, $FAIL failed"
143
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,75 @@
1
+ #!/bin/bash
2
+ # Tests for edit-quote-ambiguity-guard.sh
3
+ # Absolute path: tests build scratch files under TMPDIR.
4
+ HOOK="$(cd "$(dirname "$0")/../examples" && pwd)/edit-quote-ambiguity-guard.sh"
5
+ PASS=0
6
+ FAIL=0
7
+
8
+ run_test() {
9
+ local desc="$1" result="$2"
10
+ if [ "$result" = "pass" ]; then
11
+ echo " PASS: $desc"; PASS=$((PASS + 1))
12
+ else
13
+ echo " FAIL: $desc"; FAIL=$((FAIL + 1))
14
+ fi
15
+ }
16
+
17
+ D=$(mktemp -d "${TMPDIR:-/tmp}/cc-quote-guard-test.XXXXXX")
18
+
19
+ # Scratch files. printf with \xe2\x80\x9c/\x9d = curly “ ”, \x9d/\x9c = reversed.
20
+ printf 'message1 = "hello"\nmessage2 = \xe2\x80\x9chello\xe2\x80\x9d\n' > "$D/mixed.py"
21
+ printf 'message1 = \xe2\x80\x9dhello\xe2\x80\x9c\nmessage2 = \xe2\x80\x9chello\xe2\x80\x9d\n' > "$D/subtle.py"
22
+ printf 'only = \xe2\x80\x9cgreeting\xe2\x80\x9d\n' > "$D/curly_only.py"
23
+ printf 'a = "x"\nb = "y"\n' > "$D/plain.py"
24
+ printf 'dup = "z"\ndup = "z"\n' > "$D/rawdup.py"
25
+
26
+ # Run hook with a JSON payload; print "exit|stderr_line_count".
27
+ run_in() {
28
+ local payload="$1" err rc
29
+ err=$(printf '%s' "$payload" | bash "$HOOK" 2>&1 1>/dev/null); rc=$?
30
+ echo "$rc|$(printf '%s' "$err" | grep -c .)"
31
+ }
32
+
33
+ echo "Testing edit-quote-ambiguity-guard.sh"
34
+ echo "====================================="
35
+
36
+ # 1. Subtle variant (raw 0, norm 2) → BLOCK (exit 2 with message).
37
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/subtle.py\",\"old_string\":\"\\\"hello\\\"\",\"new_string\":\"X\"}}")
38
+ [ "${R%%|*}" = "2" ] && [ "${R##*|}" -gt 0 ] && run_test "subtle two-curly variant → blocks" pass || run_test "subtle → blocks ($R)" fail
39
+
40
+ # 2. Mixed straight+curly (raw 1, norm 2) → BLOCK.
41
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/mixed.py\",\"old_string\":\"\\\"hello\\\"\",\"new_string\":\"X\"}}")
42
+ [ "${R%%|*}" = "2" ] && run_test "mixed exact-wins ambiguity → blocks" pass || run_test "mixed → blocks ($R)" fail
43
+
44
+ # 3. Curly-only unique (raw 0, norm 1) → allow (exit 0).
45
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/curly_only.py\",\"old_string\":\"\\\"greeting\\\"\",\"new_string\":\"X\"}}")
46
+ [ "${R%%|*}" = "0" ] && run_test "curly-only unique normalized match → allows" pass || run_test "curly-only → allows ($R)" fail
47
+
48
+ # 4. Plain unique (raw 1, norm 1) → allow.
49
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/plain.py\",\"old_string\":\"\\\"x\\\"\",\"new_string\":\"X\"}}")
50
+ [ "${R%%|*}" = "0" ] && run_test "plain unique match → allows" pass || run_test "plain → allows ($R)" fail
51
+
52
+ # 5. Raw duplicate (raw 2, norm 2) → silent: the tool already rejects this.
53
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/rawdup.py\",\"old_string\":\"\\\"z\\\"\",\"new_string\":\"X\"}}")
54
+ [ "${R%%|*}" = "0" ] && run_test "raw duplicate (tool handles) → stays silent" pass || run_test "rawdup → silent ($R)" fail
55
+
56
+ # 6. replace_all:true → allow (intentional all-variant change).
57
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/subtle.py\",\"old_string\":\"\\\"hello\\\"\",\"new_string\":\"X\",\"replace_all\":true}}")
58
+ [ "${R%%|*}" = "0" ] && run_test "replace_all:true → allows" pass || run_test "replace_all → allows ($R)" fail
59
+
60
+ # 7. Non-Edit input (no file_path) → allow.
61
+ R=$(run_in '{"tool_input":{"command":"ls"}}')
62
+ [ "${R%%|*}" = "0" ] && run_test "no file_path → allows" pass || run_test "no file_path → allows ($R)" fail
63
+
64
+ # 8. MultiEdit whose 2nd edit is the subtle variant → BLOCK.
65
+ R=$(run_in "{\"tool_input\":{\"file_path\":\"$D/subtle.py\",\"edits\":[{\"old_string\":\"x\",\"new_string\":\"y\"},{\"old_string\":\"\\\"hello\\\"\",\"new_string\":\"X\"}]}}")
66
+ [ "${R%%|*}" = "2" ] && run_test "MultiEdit with ambiguous edit → blocks" pass || run_test "MultiEdit → blocks ($R)" fail
67
+
68
+ # 9. Malformed JSON → allow (never break the tool on bad input).
69
+ R=$(run_in 'not json')
70
+ [ "${R%%|*}" = "0" ] && run_test "malformed JSON → allows" pass || run_test "malformed → allows ($R)" fail
71
+
72
+ rm -rf "$D"
73
+ echo ""
74
+ echo "Results: $PASS passed, $FAIL failed"
75
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,251 @@
1
+ #!/bin/bash
2
+ # Tests for ephemeral-container-detector.sh
3
+ #
4
+ # Verifies the SessionStart hook behavior for issue #61141:
5
+ # Layer 1 (container detected) AND Layer 2 (.claude/ looks recreated) →
6
+ # warning. Either layer alone → silent.
7
+
8
+ set -uo pipefail
9
+
10
+ HOOK="$(dirname "$0")/../examples/ephemeral-container-detector.sh"
11
+ PASS=0
12
+ FAIL=0
13
+
14
+ assert_pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
15
+ assert_fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
16
+
17
+ # Each test runs the hook in a clean env. Container signals that the hook
18
+ # reads directly from the filesystem (/.dockerenv, /proc/1/cgroup) cannot be
19
+ # mocked here; tests rely on env-var signals (CONTAINER, DEVCONTAINER, etc.)
20
+ # which exercise the same code path.
21
+
22
+ TEST_ROOT=$(mktemp -d)
23
+ trap "rm -rf $TEST_ROOT" EXIT
24
+
25
+ # Sandbox a fake CLAUDE_HOME so we never touch the real ~/.claude
26
+ FAKE_HOME="$TEST_ROOT/claude-home"
27
+
28
+ # Wrapper: run hook with a clean env containing only what each test sets.
29
+ # Critically, the wrapper UNSETs the container env vars that may leak from the
30
+ # test harness itself (CI workers can set CONTAINER/CODESPACES).
31
+ run_hook() {
32
+ env -i \
33
+ HOME="$TEST_ROOT" \
34
+ PATH="$PATH" \
35
+ CC_CLAUDE_HOME="$FAKE_HOME" \
36
+ HOSTNAME="testhost" \
37
+ "$@" \
38
+ bash "$HOOK" 2>&1
39
+ }
40
+
41
+ echo "=== ephemeral-container-detector.sh tests ==="
42
+
43
+ # --- Test 1: no container signals → silent ---
44
+ rm -rf "$FAKE_HOME"
45
+ output=$(run_hook)
46
+ rc=$?
47
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
48
+ assert_pass "no container signals → silent"
49
+ else
50
+ assert_fail "expected silent, got rc=$rc output=$output"
51
+ fi
52
+
53
+ # --- Test 2: CONTAINER env but no reset signal (settings present, approvals present) → silent ---
54
+ mkdir -p "$FAKE_HOME"
55
+ cat > "$FAKE_HOME/settings.json" <<'JSON'
56
+ {
57
+ "mcpServers": {"slack": {"command": "slack-mcp"}},
58
+ "enabledMcpjsonServers": ["slack"]
59
+ }
60
+ JSON
61
+ output=$(run_hook CONTAINER=docker)
62
+ rc=$?
63
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
64
+ assert_pass "container + approvals present → silent"
65
+ else
66
+ assert_fail "expected silent, got rc=$rc output=$output"
67
+ fi
68
+
69
+ # --- Test 3: CONTAINER env + missing settings.json → warning ---
70
+ rm -rf "$FAKE_HOME"
71
+ output=$(run_hook CONTAINER=docker)
72
+ rc=$?
73
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "MCP approval state may not persist"; then
74
+ assert_pass "container + missing settings → warning"
75
+ else
76
+ assert_fail "expected warning, got rc=$rc output=$output"
77
+ fi
78
+
79
+ # --- Test 4: warning references issue #61141 ---
80
+ if echo "$output" | grep -q "claude-code#61141"; then
81
+ assert_pass "warning references issue #61141"
82
+ else
83
+ assert_fail "missing issue ref, got $output"
84
+ fi
85
+
86
+ # --- Test 5: warning lists the CONTAINER env signal ---
87
+ if echo "$output" | grep -q "CONTAINER env set"; then
88
+ assert_pass "warning lists CONTAINER env signal"
89
+ else
90
+ assert_fail "missing CONTAINER signal, got $output"
91
+ fi
92
+
93
+ # --- Test 6: warning lists at least one mitigation ---
94
+ if echo "$output" | grep -q "Mount a persistent volume"; then
95
+ assert_pass "warning lists persistent-volume mitigation"
96
+ else
97
+ assert_fail "missing mitigation, got $output"
98
+ fi
99
+
100
+ # --- Test 7: DEVCONTAINER env triggers detection ---
101
+ output=$(run_hook DEVCONTAINER=1)
102
+ rc=$?
103
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "DEVCONTAINER env set"; then
104
+ assert_pass "DEVCONTAINER env triggers detection"
105
+ else
106
+ assert_fail "expected DEVCONTAINER detection, got rc=$rc output=$output"
107
+ fi
108
+
109
+ # --- Test 8: CODESPACES env triggers detection ---
110
+ output=$(run_hook CODESPACES=true)
111
+ rc=$?
112
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "CODESPACES env set"; then
113
+ assert_pass "CODESPACES env triggers detection"
114
+ else
115
+ assert_fail "expected CODESPACES detection, got rc=$rc output=$output"
116
+ fi
117
+
118
+ # --- Test 9: REMOTE_CONTAINERS env triggers detection ---
119
+ output=$(run_hook REMOTE_CONTAINERS=true)
120
+ rc=$?
121
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "REMOTE_CONTAINERS env set"; then
122
+ assert_pass "REMOTE_CONTAINERS env triggers detection"
123
+ else
124
+ assert_fail "expected REMOTE_CONTAINERS detection, got rc=$rc output=$output"
125
+ fi
126
+
127
+ # --- Test 10: hex-pattern hostname triggers detection ---
128
+ output=$(env -i \
129
+ HOME="$TEST_ROOT" \
130
+ PATH="$PATH" \
131
+ CC_CLAUDE_HOME="$FAKE_HOME" \
132
+ HOSTNAME="7b3a1f8d2c4e" \
133
+ bash "$HOOK" 2>&1)
134
+ rc=$?
135
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "hostname looks like a container ID"; then
136
+ assert_pass "hex-pattern hostname triggers detection"
137
+ else
138
+ assert_fail "expected hostname detection, got rc=$rc output=$output"
139
+ fi
140
+
141
+ # --- Test 11: settings.json with no mcpServers configured → silent (no MCP risk) ---
142
+ mkdir -p "$FAKE_HOME"
143
+ echo '{"theme": "dark"}' > "$FAKE_HOME/settings.json"
144
+ output=$(run_hook CONTAINER=docker)
145
+ rc=$?
146
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
147
+ assert_pass "container + no MCP configured → silent"
148
+ else
149
+ assert_fail "expected silent, got rc=$rc output=$output"
150
+ fi
151
+
152
+ # --- Test 12: settings.json with mcpServers but empty approvals → warning ---
153
+ cat > "$FAKE_HOME/settings.json" <<'JSON'
154
+ {
155
+ "mcpServers": {"slack": {"command": "slack-mcp"}, "github": {"command": "gh-mcp"}},
156
+ "enabledMcpjsonServers": []
157
+ }
158
+ JSON
159
+ output=$(run_hook CONTAINER=docker)
160
+ rc=$?
161
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "2 mcpServers configured but enabledMcpjsonServers is empty"; then
162
+ assert_pass "container + configured-but-unapproved mcpServers → warning"
163
+ else
164
+ assert_fail "expected warning with count, got rc=$rc output=$output"
165
+ fi
166
+
167
+ # --- Test 13: project-scoped mcpServers count toward reset signal ---
168
+ cat > "$FAKE_HOME/settings.json" <<'JSON'
169
+ {
170
+ "projects": {
171
+ "/home/user/foo": {"mcpServers": {"slack": {"command": "x"}}}
172
+ }
173
+ }
174
+ JSON
175
+ output=$(run_hook CONTAINER=docker)
176
+ rc=$?
177
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "mcpServers configured but enabledMcpjsonServers is empty"; then
178
+ assert_pass "project-scoped mcpServers detected"
179
+ else
180
+ assert_fail "expected project mcpServers detection, got rc=$rc output=$output"
181
+ fi
182
+
183
+ # --- Test 14: disable flag silences even when both layers match ---
184
+ rm -f "$FAKE_HOME/settings.json"
185
+ output=$(run_hook CONTAINER=docker CC_EPHEMERAL_CONTAINER_DISABLE=1)
186
+ rc=$?
187
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
188
+ assert_pass "disable flag → silent even when both layers match"
189
+ else
190
+ assert_fail "expected disabled, got rc=$rc output=$output"
191
+ fi
192
+
193
+ # --- Test 15: multiple container signals → all listed ---
194
+ output=$(env -i \
195
+ HOME="$TEST_ROOT" \
196
+ PATH="$PATH" \
197
+ CC_CLAUDE_HOME="$FAKE_HOME" \
198
+ HOSTNAME="abc123def456" \
199
+ CONTAINER=docker \
200
+ DEVCONTAINER=1 \
201
+ bash "$HOOK" 2>&1)
202
+ rc=$?
203
+ sig_count=$(echo "$output" | grep -cE "CONTAINER env set|DEVCONTAINER env set|hostname looks like")
204
+ if [ "$rc" -eq 0 ] && [ "$sig_count" -ge 3 ]; then
205
+ assert_pass "multiple container signals all listed (got $sig_count)"
206
+ else
207
+ assert_fail "expected ≥3 signals, got $sig_count output=$output"
208
+ fi
209
+
210
+ # --- Test 16: hook exits 0 (does not block session start) ---
211
+ if [ "$rc" -eq 0 ]; then
212
+ assert_pass "hook exits 0 (non-blocking)"
213
+ else
214
+ assert_fail "hook returned non-zero rc=$rc"
215
+ fi
216
+
217
+ # --- Test 17: CC_CLAUDE_HOME override is honored ---
218
+ ALT_HOME="$TEST_ROOT/alt-claude"
219
+ mkdir -p "$ALT_HOME"
220
+ output=$(env -i \
221
+ HOME="$TEST_ROOT" \
222
+ PATH="$PATH" \
223
+ CC_CLAUDE_HOME="$ALT_HOME" \
224
+ HOSTNAME="testhost" \
225
+ CONTAINER=docker \
226
+ bash "$HOOK" 2>&1)
227
+ rc=$?
228
+ # ALT_HOME exists but has no settings.json → should warn
229
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -qF "settings.json is missing at $ALT_HOME/settings.json"; then
230
+ assert_pass "CC_CLAUDE_HOME override honored in warning"
231
+ else
232
+ assert_fail "expected ALT_HOME in output, got rc=$rc output=$output"
233
+ fi
234
+
235
+ # --- Test 18: hook handles malformed settings.json gracefully ---
236
+ mkdir -p "$FAKE_HOME"
237
+ echo 'not valid json {{{' > "$FAKE_HOME/settings.json"
238
+ output=$(run_hook CONTAINER=docker 2>&1)
239
+ rc=$?
240
+ # jq will fail on the file. mcp_configured comes back as 0, so the hook
241
+ # falls through to "no reset signal" and exits silently. That's the safe
242
+ # behavior — the hook does not crash the session start on bad JSON.
243
+ if [ "$rc" -eq 0 ]; then
244
+ assert_pass "malformed settings.json → hook exits 0 (does not crash)"
245
+ else
246
+ assert_fail "expected rc=0 on bad JSON, got rc=$rc output=$output"
247
+ fi
248
+
249
+ echo ""
250
+ echo "Summary: $PASS passed, $FAIL failed"
251
+ [ "$FAIL" -eq 0 ] && exit 0 || exit 1