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,163 @@
1
+ #!/bin/bash
2
+ # Tests for deployment-readback-gh-adapter.sh (the `gh` provider adapter)
3
+ # and its end-to-end composition with deployment-readback-gate.sh.
4
+ #
5
+ # The GitHub API is mocked via DRG_GH_CMD pointing at a fixture-driven
6
+ # stub, so these tests are deterministic and offline. Timestamps for the
7
+ # "fresh" cases are generated at run time so the staleness window holds.
8
+ ADAPTER="$(dirname "$0")/../examples/deployment-readback-gh-adapter.sh"
9
+ GATE="$(dirname "$0")/../examples/deployment-readback-gate.sh"
10
+ PASS=0 FAIL=0
11
+
12
+ WORK=$(mktemp -d -t readback-gh-XXXXXX)
13
+ trap 'rm -rf "$WORK"' EXIT
14
+
15
+ # --- mock gh -------------------------------------------------------------
16
+ # Returns canned JSON from fixture files; exit codes from MOCK_*_RC env.
17
+ MOCKGH="$WORK/mockgh"
18
+ cat > "$MOCKGH" <<'EOS'
19
+ #!/bin/bash
20
+ case "$*" in
21
+ *"/statuses"*)
22
+ [ -n "${MOCK_STATUSES_FILE:-}" ] && cat "$MOCK_STATUSES_FILE"
23
+ exit "${MOCK_STATUSES_RC:-0}" ;;
24
+ *deployments*)
25
+ [ -n "${MOCK_DEPLOYMENTS_FILE:-}" ] && cat "$MOCK_DEPLOYMENTS_FILE"
26
+ exit "${MOCK_DEPLOYMENTS_RC:-0}" ;;
27
+ "repo view"*) echo "owner/repo"; exit 0 ;;
28
+ esac
29
+ exit 0
30
+ EOS
31
+ chmod +x "$MOCKGH"
32
+
33
+ NOW=$(date -u +%Y-%m-%dT%H:%M:%S.000Z)
34
+ HOUR_AGO=$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S.000Z 2>/dev/null || echo "2000-01-01T00:00:00.000Z")
35
+
36
+ dep_fixture() { # <sha>
37
+ local f="$WORK/dep-$1.json"
38
+ printf '[{"id":42,"sha":"%s","ref":"%s","environment":"production"}]\n' "$1" "$1" > "$f"
39
+ echo "$f"
40
+ }
41
+ status_fixture() { # <state> <created_at>
42
+ local f="$WORK/st-$1-$(echo "$2" | tr ':TZ.' '----').json"
43
+ printf '[{"state":"%s","created_at":"%s"}]\n' "$1" "$2" > "$f"
44
+ echo "$f"
45
+ }
46
+
47
+ ok() { echo " PASS: $1"; PASS=$((PASS+1)); }
48
+ bad() { echo " FAIL: $1"; FAIL=$((FAIL+1)); }
49
+
50
+ # run_adapter <env-assignments...> -- captures stdout into $OUT
51
+ # (env passed as VAR=val tokens before the call)
52
+ run_adapter() { OUT=$(env "$@" DRG_GH_CMD="$MOCKGH" bash "$ADAPTER" <<<'{"hook_event_name":"Stop"}' 2>/dev/null); }
53
+
54
+ # run_chain: adapter | gate ; captures gate exit into $RC
55
+ run_chain() {
56
+ env "$@" DRG_GH_CMD="$MOCKGH" bash "$ADAPTER" <<<'{"hook_event_name":"Stop"}' 2>/dev/null \
57
+ | env CC_READBACK_RECEIPT_DIR="$WORK/receipts" bash "$GATE" >/dev/null 2>/dev/null
58
+ RC=$?
59
+ }
60
+
61
+ field() { printf '%s' "$OUT" | jq -r "$1" 2>/dev/null; }
62
+
63
+ # =========================================================================
64
+ # 1. No deployment claim → pass-through {}
65
+ run_adapter DRG_CLAIM_TEXT="All tests green, opened the PR."
66
+ [ "$OUT" = "{}" ] && ok "no claim → {}" || bad "no claim → {} (got: $OUT)"
67
+ run_chain DRG_CLAIM_TEXT="All tests green, opened the PR."
68
+ [ "$RC" -eq 0 ] && ok "no claim → gate passes (exit 0)" || bad "no claim → gate exit $RC"
69
+
70
+ # 2. Benign local context must not be a claim
71
+ run_adapter DRG_CLAIM_TEXT="I deployed the function locally to test it."
72
+ [ "$OUT" = "{}" ] && ok "'deployed locally' → {}" || bad "'deployed locally' not benign (got: $OUT)"
73
+ run_adapter DRG_CLAIM_TEXT="About to deploy api@abc1234 to production."
74
+ [ "$OUT" = "{}" ] && ok "'about to deploy' → {} (not yet a claim)" || bad "'about to deploy' tripped (got: $OUT)"
75
+
76
+ # 3. Fresh + matching + success → receipt fields + gate allow
77
+ D=$(dep_fixture abc1234); S=$(status_fixture success "$NOW")
78
+ run_adapter DRG_CLAIM_TEXT="Deployment complete for api@abc1234." DRG_REPO=owner/repo \
79
+ MOCK_DEPLOYMENTS_FILE="$D" MOCK_STATUSES_FILE="$S"
80
+ [ "$(field .queried_state)" = "success" ] && ok "success: queried_state=success" || bad "queried_state ($(field .queried_state))"
81
+ [ "$(field .queried_ref)" = "abc1234" ] && ok "success: queried_ref from deployment sha" || bad "queried_ref ($(field .queried_ref))"
82
+ [ "$(field .readback_time)" = "$NOW" ] && ok "success: readback_time from status created_at" || bad "readback_time ($(field .readback_time))"
83
+ [ "$(field .authority)" = "github_deployments_api" ] && ok "success: authority set" || bad "authority ($(field .authority))"
84
+ [ "$(field .claimed_ref)" = "abc1234" ] && ok "success: claimed_ref parsed from @sha" || bad "claimed_ref ($(field .claimed_ref))"
85
+ run_chain DRG_CLAIM_TEXT="Deployment complete for api@abc1234." DRG_REPO=owner/repo \
86
+ MOCK_DEPLOYMENTS_FILE="$D" MOCK_STATUSES_FILE="$S"
87
+ [ "$RC" -eq 0 ] && ok "success fresh+match → gate allow (exit 0)" || bad "gate should allow (exit $RC)"
88
+
89
+ # 4. Ref mismatch (authority reports a different sha) → refuse-mismatch
90
+ D2=$(dep_fixture def5678); S2=$(status_fixture success "$NOW")
91
+ run_chain DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo \
92
+ MOCK_DEPLOYMENTS_FILE="$D2" MOCK_STATUSES_FILE="$S2"
93
+ [ "$RC" -eq 2 ] && ok "ref mismatch → gate refuse (exit 2)" || bad "ref mismatch exit $RC"
94
+
95
+ # 5. Status failure → refuse-mismatch
96
+ D3=$(dep_fixture abc1234); S3=$(status_fixture failure "$NOW")
97
+ run_chain DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo \
98
+ MOCK_DEPLOYMENTS_FILE="$D3" MOCK_STATUSES_FILE="$S3"
99
+ [ "$RC" -eq 2 ] && ok "status=failure → gate refuse (exit 2)" || bad "status failure exit $RC"
100
+
101
+ # 6. Deployments API errors → query-failure → fail closed
102
+ run_adapter DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo MOCK_DEPLOYMENTS_RC=1
103
+ [ "$(field .queried_state)" = "query-failure" ] && ok "API error → queried_state=query-failure" || bad "api error state ($(field .queried_state))"
104
+ run_chain DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo MOCK_DEPLOYMENTS_RC=1
105
+ [ "$RC" -eq 2 ] && ok "API error → gate refuse-query-failure (exit 2)" || bad "api error exit $RC"
106
+
107
+ # 7. No deployment on record (empty array) → not_found → refuse-mismatch
108
+ EMPTY="$WORK/empty.json"; echo '[]' > "$EMPTY"
109
+ run_adapter DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo MOCK_DEPLOYMENTS_FILE="$EMPTY"
110
+ [ "$(field .queried_state)" = "not_found" ] && ok "no deployment → queried_state=not_found" || bad "not_found state ($(field .queried_state))"
111
+ run_chain DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo MOCK_DEPLOYMENTS_FILE="$EMPTY"
112
+ [ "$RC" -eq 2 ] && ok "no deployment → gate refuse (exit 2)" || bad "not_found exit $RC"
113
+
114
+ # 8. Deployment exists, statuses API errors → query-failure
115
+ D8=$(dep_fixture abc1234)
116
+ run_chain DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo \
117
+ MOCK_DEPLOYMENTS_FILE="$D8" MOCK_STATUSES_RC=1
118
+ [ "$RC" -eq 2 ] && ok "statuses error → gate refuse-query-failure (exit 2)" || bad "statuses error exit $RC"
119
+
120
+ # 9. Deployment exists but no status yet → no_status → refuse-mismatch
121
+ D9=$(dep_fixture abc1234); SEMPTY="$WORK/st-empty.json"; echo '[]' > "$SEMPTY"
122
+ run_adapter DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo \
123
+ MOCK_DEPLOYMENTS_FILE="$D9" MOCK_STATUSES_FILE="$SEMPTY"
124
+ [ "$(field .queried_state)" = "no_status" ] && ok "no status → queried_state=no_status" || bad "no_status state ($(field .queried_state))"
125
+
126
+ # 10. Success but STALE (status 1h older than claim) → refuse-stale
127
+ D10=$(dep_fixture abc1234); S10=$(status_fixture success "$HOUR_AGO")
128
+ run_chain DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo \
129
+ MOCK_DEPLOYMENTS_FILE="$D10" MOCK_STATUSES_FILE="$S10"
130
+ [ "$RC" -eq 2 ] && ok "stale readback → gate refuse-stale (exit 2)" || bad "stale exit $RC"
131
+
132
+ # 11. Strict mode: claim but no resolvable ref → query-failure receipt → refuse
133
+ run_adapter DRG_CLAIM_TEXT="Deployment complete." DRG_REPO=owner/repo DRG_STRICT=1
134
+ [ "$(field .queried_state)" = "query-failure" ] && ok "strict + no ref → query-failure receipt" || bad "strict state ($(field .queried_state))"
135
+ run_chain DRG_CLAIM_TEXT="Deployment complete." DRG_REPO=owner/repo DRG_STRICT=1
136
+ [ "$RC" -eq 2 ] && ok "strict + no ref → gate refuse (exit 2)" || bad "strict exit $RC"
137
+
138
+ # 12. Advisory (default): claim but no resolvable ref → pass through {}
139
+ run_adapter DRG_CLAIM_TEXT="Deployment complete." DRG_REPO=owner/repo
140
+ [ "$OUT" = "{}" ] && ok "advisory + no ref → {}" || bad "advisory no ref (got: $OUT)"
141
+
142
+ # 13. claimed_ref from a bare hex token (no @)
143
+ D13=$(dep_fixture 0a1b2c3d4e5f6789); S13=$(status_fixture success "$NOW")
144
+ run_adapter DRG_CLAIM_TEXT="Rolled out 0a1b2c3d4e5f6789 to prod." DRG_REPO=owner/repo \
145
+ MOCK_DEPLOYMENTS_FILE="$D13" MOCK_STATUSES_FILE="$S13"
146
+ [ "$(field .claimed_ref)" = "0a1b2c3d4e5f6789" ] && ok "claimed_ref from bare hex token" || bad "bare hex ($(field .claimed_ref))"
147
+
148
+ # 14. DRG_CLAIMED_REF env overrides text parsing
149
+ run_adapter DRG_CLAIM_TEXT="Deployed the service." DRG_REPO=owner/repo DRG_CLAIMED_REF=feedf00d \
150
+ MOCK_DEPLOYMENTS_FILE="$(dep_fixture feedf00d)" MOCK_STATUSES_FILE="$(status_fixture success "$NOW")"
151
+ [ "$(field .claimed_ref)" = "feedf00d" ] && ok "DRG_CLAIMED_REF override" || bad "claimed_ref override ($(field .claimed_ref))"
152
+
153
+ # 15. Adapter always emits valid JSON
154
+ run_adapter DRG_CLAIM_TEXT="Deployed api@abc1234." DRG_REPO=owner/repo \
155
+ MOCK_DEPLOYMENTS_FILE="$(dep_fixture abc1234)" MOCK_STATUSES_FILE="$(status_fixture success "$NOW")"
156
+ printf '%s' "$OUT" | jq -e . >/dev/null 2>&1 && ok "receipt is valid JSON" || bad "invalid JSON: $OUT"
157
+
158
+ # 16. target field reflects repo/environment
159
+ [ "$(field .target)" = "owner/repo/production" ] && ok "target = repo/environment" || bad "target ($(field .target))"
160
+
161
+ echo ""
162
+ echo "deployment-readback-gh-adapter: $PASS passed, $FAIL failed"
163
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,78 @@
1
+ #!/bin/bash
2
+ # Tests for disabled-feature-toggle-advisor.sh
3
+ HOOK="examples/disabled-feature-toggle-advisor.sh"
4
+ PASS=0 FAIL=0
5
+
6
+ assert_contains() { if echo "$2" | grep -qF "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected '$3')"; fi; }
7
+ assert_not_contains() { if ! echo "$2" | grep -qF "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (unexpected '$3')"; fi; }
8
+
9
+ TMP=$(mktemp -d)
10
+ export HOME="$TMP"
11
+ mkdir -p "$HOME/.claude"
12
+ PROJ="$TMP/proj"; mkdir -p "$PROJ/.claude"
13
+ INPUT_NOPROJ='{}'
14
+ INPUT_PROJ="{\"cwd\":\"$PROJ\"}"
15
+ clean() { unset CC_DISABLE_TOGGLE_ADVISOR; rm -f "$HOME/.claude/settings.json" "$HOME/.claude/settings.local.json" "$PROJ/.claude/settings.json" "$PROJ/.claude/settings.local.json"; }
16
+
17
+ # Test 1: no settings → silent
18
+ clean
19
+ OUT=$(echo "$INPUT_NOPROJ" | bash "$HOOK" 2>&1)
20
+ assert_not_contains "no settings → silent" "$OUT" "disabled-feature-toggle-advisor"
21
+
22
+ # Test 2: AUTO_MEMORY disabled (the #66232 case) → warns and names it
23
+ clean
24
+ printf '{"env":{"CLAUDE_CODE_DISABLE_AUTO_MEMORY":"1"}}' > "$HOME/.claude/settings.json"
25
+ OUT=$(echo "$INPUT_NOPROJ" | bash "$HOOK" 2>&1)
26
+ assert_contains "auto_memory disabled warns" "$OUT" "disabled-feature-toggle-advisor"
27
+ assert_contains "names the key" "$OUT" "CLAUDE_CODE_DISABLE_AUTO_MEMORY"
28
+ assert_contains "explains memory wont load" "$OUT" "persistent memory will NOT load"
29
+ assert_contains "cites the incident" "$OUT" "#66232"
30
+
31
+ # Test 3: env block present but NO disable toggle → silent
32
+ clean
33
+ printf '{"env":{"FOO":"bar","CC_MD_REINJECT_EVERY":"5"}}' > "$HOME/.claude/settings.json"
34
+ OUT=$(echo "$INPUT_NOPROJ" | bash "$HOOK" 2>&1)
35
+ assert_not_contains "non-disable env → silent" "$OUT" "disabled-feature-toggle-advisor"
36
+
37
+ # Test 4: disable toggle set to falsy ("0") → silent (not active)
38
+ clean
39
+ printf '{"env":{"CLAUDE_CODE_DISABLE_AUTO_MEMORY":"0"}}' > "$HOME/.claude/settings.json"
40
+ OUT=$(echo "$INPUT_NOPROJ" | bash "$HOOK" 2>&1)
41
+ assert_not_contains "falsy toggle → silent" "$OUT" "disabled-feature-toggle-advisor"
42
+
43
+ # Test 5: multiple toggles incl. an unknown DISABLE → lists all, generic note for unknown
44
+ clean
45
+ printf '{"env":{"DISABLE_TELEMETRY":"true","CLAUDE_CODE_DISABLE_SOMETHING_NEW":"1"}}' > "$HOME/.claude/settings.json"
46
+ OUT=$(echo "$INPUT_NOPROJ" | bash "$HOOK" 2>&1)
47
+ assert_contains "telemetry listed" "$OUT" "DISABLE_TELEMETRY"
48
+ assert_contains "unknown disable listed" "$OUT" "CLAUDE_CODE_DISABLE_SOMETHING_NEW"
49
+ assert_contains "generic note for unknown" "$OUT" "a built-in behavior is turned off"
50
+
51
+ # Test 6: project settings (via cwd) toggle → warns
52
+ clean
53
+ printf '{"env":{"CLAUDE_CODE_DISABLE_1M_CONTEXT":"1"}}' > "$PROJ/.claude/settings.json"
54
+ OUT=$(echo "$INPUT_PROJ" | bash "$HOOK" 2>&1)
55
+ assert_contains "project settings toggle warns" "$OUT" "CLAUDE_CODE_DISABLE_1M_CONTEXT"
56
+ assert_contains "1m note" "$OUT" "1M context window is turned off"
57
+
58
+ # Test 7: CC_DISABLE_TOGGLE_ADVISOR=off → silent even with a toggle set
59
+ clean
60
+ printf '{"env":{"CLAUDE_CODE_DISABLE_AUTO_MEMORY":"1"}}' > "$HOME/.claude/settings.json"
61
+ OUT=$(CC_DISABLE_TOGGLE_ADVISOR=off bash -c "echo '$INPUT_NOPROJ' | bash '$HOOK'" 2>&1)
62
+ assert_not_contains "off toggle silences" "$OUT" "disabled-feature-toggle-advisor"
63
+
64
+ # Test 8: never blocks (exit 0) even when warning
65
+ clean
66
+ printf '{"env":{"CLAUDE_CODE_DISABLE_AUTO_MEMORY":"1"}}' > "$HOME/.claude/settings.json"
67
+ echo "$INPUT_NOPROJ" | bash "$HOOK" >/dev/null 2>&1
68
+ assert_contains "exit 0 (never blocks)" "$?" "0"
69
+
70
+ # Test 9: malformed settings.json → silent, no crash (fail open)
71
+ clean
72
+ printf '{bad json' > "$HOME/.claude/settings.json"
73
+ OUT=$(echo "$INPUT_NOPROJ" | bash "$HOOK" 2>&1)
74
+ assert_not_contains "malformed json → silent" "$OUT" "disabled-feature-toggle-advisor"
75
+
76
+ echo "PASS=$PASS FAIL=$FAIL"
77
+ rm -rf "$TMP"
78
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,385 @@
1
+ #!/bin/bash
2
+ # Tests for dispatch-allowlist-preflight.sh
3
+ # Issue: anthropics/claude-code#61315 (mitselek silent-stall on MCP gate)
4
+ # Principle: background sub-agent dispatch with MCP tool refs must surface
5
+ # as a loud signal before the silent permission-gate stall.
6
+
7
+ HOOK="examples/dispatch-allowlist-preflight.sh"
8
+ PASS=0 FAIL=0
9
+
10
+ # Isolate receipts and settings to a temp directory
11
+ TMPDIR_RECEIPTS=$(mktemp -d)
12
+ TMPDIR_SETTINGS=$(mktemp -d)
13
+ export CC_DISPATCH_RECEIPT_DIR="$TMPDIR_RECEIPTS"
14
+ export CC_PROJECT_SETTINGS_PATH="$TMPDIR_SETTINGS/project-settings.json"
15
+ export CC_USER_SETTINGS_PATH="$TMPDIR_SETTINGS/user-settings.json"
16
+
17
+ cleanup() {
18
+ [ -n "$TMPDIR_RECEIPTS" ] && [ -d "$TMPDIR_RECEIPTS" ] && find "$TMPDIR_RECEIPTS" -type f -delete && rmdir "$TMPDIR_RECEIPTS" 2>/dev/null
19
+ [ -n "$TMPDIR_SETTINGS" ] && [ -d "$TMPDIR_SETTINGS" ] && find "$TMPDIR_SETTINGS" -type f -delete && rmdir "$TMPDIR_SETTINGS" 2>/dev/null
20
+ }
21
+ trap cleanup EXIT
22
+
23
+ assert_contains() { if echo "$2" | grep -q -- "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected '$3' in output)"; fi; }
24
+ assert_not_contains() { if ! echo "$2" | grep -q -- "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (unexpected '$3' in output)"; fi; }
25
+ assert_exit() { if [ "$2" = "$3" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected exit $3, got $2)"; fi; }
26
+
27
+ reset_state() {
28
+ find "$CC_DISPATCH_RECEIPT_DIR" -name '*.jsonl' -delete 2>/dev/null
29
+ rm -f "$CC_PROJECT_SETTINGS_PATH" "$CC_USER_SETTINGS_PATH"
30
+ unset CC_DISPATCH_PREFLIGHT_MODE
31
+ }
32
+
33
+ # ----------------------------------------------------------------
34
+ # Group 1: Empty / malformed input silently passes
35
+ # ----------------------------------------------------------------
36
+
37
+ # Test 1: empty input silently passes
38
+ reset_state
39
+ OUT=$(echo '{}' | bash "$HOOK" 2>&1)
40
+ RC=$?
41
+ assert_exit "empty input exit 0" "$RC" "0"
42
+
43
+ # Test 2: tool_input with no fields silently passes
44
+ reset_state
45
+ OUT=$(echo '{"tool_input":{}}' | bash "$HOOK" 2>&1)
46
+ RC=$?
47
+ assert_exit "tool_input empty exit 0" "$RC" "0"
48
+
49
+ # Test 3: completely invalid JSON treated as empty
50
+ reset_state
51
+ OUT=$(echo 'not json at all' | bash "$HOOK" 2>&1)
52
+ RC=$?
53
+ assert_exit "invalid JSON exit 0" "$RC" "0"
54
+
55
+ # ----------------------------------------------------------------
56
+ # Group 2: Dispatches without MCP refs are no-op (still writes receipt)
57
+ # ----------------------------------------------------------------
58
+
59
+ # Test 4: dispatch with no MCP refs, no run_in_background — exit 0, no warning
60
+ reset_state
61
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"general-purpose","prompt":"survey the codebase"}}' | bash "$HOOK" 2>&1)
62
+ RC=$?
63
+ assert_exit "no-MCP foreground exit 0" "$RC" "0"
64
+ assert_not_contains "no-MCP foreground no warning" "$OUT" "WARNING"
65
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
66
+ assert_contains "receipt mcp_tools_referenced empty" "$RECEIPT_BODY" '"mcp_tools_referenced":\[\]'
67
+ assert_contains "receipt decision execute" "$RECEIPT_BODY" '"decision":"execute"'
68
+
69
+ # Test 5: dispatch with no MCP refs, run_in_background=true — exit 0, no warning
70
+ reset_state
71
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"general-purpose","prompt":"do the work","run_in_background":true}}' | bash "$HOOK" 2>&1)
72
+ RC=$?
73
+ assert_exit "no-MCP background exit 0" "$RC" "0"
74
+ assert_not_contains "no-MCP background no warning" "$OUT" "WARNING"
75
+
76
+ # Test 6: MCP ref but foreground (no run_in_background) — exit 0, no warning
77
+ reset_state
78
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"general-purpose","prompt":"call mcp__service__tool"}}' | bash "$HOOK" 2>&1)
79
+ RC=$?
80
+ assert_exit "MCP foreground exit 0" "$RC" "0"
81
+ assert_not_contains "MCP foreground no warning (foreground surfaces prompts)" "$OUT" "WARNING"
82
+
83
+ # ----------------------------------------------------------------
84
+ # Group 3: MCP refs + background — warning mode (default)
85
+ # ----------------------------------------------------------------
86
+
87
+ # Test 7: MCP ref + run_in_background — warns to stderr, exits 0
88
+ reset_state
89
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"general-purpose","prompt":"call mcp__service__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
90
+ RC=$?
91
+ assert_exit "MCP bg warn-mode exit 0" "$RC" "0"
92
+ assert_contains "MCP bg warn-mode emits WARNING" "$OUT" "WARNING"
93
+ assert_contains "MCP bg warn-mode names tool" "$OUT" "mcp__service__tool"
94
+ assert_contains "MCP bg warn-mode references issue #61315" "$OUT" "61315"
95
+
96
+ # Test 8: warning mentions the silent-stall observation
97
+ reset_state
98
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"general-purpose","prompt":"call mcp__service__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
99
+ assert_contains "warning explains 28-min stall" "$OUT" "28 min"
100
+ assert_contains "warning lists mitigations" "$OUT" "Mitigations"
101
+
102
+ # Test 9: multiple MCP refs in prompt all surfaced
103
+ reset_state
104
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__a__one and mcp__b__two","run_in_background":true}}' | bash "$HOOK" 2>&1)
105
+ RC=$?
106
+ assert_exit "multi-MCP exit 0" "$RC" "0"
107
+ assert_contains "multi-MCP lists first tool" "$OUT" "mcp__a__one"
108
+ assert_contains "multi-MCP lists second tool" "$OUT" "mcp__b__two"
109
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
110
+ assert_contains "receipt has first MCP tool" "$RECEIPT_BODY" 'mcp__a__one'
111
+ assert_contains "receipt has second MCP tool" "$RECEIPT_BODY" 'mcp__b__two'
112
+
113
+ # ----------------------------------------------------------------
114
+ # Group 4: Refuse mode (CC_DISPATCH_PREFLIGHT_MODE=refuse)
115
+ # ----------------------------------------------------------------
116
+
117
+ # Test 10: refuse mode blocks dispatch (exit 2)
118
+ reset_state
119
+ export CC_DISPATCH_PREFLIGHT_MODE=refuse
120
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
121
+ RC=$?
122
+ assert_exit "refuse mode exit 2" "$RC" "2"
123
+ assert_contains "refuse mode emits BLOCKED" "$OUT" "BLOCKED"
124
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
125
+ assert_contains "receipt decision refuse" "$RECEIPT_BODY" '"decision":"refuse"'
126
+
127
+ # Test 11: refuse mode does NOT block when no MCP refs
128
+ reset_state
129
+ export CC_DISPATCH_PREFLIGHT_MODE=refuse
130
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain work","run_in_background":true}}' | bash "$HOOK" 2>&1)
131
+ RC=$?
132
+ assert_exit "refuse mode no-MCP exit 0" "$RC" "0"
133
+ assert_not_contains "refuse mode no-MCP no BLOCKED" "$OUT" "BLOCKED"
134
+
135
+ # Test 12: refuse mode does NOT block when foreground (no run_in_background)
136
+ reset_state
137
+ export CC_DISPATCH_PREFLIGHT_MODE=refuse
138
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool"}}' | bash "$HOOK" 2>&1)
139
+ RC=$?
140
+ assert_exit "refuse mode foreground exit 0" "$RC" "0"
141
+ assert_not_contains "refuse mode foreground no BLOCKED" "$OUT" "BLOCKED"
142
+
143
+ # ----------------------------------------------------------------
144
+ # Group 5: Off mode (CC_DISPATCH_PREFLIGHT_MODE=off)
145
+ # ----------------------------------------------------------------
146
+
147
+ # Test 13: off mode silent, but still writes receipt
148
+ reset_state
149
+ export CC_DISPATCH_PREFLIGHT_MODE=off
150
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
151
+ RC=$?
152
+ assert_exit "off mode exit 0" "$RC" "0"
153
+ assert_not_contains "off mode no WARNING" "$OUT" "WARNING"
154
+ assert_not_contains "off mode no BLOCKED" "$OUT" "BLOCKED"
155
+ RECEIPT_FILES=$(find "$CC_DISPATCH_RECEIPT_DIR" -name '*.jsonl' | wc -l)
156
+ if [ "$RECEIPT_FILES" -ge "1" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: off mode did not write receipt"; fi
157
+
158
+ # ----------------------------------------------------------------
159
+ # Group 6: Allowlist coverage detection
160
+ # ----------------------------------------------------------------
161
+
162
+ # Test 14: allowlist includes the MCP tool — coverage marked true,
163
+ # warning explains parent has it but inheritance bug persists
164
+ reset_state
165
+ cat > "$CC_PROJECT_SETTINGS_PATH" <<JSON
166
+ {"permissions":{"allow":["mcp__plugin__tool","Read"]}}
167
+ JSON
168
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
169
+ RC=$?
170
+ assert_exit "covered MCP exit 0" "$RC" "0"
171
+ assert_contains "covered MCP warning mentions parent allowlist" "$OUT" "In parent allowlist"
172
+ assert_contains "covered MCP warning mentions inheritance bug" "$OUT" "61315"
173
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
174
+ assert_contains "receipt marks coverage true" "$RECEIPT_BODY" '"parent_covered":true'
175
+
176
+ # Test 15: allowlist does NOT include the MCP tool — coverage false,
177
+ # warning mentions silent permission gate
178
+ reset_state
179
+ cat > "$CC_PROJECT_SETTINGS_PATH" <<JSON
180
+ {"permissions":{"allow":["Read","Bash"]}}
181
+ JSON
182
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
183
+ assert_contains "uncovered MCP warning mentions silent permission gate" "$OUT" "silent permission gate"
184
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
185
+ assert_contains "receipt marks coverage false" "$RECEIPT_BODY" '"parent_covered":false'
186
+
187
+ # Test 16: allowlist merged from both project + user scopes
188
+ reset_state
189
+ cat > "$CC_PROJECT_SETTINGS_PATH" <<JSON
190
+ {"permissions":{"allow":["Read"]}}
191
+ JSON
192
+ cat > "$CC_USER_SETTINGS_PATH" <<JSON
193
+ {"permissions":{"allow":["mcp__plugin__tool"]}}
194
+ JSON
195
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
196
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
197
+ assert_contains "user-scope allowlist counted" "$RECEIPT_BODY" '"parent_covered":true'
198
+
199
+ # Test 17: malformed settings file does not crash
200
+ reset_state
201
+ echo 'not valid json' > "$CC_PROJECT_SETTINGS_PATH"
202
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"use mcp__plugin__tool","run_in_background":true}}' | bash "$HOOK" 2>&1)
203
+ RC=$?
204
+ assert_exit "malformed settings exit 0" "$RC" "0"
205
+
206
+ # ----------------------------------------------------------------
207
+ # Group 7: Receipt format integrity
208
+ # ----------------------------------------------------------------
209
+
210
+ # Test 18: receipt is valid JSONL (one object per line)
211
+ reset_state
212
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"p1","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
213
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"y","prompt":"p2 with mcp__a__b","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
214
+ LINES_OK=0
215
+ LINES_TOTAL=0
216
+ while IFS= read -r line; do
217
+ LINES_TOTAL=$((LINES_TOTAL+1))
218
+ if echo "$line" | jq . >/dev/null 2>&1; then
219
+ LINES_OK=$((LINES_OK+1))
220
+ fi
221
+ done < "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl
222
+ if [ "$LINES_OK" = "2" ] && [ "$LINES_TOTAL" = "2" ]; then
223
+ PASS=$((PASS+1))
224
+ else
225
+ FAIL=$((FAIL+1))
226
+ echo "FAIL: receipt JSONL not valid (got $LINES_OK/$LINES_TOTAL valid)"
227
+ fi
228
+
229
+ # Test 19: receipt has ISO 8601 UTC timestamp
230
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null | head -1)
231
+ assert_contains "receipt ts ISO 8601 UTC" "$RECEIPT_BODY" '"ts":"20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z"'
232
+
233
+ # Test 20: PHI safety — prompt not stored verbatim
234
+ reset_state
235
+ SENSITIVE="patient SSN 123-45-6789 needs review"
236
+ echo "{\"tool_name\":\"Agent\",\"tool_input\":{\"subagent_type\":\"x\",\"prompt\":\"$SENSITIVE\",\"run_in_background\":true}}" | bash "$HOOK" >/dev/null 2>&1
237
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
238
+ assert_not_contains "receipt does not contain SSN" "$RECEIPT_BODY" "123-45-6789"
239
+ assert_not_contains "receipt does not contain 'patient'" "$RECEIPT_BODY" "patient SSN"
240
+ assert_contains "receipt does contain prompt_hash" "$RECEIPT_BODY" '"prompt_hash"'
241
+
242
+ # Test 21: prompt_hash deterministic sha256
243
+ reset_state
244
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"hello world","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
245
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
246
+ EXPECTED_HASH="b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
247
+ assert_contains "prompt_hash matches sha256('hello world')" "$RECEIPT_BODY" "$EXPECTED_HASH"
248
+
249
+ # ----------------------------------------------------------------
250
+ # Group 8: Edge cases
251
+ # ----------------------------------------------------------------
252
+
253
+ # Test 22: very large prompt (10KB) handled
254
+ reset_state
255
+ BIG=$(printf 'use mcp__a__b. ' && python3 -c "print('x' * 10000)")
256
+ PAYLOAD=$(printf '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":%s,"run_in_background":true}}' "$(printf '%s' "$BIG" | jq -Rs .)")
257
+ OUT=$(echo "$PAYLOAD" | bash "$HOOK" 2>&1)
258
+ RC=$?
259
+ assert_exit "10KB prompt exit 0" "$RC" "0"
260
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
261
+ assert_contains "10KB prompt MCP ref captured" "$RECEIPT_BODY" "mcp__a__b"
262
+
263
+ # Test 23: special chars in subagent_type
264
+ reset_state
265
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"agent-with-dashes_and_under","prompt":"use mcp__svc__tool","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
266
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
267
+ assert_contains "subagent_type with dashes preserved" "$RECEIPT_BODY" 'agent-with-dashes_and_under'
268
+
269
+ # Test 24: subagent_type missing — defaults to general-purpose
270
+ reset_state
271
+ echo '{"tool_name":"Agent","tool_input":{"prompt":"use mcp__svc__tool","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
272
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/*.jsonl 2>/dev/null)
273
+ assert_contains "subagent_type defaults to general-purpose" "$RECEIPT_BODY" '"subagent_type":"general-purpose"'
274
+
275
+ # ----------------------------------------------------------------
276
+ # Group 9: Audit query usability
277
+ # ----------------------------------------------------------------
278
+
279
+ # Test 25: audit query to find dispatches with MCP refs works
280
+ reset_state
281
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"a","prompt":"plain","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
282
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"b","prompt":"use mcp__svc__tool","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
283
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"c","prompt":"use mcp__other__one mcp__other__two","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
284
+ MCP_DISPATCHES=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null | jq -c 'select(.mcp_tools_referenced | length > 0)' | wc -l)
285
+ if [ "$MCP_DISPATCHES" = "2" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: audit query expected 2 MCP-ref dispatches, got $MCP_DISPATCHES"; fi
286
+
287
+ # ----------------------------------------------------------------
288
+ # Group 10: Schema v2 — articulated_scope fields from companion log
289
+ #
290
+ # Schema v2 adds articulated_scope_hash and articulated_scope_length
291
+ # fields to the receipt, populated from the most recent
292
+ # userprompt-submit-YYYY-MM-DD.jsonl companion log entry. When the
293
+ # companion log is absent, both fields are written as null.
294
+ #
295
+ # Architecture rationale at:
296
+ # https://github.com/anthropics/claude-code/issues/61102#issuecomment-4514215413
297
+ # ----------------------------------------------------------------
298
+
299
+ # Test 26: receipt includes schema_version 2
300
+ reset_state
301
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain"}}' | bash "$HOOK" >/dev/null 2>&1
302
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null)
303
+ assert_contains "receipt has schema_version 2" "$RECEIPT_BODY" '"schema_version":2'
304
+
305
+ # Test 27: without companion log, articulated_scope_hash is null
306
+ reset_state
307
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain"}}' | bash "$HOOK" >/dev/null 2>&1
308
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null)
309
+ assert_contains "no companion → articulated_scope_hash null" "$RECEIPT_BODY" '"articulated_scope_hash":null'
310
+ assert_contains "no companion → articulated_scope_length null" "$RECEIPT_BODY" '"articulated_scope_length":null'
311
+
312
+ # Test 28: with companion log, articulated_scope fields populated
313
+ reset_state
314
+ COMPANION="$CC_DISPATCH_RECEIPT_DIR/userprompt-submit-$(date +%Y-%m-%d).jsonl"
315
+ cat > "$COMPANION" <<JSON
316
+ {"ts":"2026-05-22T00:00:00Z","prompt_hash":"abcdef0123456789","prompt_length":42,"schema_version":1}
317
+ JSON
318
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain"}}' | bash "$HOOK" >/dev/null 2>&1
319
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null)
320
+ assert_contains "with companion → articulated_scope_hash populated" "$RECEIPT_BODY" '"articulated_scope_hash":"abcdef0123456789"'
321
+ assert_contains "with companion → articulated_scope_length populated" "$RECEIPT_BODY" '"articulated_scope_length":42'
322
+
323
+ # Test 29: companion log with multiple entries — only the last is used
324
+ reset_state
325
+ COMPANION="$CC_DISPATCH_RECEIPT_DIR/userprompt-submit-$(date +%Y-%m-%d).jsonl"
326
+ cat > "$COMPANION" <<JSON
327
+ {"ts":"2026-05-22T00:00:00Z","prompt_hash":"first0000000000","prompt_length":10,"schema_version":1}
328
+ {"ts":"2026-05-22T00:00:01Z","prompt_hash":"last1111111111","prompt_length":20,"schema_version":1}
329
+ JSON
330
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain"}}' | bash "$HOOK" >/dev/null 2>&1
331
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null)
332
+ assert_contains "last entry wins (hash)" "$RECEIPT_BODY" '"articulated_scope_hash":"last1111111111"'
333
+ assert_contains "last entry wins (length)" "$RECEIPT_BODY" '"articulated_scope_length":20'
334
+
335
+ # Test 30: malformed companion log entry — fields stay null, no crash
336
+ reset_state
337
+ COMPANION="$CC_DISPATCH_RECEIPT_DIR/userprompt-submit-$(date +%Y-%m-%d).jsonl"
338
+ echo 'not valid json at all' > "$COMPANION"
339
+ OUT=$(echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain"}}' | bash "$HOOK" 2>&1)
340
+ RC=$?
341
+ assert_exit "malformed companion exit 0" "$RC" "0"
342
+ RECEIPT_BODY=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null)
343
+ assert_contains "malformed companion → hash null" "$RECEIPT_BODY" '"articulated_scope_hash":null'
344
+
345
+ # Test 31: receipt is still valid JSONL with schema v2 fields
346
+ reset_state
347
+ COMPANION="$CC_DISPATCH_RECEIPT_DIR/userprompt-submit-$(date +%Y-%m-%d).jsonl"
348
+ cat > "$COMPANION" <<JSON
349
+ {"ts":"2026-05-22T00:00:00Z","prompt_hash":"abcd1234","prompt_length":50,"schema_version":1}
350
+ JSON
351
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"p1"}}' | bash "$HOOK" >/dev/null 2>&1
352
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"y","prompt":"p2 with mcp__a__b","run_in_background":true}}' | bash "$HOOK" >/dev/null 2>&1
353
+ LINES_OK=0
354
+ LINES_TOTAL=0
355
+ while IFS= read -r line; do
356
+ LINES_TOTAL=$((LINES_TOTAL+1))
357
+ if echo "$line" | jq . >/dev/null 2>&1; then
358
+ LINES_OK=$((LINES_OK+1))
359
+ fi
360
+ done < "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl
361
+ if [ "$LINES_OK" = "2" ] && [ "$LINES_TOTAL" = "2" ]; then
362
+ PASS=$((PASS+1))
363
+ else
364
+ FAIL=$((FAIL+1))
365
+ echo "FAIL: v2 receipt JSONL not valid (got $LINES_OK/$LINES_TOTAL valid)"
366
+ fi
367
+
368
+ # Test 32: schema v2 receipt is joinable on articulated_scope_hash
369
+ reset_state
370
+ COMPANION="$CC_DISPATCH_RECEIPT_DIR/userprompt-submit-$(date +%Y-%m-%d).jsonl"
371
+ cat > "$COMPANION" <<JSON
372
+ {"ts":"2026-05-22T00:00:00Z","prompt_hash":"joinable_hash_1","prompt_length":33,"schema_version":1}
373
+ JSON
374
+ echo '{"tool_name":"Agent","tool_input":{"subagent_type":"x","prompt":"plain"}}' | bash "$HOOK" >/dev/null 2>&1
375
+ # Audit query: find dispatches whose articulated_scope is known
376
+ JOINABLE=$(cat "$CC_DISPATCH_RECEIPT_DIR"/dispatch-preflight-*.jsonl 2>/dev/null | \
377
+ jq -c 'select(.articulated_scope_hash != null)' | wc -l)
378
+ if [ "$JOINABLE" = "1" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: joinable receipt count expected 1, got $JOINABLE"; fi
379
+
380
+ echo ""
381
+ echo "===================="
382
+ echo "PASS: $PASS"
383
+ echo "FAIL: $FAIL"
384
+ echo "===================="
385
+ [ "$FAIL" = "0" ] && exit 0 || exit 1