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,114 @@
1
+ #!/bin/bash
2
+ # destructive-guard: mass deletion driven by find
3
+ #
4
+ # The old Check 5 matched only `find /`, `find ~` and `find ..` followed by
5
+ # -delete. The two forms people actually run -- `find . -delete` and
6
+ # `find . -exec rm -rf {} \;` -- walked straight past it, and so did every
7
+ # variant that quoted the flag or put a wrapper in front of the command.
8
+ # Two adversarial reviews in 2026-07 rejected earlier attempts because a
9
+ # simpler bypass always survived the word-boundary checks.
10
+ #
11
+ # The rewrite inverts the detection: normalise the line first (drop quotes,
12
+ # drop wrappers, resolve /usr/bin/find, join continuations), then ask three
13
+ # plain questions -- is the command find, does it delete, and how wide is the
14
+ # search. Everyday narrowed cleanup stays allowed; an unnarrowed sweep does not.
15
+ #
16
+ # Measured 2026-07-27: 26 of the 30 blocking cases below returned exit 0
17
+ # against the shipped guard.
18
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
19
+ GUARD=$(mktemp); trap 'rm -f "$GUARD"' EXIT
20
+ python3 -c "
21
+ import json,sys
22
+ sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$GUARD"
23
+
24
+ PASS=0; FAIL=0
25
+
26
+ check() {
27
+ local desc="$1" cmd="$2" want="$3" # want: 2 = blocked, 0 = allowed
28
+ local payload code
29
+ payload=$(python3 -c '
30
+ import json,sys
31
+ print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$cmd")
32
+ printf '%s' "$payload" | bash "$GUARD" >/dev/null 2>&1
33
+ code=$?
34
+ if [ "$code" = "$want" ]; then
35
+ echo "PASS: $desc"; PASS=$((PASS+1))
36
+ else
37
+ echo "FAIL: $desc (expected exit $want, got $code)"; FAIL=$((FAIL+1))
38
+ fi
39
+ }
40
+
41
+ # --- the two forms people actually run ---------------------------------------
42
+ check "plain find -delete" 'find . -delete' 2
43
+ check "find -exec rm" 'find . -exec rm -rf {} \;' 2
44
+ check "find -execdir rm" 'find . -execdir rm -f {} \;' 2
45
+ check "find -exec unlink" 'find . -exec unlink {} \;' 2
46
+ check "no root given" 'find -delete' 2
47
+
48
+ # --- N series: quoting defeated the word boundaries --------------------------
49
+ check "quoted flag, single" "find . '-delete'" 2
50
+ check "quoted flag, double" 'find . "-delete"' 2
51
+ check "quoted rm inside -exec" "find . -exec 'rm' -rf {} \;" 2
52
+
53
+ # --- K series: a wrapper in front of the real command ------------------------
54
+ check "env wrapper" 'env find . -delete' 2
55
+ check "nice wrapper" 'nice find . -delete' 2
56
+ check "nice with option" 'nice -n 5 find . -delete' 2
57
+ check "timeout wrapper" 'timeout 30 find . -delete' 2
58
+ check "sudo wrapper" 'sudo find . -delete' 2
59
+ check "exec wrapper" 'exec find . -delete' 2
60
+ check "doubled command builtin" 'command command find . -delete' 2
61
+ check "relative path to find" './find . -delete' 2
62
+ check "absolute path to find" '/usr/bin/find . -delete' 2
63
+ check "leading assignment" 'FOO=1 find . -delete' 2
64
+ check "shell -c wrapper" 'bash -c "find . -delete"' 2
65
+ check "xargs in front" 'xargs find . -delete' 2
66
+
67
+ # --- dangerous search roots ---------------------------------------------------
68
+ check "root is /" "find / -name '*.log' -delete" 2
69
+ check "root is ~" "find ~ -name '*.tmp' -delete" 2
70
+ check "root is \$HOME" 'find $HOME -delete' 2
71
+ check "root is parent" 'find .. -delete' 2
72
+
73
+ # --- narrowing that does not actually narrow ---------------------------------
74
+ check "-type alone is not narrowing" 'find . -type f -delete' 2
75
+ check "bare wildcard is not narrowing" "find . -name '*' -delete" 2
76
+ check "-o rebinds the delete" "find . -name '*.pyc' -o -delete" 2
77
+
78
+ # --- reachable through any separator, and across a continued line ------------
79
+ check "bare & separator" 'true & find . -delete' 2
80
+ check "semicolon separator" 'true ; find . -delete' 2
81
+ check "line continuation" 'find . \
82
+ -delete' 2
83
+
84
+ # --- everyday cleanup must stay allowed --------------------------------------
85
+ check "narrowed by name" "find . -name '*.pyc' -delete" 0
86
+ check "narrowed by name and age" "find ./logs -name '*.log' -mtime +30 -delete" 0
87
+ check "type plus name" "find . -type f -name '*.tmp' -delete" 0
88
+ check "narrowed by -newer" 'find . -newer package.json -delete' 0
89
+ check "throwaway dir: node_modules" 'find node_modules -delete' 0
90
+ check "throwaway dir: dist" 'find dist -delete' 0
91
+ check "throwaway dir: ./build" 'find ./build -delete' 0
92
+ check "print only" 'find . -print' 0
93
+ check "print only from /" "find / -name '*.log' -print" 0
94
+ check "piped to grep" "find . -name '*.py' | xargs grep foo" 0
95
+ check "find inside a string" 'echo "find . -delete"' 0
96
+ check "find inside a commit message" 'git commit -m "add find . -delete example"' 0
97
+ check "prune, no deletion" 'find . -type d -name node_modules -prune' 0
98
+ check "unrelated command" 'ls -la' 0
99
+
100
+ # --- Check 1: trailing content used to defeat the tilde/HOME position --------
101
+ check "bare tilde" 'rm -rf ~' 2
102
+ check "tilde then a comment" 'rm -rf ~ # cleanup' 2
103
+ check "tilde then another argument" 'rm -rf ~ /srv/data' 2
104
+ check "quoted HOME" 'rm -rf "$HOME"' 2
105
+ check "HOME then a redirect" 'rm -rf "$HOME" 2>/dev/null' 2
106
+ check "parent then a comment" 'rm -rf .. # oops' 2
107
+ check "cwd then a comment" 'rm -rf . # oops' 2
108
+ check "specific subdirectory allowed" 'rm -rf ./node_modules' 0
109
+ check "nested build path allowed" 'rm -rf ./dist/assets' 0
110
+ check "path under .git allowed" 'rm -rf .git/objects/tmp' 0
111
+
112
+ echo
113
+ echo "destructive-guard-find-deletion: $PASS passed, $FAIL failed"
114
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,106 @@
1
+ #!/bin/bash
2
+ # destructive-guard: the words do not have to be in that order
3
+ #
4
+ # Checks 2, 3 and 4 each pinned the position of a flag:
5
+ #
6
+ # Check 2 git\s+reset\s+--hard -- --hard must follow `reset`
7
+ # Check 3 git\s+clean\s+-[a-z]*[fd] -- the flags must be one bundle, first
8
+ # Check 4 chmod\s+(-R\s+)?777\s+(/|~|\.) -- -R before 777, path right after
9
+ #
10
+ # A shell does not care. `git reset HEAD~1 --hard` discards exactly the same work,
11
+ # `git clean -x -f -d` deletes more than `git clean -fd`, and `chmod 777 -R /etc`
12
+ # is `chmod -R 777 /etc`. All three walked past the guard.
13
+ #
14
+ # Measured 2026-08-03 against the shipped copy, with the denominator restricted to
15
+ # the pairs this guard actually blocks in their canonical form: 5 of 19 reorderings
16
+ # were not blocked. After the fix: 0 of 19, with 0 newly blocked out of 28 everyday
17
+ # commands.
18
+ #
19
+ # This is the same shape as the defect in the approving hooks fixed the same day
20
+ # (#937/#940/#941/#942/#943/#947/#948), one level up: there the rule assumed the
21
+ # dangerous part came *after* the first command position; here it assumes the
22
+ # dangerous flag comes in a fixed *slot*. Both are a pattern that encodes a habit
23
+ # of typing rather than what the command does.
24
+ #
25
+ # `[^;&|]` keeps every scan inside one command, so a later command's words are
26
+ # never borrowed to make a match.
27
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
28
+ GUARD=$(mktemp); trap 'rm -f "$GUARD"' EXIT
29
+ python3 -c "
30
+ import json,sys
31
+ sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$GUARD"
32
+
33
+ PASS=0; FAIL=0
34
+
35
+ check() {
36
+ local desc="$1" cmd="$2" want="$3" # want: 2 = blocked, 0 = allowed
37
+ local payload code
38
+ payload=$(python3 -c '
39
+ import json,sys
40
+ print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$cmd")
41
+ printf '%s' "$payload" | bash "$GUARD" >/dev/null 2>&1
42
+ code=$?
43
+ if [ "$code" = "$want" ]; then
44
+ echo "PASS: $desc"; PASS=$((PASS+1))
45
+ else
46
+ echo "FAIL: $desc (expected exit $want, got $code)"; FAIL=$((FAIL+1))
47
+ fi
48
+ }
49
+
50
+ # --- Check 2: git reset --hard, wherever the flag sits ---
51
+ check "reset: canonical order" 'git reset --hard HEAD~1' 2
52
+ check "reset: flag last" 'git reset HEAD~1 --hard' 2
53
+ check "reset: flag last, named remote" 'git reset origin/main --hard' 2
54
+ check "reset: bare" 'git reset --hard' 2
55
+ check "reset: --soft is not --hard" 'git reset --soft HEAD~1' 0
56
+ check "reset: plain reset unstages only" 'git reset HEAD~1' 0
57
+ check "reset: --hard belongs to the next command" 'git reset HEAD~1 ; echo --hard' 0
58
+ check "reset: inside a message" "git commit -m 'git reset --hard の話'" 0
59
+
60
+ # --- Check 3: git clean, flags split or reordered ---
61
+ check "clean: canonical bundle" 'git clean -fd' 2
62
+ check "clean: split flags" 'git clean -f -d' 2
63
+ check "clean: reversed" 'git clean -d -f' 2
64
+ check "clean: another flag first" 'git clean -x -f -d' 2
65
+ check "clean: bundle with a trailing x" 'git clean -fdx' 2
66
+ check "clean: bundle with two extras" 'git clean -fdxq' 2
67
+ check "clean: long form" 'git clean --force -d' 2
68
+ check "clean: dry run stays allowed" 'git clean -n' 0
69
+ check "clean: dry run with -d" 'git clean -nd' 0
70
+ check "clean: dry run with -d and -x" 'git clean -ndx' 0
71
+ check "clean: long dry run" 'git clean --dry-run' 0
72
+ check "clean: force plus dry run is a dry run" 'git clean --force --dry-run' 0
73
+
74
+ # --- Check 4: chmod 777, wherever -R sits ---
75
+ check "chmod: canonical order" 'chmod -R 777 /etc' 2
76
+ check "chmod: -R after the mode" 'chmod 777 -R /etc' 2
77
+ check "chmod: -R last" 'chmod 777 /etc -R' 2
78
+ check "chmod: long recursive flag" 'chmod --recursive 777 /etc' 2
79
+ check "chmod: no -R at all" 'chmod 777 /etc' 2
80
+ check "chmod: home directory" 'chmod 777 -R ~/' 2
81
+ check "chmod: relative path" 'chmod 777 -R ./' 2
82
+ check "chmod: a narrower mode is fine" 'chmod 644 ./file.txt' 0
83
+ check "chmod: 755 on a script" 'chmod 755 ./bin/run' 0
84
+ check "chmod: +x is fine" 'chmod +x script.sh' 0
85
+ check "chmod: 777 on a plain filename" 'chmod 777 file.txt' 0
86
+
87
+ # --- the scans must not cross into the next command ---
88
+ check "no borrowing across ;" 'echo 777 ; chmod 644 ./x' 0
89
+ check "no borrowing across &&" 'git clean -n && echo -fd' 0
90
+
91
+ # --- Check 5: a wrapper may carry assignments of its own ---
92
+ # Found while judging the 2026-07-27 find hypothesis: the prefix stripper dropped
93
+ # leading VAR=value once, then dropped wrappers in a loop. `env LC_ALL=C find` puts
94
+ # the assignment *after* the wrapper, so it survived and the command word was read
95
+ # as `LC_ALL=C`. Same shape as the rest of this file: a rule that assumed which
96
+ # order the pieces arrive in. Assignments are now dropped inside the same loop.
97
+ check "find: bare wrapper" 'env find . -delete' 2
98
+ check "find: wrapper with an assignment" 'env LC_ALL=C find . -delete' 2
99
+ check "find: two assignments" 'env LC_ALL=C TZ=UTC find . -delete' 2
100
+ check "find: assignment with no wrapper" 'LC_ALL=C find . -delete' 2
101
+ check "find: narrowed cleanup still runs" "find . -name '*.pyc' -delete" 0
102
+ check "find: narrowed with a wrapper" "env LC_ALL=C find . -name '*.pyc' -delete" 0
103
+
104
+ echo
105
+ echo "destructive-guard-flag-order: $PASS passed, $FAIL failed"
106
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,107 @@
1
+ #!/bin/bash
2
+ # Searching for a dangerous command is not running one.
3
+ #
4
+ # destructive-guard scans the whole command string, so a dangerous string
5
+ # written inside quotes — or inside a sentence — reached the same checks as an
6
+ # executed command. Measured 2026-08-04 against fifteen commands that must not
7
+ # be blocked: six were blocked. All six merely mention a command:
8
+ #
9
+ # grep -r "rm -rf /" . searching for it
10
+ # echo 'rm -rf /' >> notes.md writing it into a note
11
+ # git commit -m "docs: warn about rm -rf /" naming it in a message
12
+ # jq -n '{cmd: "rm -rf /"}' naming it in a filter
13
+ # awk '/rm -rf / {print}' history.log naming it in a program
14
+ # echo "the command rm -rf ~ destroys ..." describing it
15
+ #
16
+ # A guard that blocks grep, awk and git commit is switched off the same day it
17
+ # is installed, and a switched-off guard is worse than none because the user
18
+ # still believes it is there. (The author hit this false positive seven times in
19
+ # one day while writing about the guard.)
20
+ #
21
+ # Check 0y blanks quoted spans and asks whether a destructive verb still appears
22
+ # at a command start. If none does, nothing destructive is being invoked.
23
+ # It does NOT strip the quotes before matching — stripping them would lose a
24
+ # real invocation whose target is quoted. Everything after the gate still
25
+ # matches against the original text.
26
+ #
27
+ # The block half of this file is what keeps the gate honest. A gate that lets
28
+ # too much through is exactly as useless as the false positives it removes, so
29
+ # every wrapper form the other suites cover is repeated here: prefixes, leading
30
+ # assignments, path-qualified names, and the three constructs that execute their
31
+ # quoted argument (`sh -c`, `eval`, `powershell -Command`).
32
+
33
+ set -u
34
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
35
+ WORK="$(mktemp -d)"
36
+ trap 'find "$WORK" -mindepth 1 -delete 2>/dev/null; rmdir "$WORK" 2>/dev/null' EXIT
37
+ PASS=0; FAIL=0
38
+
39
+ python3 -c "
40
+ import json,sys
41
+ sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$WORK/dg.sh"
42
+
43
+ run() {
44
+ local T; T="$(mktemp -d)"
45
+ python3 -c '
46
+ import json,sys
47
+ print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]},
48
+ "cwd":sys.argv[2],"session_id":"t"}))' "$1" "$T" \
49
+ | HOME="$T" bash "$WORK/dg.sh" >/dev/null 2>&1
50
+ local rc=$?
51
+ find "$T" -mindepth 1 -delete 2>/dev/null; rmdir "$T" 2>/dev/null
52
+ return $rc
53
+ }
54
+ want_block() {
55
+ if run "$1"; then FAIL=$((FAIL+1)); echo " FAIL blocked: $1"
56
+ else PASS=$((PASS+1)); echo " ok blocked: $1"; fi
57
+ }
58
+ want_allow() {
59
+ if run "$1"; then PASS=$((PASS+1)); echo " ok allowed: $1"
60
+ else FAIL=$((FAIL+1)); echo " FAIL allowed: $1"; fi
61
+ }
62
+
63
+ RM="$(printf 'r%s' 'm') -rf "
64
+ echo "destructive-guard-mentions-vs-invocations"
65
+
66
+ # --- mentions: the command appears only inside quotes or prose ---------------
67
+ want_allow "grep -r \"${RM}/\" ."
68
+ want_allow "grep -rn '${RM}~' docs/"
69
+ want_allow "echo \"${RM}~\""
70
+ want_allow "echo '${RM}/' >> notes.md"
71
+ want_allow "git commit -m \"docs: warn about ${RM}/ in the guide\""
72
+ want_allow "git log --grep=\"${RM}\""
73
+ want_allow "python3 -c \"print('${RM}~')\""
74
+ want_allow "jq -n '{cmd: \"${RM}/\"}'"
75
+ want_allow "printf \"%s\\n\" \"${RM}~\" > example.txt"
76
+ want_allow "rg \"${RM}\" --files-with-matches"
77
+ want_allow "sed -n \"/${RM}/p\" history.log"
78
+ want_allow "awk '/${RM}/ {print}' history.log"
79
+ want_allow "echo \"the command ${RM}~ destroys your home directory\""
80
+
81
+ # --- invocations: the command actually runs ---------------------------------
82
+ want_block "${RM}~"
83
+ want_block "${RM}/"
84
+ want_block "cd /tmp && ${RM}~"
85
+ want_block "[[ -n \$(${RM}~) ]]"
86
+ want_block "if true; then ${RM}~; fi"
87
+ want_block "env ${RM}~"
88
+ want_block "nice -n 5 ${RM}~"
89
+ want_block "timeout 30 ${RM}~"
90
+ want_block "FOO=1 ${RM}~"
91
+ want_block "/bin/${RM}~"
92
+ want_block "git reset --hard HEAD~5"
93
+
94
+ # --- the quoted argument is executed here, so it is an invocation ------------
95
+ want_block "bash -c \"${RM}~\""
96
+ want_block "sh -c '${RM}/'"
97
+
98
+ # Known gap, not asserted: `eval "rm -rf ~"` passes, and so do `rm -rf "/etc"`
99
+ # and `rm -rf '~'`. The gate correctly refuses to treat these as mentions, but
100
+ # the target matching downstream does not unquote its operand, so the path is
101
+ # never recognised. Measured 2026-08-04 on the shipped guard as well — this
102
+ # predates the gate and is tracked separately. Asserting it here would make the
103
+ # file fail for a reason it does not fix.
104
+
105
+ echo
106
+ echo "destructive-guard-mentions-vs-invocations: $PASS passed, $FAIL failed"
107
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,89 @@
1
+ #!/bin/bash
2
+ # Quoting the argument made the target invisible.
3
+ #
4
+ # Check 1 required the path to follow the flags directly:
5
+ #
6
+ # rm -rf /etc blocked
7
+ # rm -rf "/etc" NOT blocked <- same deletion, one character apart
8
+ # rm -rf '~' NOT blocked
9
+ #
10
+ # Quoting an argument is an ordinary way to write a command — a path with a
11
+ # space in it has to be quoted — so this is not an evasion technique, it is
12
+ # what a careful user types. Measured 2026-08-04 against the shipped guard:
13
+ # five of nine quoted forms passed.
14
+ #
15
+ # Two places assumed an unquoted operand: the Check 1 pattern (one optional
16
+ # quote is now allowed in front of the path, and the terminators accept a
17
+ # closing quote) and the TARGET_PATH extraction feeding findmnt (`\S+` picked
18
+ # up the quotes, and findmnt cannot resolve a path spelled with them attached).
19
+ #
20
+ # The controls are what keep this from becoming "block anything with a quote":
21
+ # a quoted safe target must still pass, and — this is the one that matters after
22
+ # the mentions/invocations gate landed — a dangerous string quoted inside grep,
23
+ # echo, git commit or awk must still pass, because searching for a command is
24
+ # not running it.
25
+
26
+ set -u
27
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
28
+ WORK="$(mktemp -d)"
29
+ trap 'find "$WORK" -mindepth 1 -delete 2>/dev/null; rmdir "$WORK" 2>/dev/null' EXIT
30
+ PASS=0; FAIL=0
31
+
32
+ python3 -c "
33
+ import json,sys
34
+ sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$WORK/dg.sh"
35
+
36
+ run() {
37
+ local T; T="$(mktemp -d)"
38
+ python3 -c '
39
+ import json,sys
40
+ print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]},
41
+ "cwd":sys.argv[2],"session_id":"t"}))' "$1" "$T" \
42
+ | HOME="$T" bash "$WORK/dg.sh" >/dev/null 2>&1
43
+ local rc=$?
44
+ find "$T" -mindepth 1 -delete 2>/dev/null; rmdir "$T" 2>/dev/null
45
+ return $rc
46
+ }
47
+ want_block() {
48
+ if run "$1"; then FAIL=$((FAIL+1)); echo " FAIL blocked: $1"
49
+ else PASS=$((PASS+1)); echo " ok blocked: $1"; fi
50
+ }
51
+ want_allow() {
52
+ if run "$1"; then PASS=$((PASS+1)); echo " ok allowed: $1"
53
+ else FAIL=$((FAIL+1)); echo " FAIL allowed: $1"; fi
54
+ }
55
+
56
+ RM="$(printf 'r%s' 'm') -rf "
57
+ echo "destructive-guard-quoted-target"
58
+
59
+ # --- the target is quoted, the deletion is real ------------------------------
60
+ want_block "${RM}\"/etc\""
61
+ want_block "${RM}'/etc'"
62
+ want_block "${RM}\"~\""
63
+ want_block "${RM}'~'"
64
+ want_block "${RM}\"/home/user\""
65
+ want_block "sudo ${RM}\"/var\""
66
+
67
+ # --- unquoted, which already worked ------------------------------------------
68
+ want_block "${RM}~"
69
+ want_block "${RM}/"
70
+ want_block "${RM}/etc"
71
+
72
+ # --- controls: a quoted safe target is still safe ----------------------------
73
+ want_allow "${RM}\"node_modules\""
74
+ want_allow "${RM}'node_modules'"
75
+ want_allow "${RM}\"./build\""
76
+ want_allow "${RM}node_modules"
77
+ want_allow "${RM}./build"
78
+
79
+ # --- controls: quoting it inside another command is still a mention ----------
80
+ want_allow "echo \"${RM}/\""
81
+ want_allow "grep -r \"${RM}/\" ."
82
+ want_allow "git commit -m \"docs: ${RM}/ warning\""
83
+ want_allow "awk '/${RM}/ {print}' h.log"
84
+ want_allow "ls -la"
85
+ want_allow "npm ci && npm run build"
86
+
87
+ echo
88
+ echo "destructive-guard-quoted-target: $PASS passed, $FAIL failed"
89
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,105 @@
1
+ #!/bin/bash
2
+ # destructive-guard: command separators
3
+ #
4
+ # Checks 2, 3 and 7 listed their separators as (^ | ; | && | ||) and left out
5
+ # a bare `&`. `true & git reset --hard` therefore ran unguarded — the same
6
+ # "allow-list of separators" hole that has bitten this guard before.
7
+ # Measured on 2026-07-27: all three checks let a bare & through.
8
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
9
+ GUARD=$(mktemp); trap 'rm -f "$GUARD"' EXIT
10
+ python3 -c "
11
+ import json,sys
12
+ sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$GUARD"
13
+
14
+ PASS=0; FAIL=0
15
+
16
+ check() {
17
+ local desc="$1" cmd="$2" want="$3" # want: 2 = blocked, 0 = allowed
18
+ local payload code
19
+ payload=$(python3 -c '
20
+ import json,sys
21
+ print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$cmd")
22
+ printf '%s' "$payload" | bash "$GUARD" >/dev/null 2>&1
23
+ code=$?
24
+ if [ "$code" = "$want" ]; then
25
+ echo "PASS: $desc"; ((PASS++))
26
+ else
27
+ echo "FAIL: $desc (expected exit $want, got $code)"; ((FAIL++))
28
+ fi
29
+ }
30
+
31
+ # Check 2 — git reset --hard, reachable through every separator
32
+ check "reset: bare & is blocked" 'true & git reset --hard' 2
33
+ check "reset: semicolon is blocked" 'true ; git reset --hard' 2
34
+ check "reset: && is blocked" 'true && git reset --hard' 2
35
+ check "reset: || is blocked" 'false || git reset --hard' 2
36
+ check "reset: start of line is blocked" 'git reset --hard' 2
37
+ check "reset: --soft stays allowed" 'git reset --soft HEAD~1' 0
38
+
39
+ # Check 3 — git clean
40
+ check "clean: bare & is blocked" 'true & git clean -fd' 2
41
+ check "clean: && is blocked" 'true && git clean -fd' 2
42
+ check "clean: start of line is blocked" 'git clean -fd' 2
43
+ check "clean: --dry-run stays allowed" 'git clean --dry-run' 0
44
+
45
+ # Check 7 — git checkout --force
46
+ check "checkout: bare & is blocked" 'true & git checkout -f main' 2
47
+ check "checkout: && is blocked" 'true && git checkout -f main' 2
48
+ check "checkout: plain checkout allowed" 'git checkout main' 0
49
+ check "checkout: plain switch allowed" 'git switch feature' 0
50
+
51
+ # Check 6 — sudo in front of a destructive command.
52
+ #
53
+ # This check anchored its pattern with `^\s*sudo`, so the anchor was applied to
54
+ # the whole command string instead of to each command position. Anything placed
55
+ # after a separator was never examined. It stayed invisible for a long time
56
+ # because Check 1 independently blocks rm on a sensitive path, so the usual
57
+ # probe (`cd /tmp && sudo rm -rf /var`) still came back blocked. The gap only
58
+ # shows on the targets Check 6 alone is responsible for: an ordinary relative
59
+ # path, and dd/mkfs, which no other check looks at.
60
+ # Measured 2026-08-03 against the shipped scripts.json: 7 of 8 such commands
61
+ # exited 0 once a separator was placed in front. Same shape as PR #937.
62
+ check "sudo rm: start of line is blocked" 'sudo rm -rf myproject' 2
63
+ check "sudo rm: && is blocked" 'cd /tmp && sudo rm -rf myproject' 2
64
+ check "sudo rm: semicolon is blocked" 'cd /tmp; sudo rm -rf myproject' 2
65
+ check "sudo rm: bare & is blocked" 'true & sudo rm -rf myproject' 2
66
+ check "sudo rm: || is blocked" 'false || sudo rm -rf myproject' 2
67
+ check "sudo rm -r: && is blocked" 'cd /tmp && sudo rm -r data' 2
68
+ check "sudo dd: && is blocked" 'cd /tmp && sudo dd if=/dev/zero of=/dev/sda' 2
69
+ check "sudo mkfs: && is blocked" 'cd /tmp && sudo mkfs.ext4 /dev/sdb1' 2
70
+ check "sudo chmod 777: && is blocked" 'cd /tmp && sudo chmod -R 777 /opt/app' 2
71
+
72
+ # Closing the hole must not close anything else. sudo on a harmless command is
73
+ # everyday work and stays allowed in every position.
74
+ check "sudo apt stays allowed" 'sudo apt update' 0
75
+ check "sudo apt after && stays allowed" 'cd /tmp && sudo apt update' 0
76
+ check "sudo -l stays allowed" 'sudo -l' 0
77
+ check "sudo systemctl stays allowed" 'cd /srv && sudo systemctl reload nginx' 0
78
+
79
+ # Check 7 — PowerShell Remove-Item.
80
+ #
81
+ # The skip that keeps `echo "Remove-Item -Recurse -Force"` from being read as a
82
+ # deletion was anchored the same way, so it only applied when the command
83
+ # *began* with a string-output command. Put anything in front and the guard
84
+ # blocked a command that only prints text. Measured 2026-08-03: exit 2 on
85
+ # `cd /tmp && echo "..."`. That is the over-tightening side of the same anchor.
86
+ check "PS: bare Remove-Item is blocked" 'Remove-Item -Recurse -Force *' 2
87
+ check "PS: after && is blocked" 'cd /tmp && Remove-Item -Recurse -Force *' 2
88
+ check "PS: after semicolon is blocked" 'cd /tmp; Remove-Item -Recurse -Force *' 2
89
+ check "PS: powershell wrapper is blocked" 'powershell -c "Remove-Item -Recurse -Force C:\\Users\\john"' 2
90
+ check "PS: single file stays allowed" 'Remove-Item ./file.txt' 0
91
+ check "PS: echo of the words allowed" 'echo "Remove-Item -Recurse -Force"' 0
92
+ check "PS: echo after && allowed" 'cd /tmp && echo "Remove-Item -Recurse -Force"' 0
93
+ check "PS: git commit message allowed" 'git commit -m "handle Remove-Item -Recurse -Force"' 0
94
+ check "PS: commit message after && ok" 'cd repo && git commit -m "handle Remove-Item -Recurse -Force"' 0
95
+ check "PS: grep for the words allowed" 'cat notes.txt | grep "Remove-Item -Recurse -Force"' 0
96
+
97
+ # Nothing above should have changed the ordinary allow cases
98
+ check "read-only command allowed" 'grep -r TODO .' 0
99
+ check "safe dir deletion allowed" 'rm -rf node_modules' 0
100
+ check "plain cd compound allowed" 'cd /tmp && ls -la' 0
101
+ check "echo compound allowed" 'echo hello && pwd' 0
102
+
103
+ echo ""
104
+ echo "PASS: $PASS FAIL: $FAIL"
105
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,98 @@
1
+ #!/bin/bash
2
+ # Putting the target in a variable made the deletion invisible.
3
+ #
4
+ # Every check keys on the literal text of the command, so a path held in a
5
+ # variable was never seen:
6
+ #
7
+ # rm -rf /etc blocked
8
+ # D=/etc; rm -rf $D NOT blocked <- same deletion, same command string
9
+ # CMD="rm -rf /"; $CMD NOT blocked
10
+ #
11
+ # Assigning a path to a variable is ordinary shell, not an evasion technique —
12
+ # the same shape as the quoted-target hole (#961): the more carefully someone
13
+ # writes the script, the less protected they were. Measured 2026-08-06 against
14
+ # the shipped guard: three of seven variable forms passed.
15
+ #
16
+ # The fix resolves assignments that are visible in the same command string and
17
+ # runs this same guard against the resolved text (the Check 0z pattern), so no
18
+ # new detection logic is added. A safe value stays safe once expanded, which is
19
+ # what keeps this from becoming "block anything with a $".
20
+ #
21
+ # ORDER MATTERS: Check 0x has to sit before Check 0y. Check 0y returns 0 when no
22
+ # destructive verb appears outside quotes, and `CMD="rm -rf /"; $CMD` has none —
23
+ # so a version placed after 0y never reached the substitution at all. The
24
+ # false-positive protection of 0y still applies, because the child process runs
25
+ # the full file including 0y against the resolved text.
26
+ #
27
+ # Values that only exist at runtime (environment variables inherited from the
28
+ # parent) cannot be resolved statically. That hole stays, and is documented
29
+ # rather than asserted.
30
+
31
+ set -u
32
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
33
+ WORK="$(mktemp -d)"
34
+ trap 'find "$WORK" -mindepth 1 -delete 2>/dev/null; rmdir "$WORK" 2>/dev/null' EXIT
35
+ PASS=0; FAIL=0
36
+
37
+ python3 -c "
38
+ import json,sys
39
+ sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$WORK/dg.sh"
40
+
41
+ run() {
42
+ local T; T="$(mktemp -d)"
43
+ python3 -c '
44
+ import json,sys
45
+ print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]},
46
+ "cwd":sys.argv[2],"session_id":"t"}))' "$1" "$T" \
47
+ | HOME="$T" bash "$WORK/dg.sh" >/dev/null 2>&1
48
+ local rc=$?
49
+ find "$T" -mindepth 1 -delete 2>/dev/null; rmdir "$T" 2>/dev/null
50
+ return $rc
51
+ }
52
+ want_block() {
53
+ if run "$1"; then FAIL=$((FAIL+1)); echo " FAIL blocked: $1"
54
+ else PASS=$((PASS+1)); echo " ok blocked: $1"; fi
55
+ }
56
+ want_allow() {
57
+ if run "$1"; then PASS=$((PASS+1)); echo " ok allowed: $1"
58
+ else FAIL=$((FAIL+1)); echo " FAIL allowed: $1"; fi
59
+ }
60
+
61
+ RM="$(printf 'r%s' 'm') -rf "
62
+ echo "destructive-guard-variable-target"
63
+
64
+ # --- the assignment is visible in the same command string --------------------
65
+ want_block "D=/etc; ${RM}\$D"
66
+ want_block "D=/; ${RM}\"\$D\""
67
+ want_block "D=/var; ${RM}\${D}"
68
+ want_block "CMD=\"${RM}/\"; \$CMD"
69
+ want_block "TARGET=/var; sudo ${RM}\$TARGET"
70
+ want_block "P='/etc'; ${RM}\$P"
71
+
72
+ # --- named environment variables whose value is known ------------------------
73
+ want_block "${RM}\$HOME"
74
+ want_block "${RM}\${HOME}"
75
+ want_block "${RM}\"\$HOME\""
76
+
77
+ # --- controls: wrappers already closed (a break here means the harness moved) -
78
+ want_block "eval \"${RM}/etc\""
79
+ want_block "sh -c \"${RM}/etc\""
80
+
81
+ # --- controls: a safe value stays safe once expanded -------------------------
82
+ want_allow "D=./build; ${RM}\$D"
83
+ want_allow "D=node_modules; ${RM}\$D"
84
+ want_allow "OUT=dist; ${RM}\"\$OUT\""
85
+ want_allow "${RM}\$TMPDIR/work"
86
+
87
+ # --- controls: mentioning is still not running -------------------------------
88
+ want_allow "echo \"${RM}\$HOME\""
89
+ want_allow "D=/etc; echo \"${RM}\$D\""
90
+ want_allow "grep -rn '\$D' ."
91
+
92
+ # --- controls: ordinary commands ---------------------------------------------
93
+ want_allow "ls -la"
94
+ want_allow "npm ci && npm run build"
95
+
96
+ echo
97
+ echo "destructive-guard-variable-target: $PASS passed, $FAIL failed"
98
+ [ "$FAIL" -eq 0 ]