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.
- package/.claude-plugin/marketplace.json +72 -19
- package/.claude-plugin/plugin.json +1 -1
- package/CONTRIBUTING.md +7 -2
- package/COOKBOOK.md +50 -46
- package/LICENSE +21 -0
- package/MIGRATION.md +8 -8
- package/README.md +419 -512
- package/SAFETY_CHECKLIST.md +15 -7
- package/SERVICES.md +194 -0
- package/SETTINGS_REFERENCE.md +236 -17
- package/SKILL.md +5 -5
- package/TROUBLESHOOTING.md +35 -14
- package/action.yml +12 -4
- package/audit/README.md +84 -0
- package/audit/audit-checklist.md +152 -0
- package/audit/boundary-selftest.sh +85 -0
- package/audit/boundary.sh +123 -0
- package/audit/count-hooks.py +42 -0
- package/audit/find-dead-hooks.sh +82 -0
- package/audit/find-unfirable-rules.sh +142 -0
- package/audit/fire.sh +97 -0
- package/audit/selftest.sh +42 -0
- package/audit/unfirable-selftest.sh +81 -0
- package/audit-web/index.html +9 -9
- package/examples/README.md +54 -17
- package/examples/account-billing-log.sh +98 -0
- package/examples/account-routing-preflight.sh +123 -0
- package/examples/agent-sdk-credit-pool-monitor.sh +145 -0
- package/examples/agent-view-quota-decrement.sh +32 -0
- package/examples/agent-view-quota-warn.sh +94 -0
- package/examples/agents-md-edit-drift-warner.sh +223 -0
- package/examples/agents-md-loader.sh +160 -0
- package/examples/agents-md-sync-checker.sh +102 -0
- package/examples/ai-slop-punctuation-arrest.sh +210 -0
- package/examples/allowlist.sh +70 -10
- package/examples/always-allow-pattern-suggester.sh +125 -0
- package/examples/ansible-vault-guard.sh +2 -1
- package/examples/anthropic-base-url-guard.sh +76 -0
- package/examples/api-busyloop-guard.sh +123 -0
- package/examples/api-endpoint-guard.sh +12 -0
- package/examples/api-key-in-url-guard.sh +17 -1
- package/examples/api-rate-limit-guard.sh +36 -1
- package/examples/api-rate-limit-tracker.sh +12 -0
- package/examples/articulated-scope-capture.sh +101 -0
- package/examples/askuserquestion-autonomy-gate.sh +102 -0
- package/examples/attachment-traversal-guard.sh +118 -0
- package/examples/aup-block-pattern-logger.sh +161 -0
- package/examples/aup-false-positive-helper.sh +124 -0
- package/examples/aup-large-tool-output-warner.sh +282 -0
- package/examples/aup-retry-loop-guard.sh +229 -0
- package/examples/auth-expiry-reminder.sh +157 -0
- package/examples/auth-macos-sleep-detector.sh +185 -0
- package/examples/auth-path-detector.sh +171 -0
- package/examples/auth-status-checker.sh +157 -0
- package/examples/authorized-reconfirmation-detector.sh +195 -0
- package/examples/auto-approve-build.sh +39 -0
- package/examples/auto-approve-cargo.sh +31 -1
- package/examples/auto-approve-docker.sh +35 -0
- package/examples/auto-approve-git-read.sh +37 -14
- package/examples/auto-approve-go.sh +30 -1
- package/examples/auto-approve-gradle.sh +29 -1
- package/examples/auto-approve-make.sh +29 -1
- package/examples/auto-approve-maven.sh +29 -1
- package/examples/auto-approve-python.sh +41 -1
- package/examples/auto-approve-readonly-tools.sh +1 -0
- package/examples/auto-approve-readonly.sh +110 -33
- package/examples/auto-approve-ssh.sh +30 -1
- package/examples/auto-approve-test.sh +44 -0
- package/examples/auto-checkpoint.sh +1 -1
- package/examples/auto-compact-prep.sh +0 -0
- package/examples/auto-git-checkpoint.sh +0 -0
- package/examples/auto-mode-safe-commands.sh +53 -1
- package/examples/auto-mode-safety-enforcer.sh +151 -4
- package/examples/auto-push-session-branch.sh +22 -0
- package/examples/aws-production-guard.sh +13 -1
- package/examples/aws-region-guard.sh +1 -1
- package/examples/background-cost-launch-guard.sh +82 -0
- package/examples/background-task-guard.sh +12 -0
- package/examples/backup-before-refactor.sh +0 -0
- package/examples/banned-command-guard.sh +12 -0
- package/examples/bash-allowlist-secondary-check.sh +157 -0
- package/examples/bash-domain-allowlist.sh +12 -0
- package/examples/bash-fanout-bounded-rewriter.sh +191 -0
- package/examples/bash-heuristic-approver.sh +112 -10
- package/examples/bash-project-fence.sh +194 -0
- package/examples/bash-safety-auto-deny.sh +12 -0
- package/examples/bash-secret-output-detector.sh +44 -3
- package/examples/bash-trace-guard.sh +12 -0
- package/examples/bashrc-safety-check.sh +0 -0
- package/examples/bg-permission-prompt-warner.sh +182 -0
- package/examples/bg-task-cooldown-guard.sh +12 -0
- package/examples/binary-read-detector.sh +135 -0
- package/examples/binary-upload-guard.sh +12 -0
- package/examples/block-database-wipe.sh +35 -10
- package/examples/branch-name-check.sh +8 -3
- package/examples/branch-naming-convention.sh +0 -0
- package/examples/broad-find-guard.sh +12 -0
- package/examples/broad-prefix-session-trap-warner.sh +106 -0
- package/examples/bulk-file-delete-guard.sh +45 -0
- package/examples/bypass-mode-effective-verifier.sh +203 -0
- package/examples/cache-creation-drift-detector.sh +120 -0
- package/examples/cache-residue-detector.sh +195 -0
- package/examples/cache-tier-logger.sh +70 -0
- package/examples/cache-ttl-eviction-detector.sh +149 -0
- package/examples/cargo-publish-guard.sh +14 -1
- package/examples/case-insensitive-path-guard.sh +21 -2
- package/examples/case-sensitive-guard.sh +23 -2
- package/examples/cch-cache-guard.sh +0 -0
- package/examples/cch-sentinel-precommit-guard.sh +47 -0
- package/examples/check-abort-controller.sh +1 -1
- package/examples/check-accessibility.sh +0 -0
- package/examples/check-aria-labels.sh +0 -0
- package/examples/check-before-act-enforcer.sh +12 -0
- package/examples/check-charset-meta.sh +0 -0
- package/examples/check-cookie-flags.sh +0 -0
- package/examples/check-cors-config.sh +0 -0
- package/examples/check-csp-headers.sh +0 -0
- package/examples/check-csrf-protection.sh +0 -0
- package/examples/check-debounce.sh +1 -1
- package/examples/check-dependency-age.sh +0 -0
- package/examples/check-dependency-license.sh +0 -0
- package/examples/check-dockerfile-best-practice.sh +0 -0
- package/examples/check-error-boundaries.sh +0 -0
- package/examples/check-error-class.sh +1 -1
- package/examples/check-error-handling.sh +0 -0
- package/examples/check-error-logging.sh +1 -1
- package/examples/check-error-message.sh +0 -0
- package/examples/check-error-stack.sh +0 -0
- package/examples/check-favicon.sh +0 -0
- package/examples/check-git-hooks-compat.sh +0 -0
- package/examples/check-gitattributes.sh +0 -0
- package/examples/check-https-redirect.sh +0 -0
- package/examples/check-input-validation.sh +0 -0
- package/examples/check-lang-attribute.sh +0 -0
- package/examples/check-npm-scripts-exist.sh +0 -0
- package/examples/check-package-size.sh +0 -0
- package/examples/check-port-availability.sh +0 -0
- package/examples/check-promise-all.sh +1 -1
- package/examples/check-rate-limiting.sh +0 -0
- package/examples/check-return-types.sh +0 -0
- package/examples/check-semantic-versioning.sh +0 -0
- package/examples/check-suspense-fallback.sh +1 -1
- package/examples/check-test-exists.sh +0 -0
- package/examples/check-test-naming.sh +0 -0
- package/examples/check-timeout-cleanup.sh +1 -1
- package/examples/check-tls-version.sh +0 -0
- package/examples/check-unsubscribe.sh +1 -1
- package/examples/check-viewport-meta.sh +0 -0
- package/examples/check-worker-terminate.sh +1 -1
- package/examples/checkpoint-tamper-guard.sh +12 -0
- package/examples/chmod-guard.sh +12 -0
- package/examples/chown-guard.sh +24 -0
- package/examples/ci-workflow-guard.sh +6 -1
- package/examples/claim-verify-detector.sh +109 -0
- package/examples/claim-vs-caveat-checker.sh +77 -0
- package/examples/classifier-fallback-allow.sh +114 -40
- package/examples/claude-cache-gc.sh +1 -0
- package/examples/claude-code-version-pin-advisor.sh +183 -0
- package/examples/claude-md-reinjector.sh +129 -0
- package/examples/claude-md-size-monitor.sh +66 -0
- package/examples/claude-update-budget-guard.sh +123 -0
- package/examples/claude-update-smart.sh +113 -0
- package/examples/claudeignore-enforce-guard.sh +12 -0
- package/examples/claudemd-enforcer.sh +0 -0
- package/examples/claudemd-tool-prohibition.sh +128 -0
- package/examples/clear-command-confirm-guard.sh +32 -15
- package/examples/cli-config-pinning-detector.sh +162 -0
- package/examples/cliff-countdown-advisor.sh +96 -0
- package/examples/clipboard-secret-guard.sh +12 -0
- package/examples/closure-word-verify-gate.sh +150 -0
- package/examples/cloud-cli-guard.sh +39 -2
- package/examples/commit-all-scope-guard.sh +44 -0
- package/examples/commit-message-check.sh +1 -1
- package/examples/commit-message-quality.sh +6 -1
- package/examples/commitment-carry-forward-arrest.sh +361 -0
- package/examples/compact-alert-notification.sh +0 -0
- package/examples/compact-circuit-breaker.sh +72 -0
- package/examples/compact-dispatch-watchdog.sh +149 -0
- package/examples/completion-claim-without-verification-detector.sh +207 -0
- package/examples/composer-guard.sh +12 -0
- package/examples/compound-bash-permission-resolver.sh +156 -0
- package/examples/compound-command-allow.sh +1 -1
- package/examples/compound-command-deny-enforcer.sh +183 -0
- package/examples/compound-inject-guard.sh +12 -0
- package/examples/concurrent-edit-lock.sh +12 -0
- package/examples/conflict-marker-guard.sh +12 -0
- package/examples/consecutive-error-breaker.sh +0 -0
- package/examples/console-log-count.sh +1 -0
- package/examples/context-compact-advisor.sh +29 -2
- package/examples/context-length-budget.sh +69 -0
- package/examples/context-threshold-alert.sh +12 -0
- package/examples/context-usage-drift-alert.sh +41 -13
- package/examples/conversation-history-guard.sh +12 -0
- package/examples/core-file-protect-guard.sh +12 -0
- package/examples/cors-star-warn.sh +0 -0
- package/examples/cost-incident-self-audit.sh +162 -0
- package/examples/cowork-claude-md-load-checker.sh +100 -0
- package/examples/cowork-fuse-staleness-watcher.sh +140 -0
- package/examples/cowork-hook-absence-warner.sh +167 -0
- package/examples/cowork-model-picker-advisor.sh +115 -0
- package/examples/credential-exfil-guard.sh +65 -4
- package/examples/credential-file-cat-guard.sh +17 -1
- package/examples/cron-create-receipt.sh +112 -0
- package/examples/cron-modification-guard.sh +12 -0
- package/examples/cross-product-mcp-spawn-detector.sh +178 -0
- package/examples/cwd-project-boundary-guard.sh +0 -0
- package/examples/daemon-zombie-worker-surfacer.sh +118 -0
- package/examples/daily-cost-guard.sh +164 -0
- package/examples/daily-usage-tracker.sh +0 -0
- package/examples/dangerous-pip-flag-guard.sh +12 -0
- package/examples/db-connect-guard.sh +13 -1
- package/examples/denied-action-retry-guard.sh +12 -0
- package/examples/deny-bypass-detector.sh +12 -0
- package/examples/deny-rule-integrity-verifier.sh +181 -0
- package/examples/dependency-install-guard.sh +12 -0
- package/examples/deploy-guard.sh +14 -2
- package/examples/deploy-path-verify-guard.sh +12 -0
- package/examples/deployment-readback-gate.sh +135 -0
- package/examples/deployment-readback-gh-adapter.sh +247 -0
- package/examples/deployment-verify-guard.sh +25 -2
- package/examples/destructive-db-script-write-guard.sh +166 -0
- package/examples/destructive-migration-write-guard.sh +163 -0
- package/examples/diff-size-guard.sh +12 -0
- package/examples/disabled-feature-toggle-advisor.sh +88 -0
- package/examples/disk-partition-guard.sh +12 -0
- package/examples/dispatch-allowlist-preflight.sh +301 -0
- package/examples/dispatch-liveness-watchdog.sh +216 -0
- package/examples/dispatch-receipt.sh +174 -0
- package/examples/django-migrate-guard.sh +12 -0
- package/examples/dns-config-guard.sh +12 -0
- package/examples/docker-dangerous-guard.sh +12 -0
- package/examples/docker-volume-guard.sh +0 -0
- package/examples/dockerfile-latest-guard.sh +1 -0
- package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
- package/examples/dotenv-commit-guard.sh +12 -0
- package/examples/dotenv-read-guard.sh +12 -0
- package/examples/dotfile-protection-guard.sh +12 -0
- package/examples/dotnet-build-on-edit.sh +1 -1
- package/examples/drizzle-migrate-guard.sh +27 -2
- package/examples/echo-probe-spam-detector.sh +176 -0
- package/examples/edit-counter-test-gate.sh +12 -0
- package/examples/edit-error-counter.sh +1 -1
- package/examples/edit-guard.sh +12 -0
- package/examples/edit-old-string-validator.sh +12 -0
- package/examples/edit-quote-ambiguity-guard.sh +97 -0
- package/examples/edit-retry-loop-guard.sh +0 -0
- package/examples/edit-verify.sh +0 -0
- package/examples/env-inline-secret-guard.sh +14 -2
- package/examples/env-naming-convention.sh +0 -0
- package/examples/env-prod-guard.sh +0 -0
- package/examples/env-required-check.sh +0 -0
- package/examples/env-source-guard.sh +12 -0
- package/examples/env-var-check.sh +24 -1
- package/examples/ephemeral-container-detector.sh +147 -0
- package/examples/error-memory-guard.sh +12 -0
- package/examples/evidence-claim-gate.sh +187 -0
- package/examples/exploration-budget-guard.sh +89 -0
- package/examples/expo-eject-guard.sh +13 -0
- package/examples/extended-thinking-loop-guard.sh +139 -0
- package/examples/extended-thinking-resume-warning.sh +119 -0
- package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
- package/examples/fabricated-command-detector.sh +145 -0
- package/examples/false-disk-full-guard.sh +63 -0
- package/examples/feature-deprecation-detector.sh +109 -0
- package/examples/file-change-tracker.sh +1 -1
- package/examples/file-change-undo-tracker.sh +0 -0
- package/examples/file-edit-backup.sh +63 -14
- package/examples/file-reference-check.sh +0 -0
- package/examples/file-size-limit.sh +12 -0
- package/examples/financial-operation-guard.sh +12 -0
- package/examples/firewall-guard.sh +12 -0
- package/examples/fish-shell-wrapper.sh +125 -7
- package/examples/five-hundred-milestone.sh +1 -0
- package/examples/flask-static-route-guard.sh +89 -0
- package/examples/forbidden-response-phrase-detector.sh +161 -0
- package/examples/gem-push-guard.sh +13 -0
- package/examples/gh-cli-destructive-guard.sh +13 -1
- package/examples/git-checkout-safety-guard.sh +12 -0
- package/examples/git-checkout-uncommitted-guard.sh +12 -0
- package/examples/git-config-guard.sh +12 -0
- package/examples/git-crypt-worktree-guard.sh +12 -0
- package/examples/git-filter-repo-guard.sh +56 -0
- package/examples/git-history-rewrite-guard.sh +12 -0
- package/examples/git-hook-bypass-guard.sh +0 -0
- package/examples/git-maintenance-guard.sh +83 -0
- package/examples/git-merge-conflict-prevent.sh +0 -0
- package/examples/git-message-length-check.sh +0 -0
- package/examples/git-message-length.sh +0 -0
- package/examples/git-operations-require-approval.sh +68 -14
- package/examples/git-pack-temp-cleanup-guard.sh +102 -0
- package/examples/git-push-blast-radius-guard.sh +218 -0
- package/examples/git-remote-guard.sh +24 -3
- package/examples/git-rm-orphan-wipe-guard.sh +85 -0
- package/examples/git-stash-before-checkout.sh +12 -0
- package/examples/git-stash-before-danger.sh +0 -0
- package/examples/git-submodule-guard.sh +69 -2
- package/examples/git-tag-guard.sh +12 -0
- package/examples/github-actions-secret-guard.sh +0 -0
- package/examples/gitignore-check.sh +0 -0
- package/examples/gitops-drift-guard.sh +12 -0
- package/examples/go-mod-tidy-warn.sh +1 -0
- package/examples/go-vet-after-edit.sh +12 -0
- package/examples/goal-iteration-limit-warner.sh +152 -0
- package/examples/grep-nul-false-negative-guard.sh +30 -0
- package/examples/growthbook-flag-monitor.sh +257 -0
- package/examples/hallucination-url-check.sh +1 -1
- package/examples/halt-signal-detector.sh +135 -0
- package/examples/handoff-on-clear.sh +65 -0
- package/examples/hardcoded-ip-guard.sh +1 -0
- package/examples/headless-empty-result-guard.sh +0 -0
- package/examples/headless-stop-guard.sh +0 -0
- package/examples/helm-install-guard.sh +2 -1
- package/examples/home-critical-bash-guard.sh +17 -1
- package/examples/hook-debug-wrapper.sh +6 -2
- package/examples/hook-permission-fixer.sh +0 -0
- package/examples/hook-self-disable-detector.sh +99 -0
- package/examples/hook-stdout-sanitizer.sh +6 -2
- package/examples/hook-tamper-guard.sh +12 -0
- package/examples/idle-session-cost-alert.sh +0 -0
- package/examples/image-dimension-guard.sh +109 -0
- package/examples/image-file-validator.sh +0 -0
- package/examples/iteration-quality-degradation-detector.sh +170 -0
- package/examples/java-compile-on-edit.sh +1 -1
- package/examples/json-syntax-check.sh +0 -0
- package/examples/k8s-production-guard.sh +13 -1
- package/examples/kill-process-guard.sh +12 -0
- package/examples/kubernetes-guard.sh +13 -1
- package/examples/laravel-artisan-guard.sh +13 -0
- package/examples/large-file-guard.sh +1 -1
- package/examples/log-level-guard.sh +0 -0
- package/examples/log-truncation-guard.sh +12 -0
- package/examples/long-session-malformed-tool-call-detector.sh +183 -0
- package/examples/loop-detector.sh +12 -0
- package/examples/magic-number-warn.sh +1 -0
- package/examples/main-branch-warn.sh +12 -0
- package/examples/markdown-link-check.sh +0 -0
- package/examples/max-concurrent-agents.sh +12 -0
- package/examples/max-edit-size-guard.sh +13 -0
- package/examples/max-file-count-guard.sh +0 -0
- package/examples/max-file-delete-count.sh +0 -0
- package/examples/max-function-length.sh +1 -0
- package/examples/max-import-count.sh +0 -0
- package/examples/max-subagent-count.sh +0 -0
- package/examples/mcp-config-freeze.sh +12 -0
- package/examples/mcp-config-poisoning-audit.sh +150 -0
- package/examples/mcp-data-boundary.sh +1 -1
- package/examples/mcp-misdiagnosis-arrest.sh +209 -0
- package/examples/mcp-orphan-leak-warner.sh +49 -0
- package/examples/mcp-permissions-ask-warner.sh +151 -0
- package/examples/mcp-routine-approval-detector.sh +154 -0
- package/examples/mcp-server-allowlist.sh +12 -0
- package/examples/mcp-server-guard.sh +12 -0
- package/examples/mcp-startup-bloat-detector.sh +87 -0
- package/examples/mcp-stdio-compatibility-test.sh +153 -0
- package/examples/mcp-tool-audit-log.sh +0 -0
- package/examples/mcp-tool-guard.sh +101 -1
- package/examples/mcp-warmup-wait.sh +0 -0
- package/examples/memory-chain-audit.sh +56 -0
- package/examples/memory-orphan-detector.sh +188 -0
- package/examples/memory-write-guard.sh +99 -17
- package/examples/migration-verify-guard.sh +12 -0
- package/examples/model-swap-suggester.sh +177 -0
- package/examples/model-version-alert.sh +5 -1
- package/examples/model-version-lock.sh +63 -0
- package/examples/move-delete-sequence-guard.sh +33 -2
- package/examples/multi-file-plan-routing-gate.sh +192 -0
- package/examples/multi-vendor-concurrent-warner.sh +108 -0
- package/examples/multi-window-auth-drift-detector.sh +183 -0
- package/examples/multiline-command-approver.sh +161 -23
- package/examples/nested-background-agent-guard.sh +109 -0
- package/examples/nested-spawn-inflight-guard.sh +178 -0
- package/examples/network-exfil-guard.sh +12 -0
- package/examples/network-guard.sh +12 -0
- package/examples/network-interface-guard.sh +12 -0
- package/examples/nextjs-env-guard.sh +1 -1
- package/examples/no-absolute-import.sh +0 -0
- package/examples/no-alert-confirm-prompt.sh +0 -0
- package/examples/no-anonymous-default-export.sh +0 -0
- package/examples/no-any-type.sh +0 -0
- package/examples/no-any-typescript.sh +1 -0
- package/examples/no-ask-human.sh +12 -0
- package/examples/no-assignment-in-condition.sh +0 -0
- package/examples/no-base64-exfil.sh +12 -0
- package/examples/no-callback-hell.sh +0 -0
- package/examples/no-circular-dependency.sh +0 -0
- package/examples/no-cleartext-storage.sh +0 -0
- package/examples/no-commented-code.sh +0 -0
- package/examples/no-commit-fixup.sh +0 -0
- package/examples/no-console-assert.sh +0 -0
- package/examples/no-console-error-swallow.sh +0 -0
- package/examples/no-console-in-prod.sh +0 -0
- package/examples/no-console-log-commit.sh +12 -0
- package/examples/no-console-log.sh +0 -0
- package/examples/no-console-time.sh +0 -0
- package/examples/no-cors-wildcard.sh +4 -1
- package/examples/no-curl-upload.sh +0 -0
- package/examples/no-dangerouslySetInnerHTML.sh +0 -0
- package/examples/no-dangling-await.sh +1 -0
- package/examples/no-debug-commit.sh +12 -0
- package/examples/no-debug-in-commit.sh +0 -0
- package/examples/no-deep-nesting.sh +0 -0
- package/examples/no-deep-relative-import.sh +1 -0
- package/examples/no-default-credentials.sh +0 -0
- package/examples/no-deploy-friday.sh +13 -1
- package/examples/no-disabled-test.sh +0 -0
- package/examples/no-document-write.sh +0 -0
- package/examples/no-empty-function.sh +0 -0
- package/examples/no-eval-in-template.sh +0 -0
- package/examples/no-eval-template.sh +3 -1
- package/examples/no-eval.sh +0 -0
- package/examples/no-exec-user-input.sh +0 -0
- package/examples/no-fixme-ship.sh +12 -0
- package/examples/no-floating-promises.sh +0 -0
- package/examples/no-force-flag.sh +22 -5
- package/examples/no-force-install.sh +0 -0
- package/examples/no-git-amend.sh +12 -0
- package/examples/no-git-rebase-public.sh +0 -0
- package/examples/no-global-install.sh +12 -0
- package/examples/no-global-state.sh +0 -0
- package/examples/no-hardcoded-port.sh +1 -0
- package/examples/no-hardcoded-url.sh +0 -0
- package/examples/no-helmet-missing.sh +0 -0
- package/examples/no-http-url.sh +1 -0
- package/examples/no-http-without-https.sh +0 -0
- package/examples/no-inline-style.sh +0 -0
- package/examples/no-inline-styles.sh +1 -0
- package/examples/no-innerhtml.sh +0 -0
- package/examples/no-install-global.sh +12 -0
- package/examples/no-jwt-in-url.sh +0 -0
- package/examples/no-large-commit.sh +0 -0
- package/examples/no-localhost-expose.sh +0 -0
- package/examples/no-magic-number.sh +0 -0
- package/examples/no-md5-sha1.sh +0 -0
- package/examples/no-mixed-line-endings.sh +8 -1
- package/examples/no-mutation-in-reducer.sh +0 -0
- package/examples/no-nested-ternary.sh +0 -0
- package/examples/no-network-exfil.sh +0 -0
- package/examples/no-open-redirect.sh +0 -0
- package/examples/no-output-truncation.sh +12 -0
- package/examples/no-package-downgrade.sh +0 -0
- package/examples/no-package-lock-edit.sh +12 -0
- package/examples/no-path-join-user-input.sh +0 -0
- package/examples/no-port-bind.sh +0 -0
- package/examples/no-process-exit.sh +0 -0
- package/examples/no-prototype-pollution.sh +0 -0
- package/examples/no-push-without-ci.sh +0 -0
- package/examples/no-push-without-tests.sh +12 -0
- package/examples/no-raw-password-in-url.sh +0 -0
- package/examples/no-root-user-docker.sh +1 -0
- package/examples/no-root-write.sh +12 -0
- package/examples/no-secrets-in-args.sh +4 -1
- package/examples/no-secrets-in-logs.sh +0 -0
- package/examples/no-sensitive-log.sh +0 -0
- package/examples/no-sleep-in-hooks.sh +0 -0
- package/examples/no-star-import-python.sh +1 -0
- package/examples/no-string-concat-sql.sh +0 -0
- package/examples/no-sudo-guard.sh +12 -0
- package/examples/no-sync-fs.sh +0 -0
- package/examples/no-todo-in-merge.sh +0 -0
- package/examples/no-todo-in-production.sh +1 -0
- package/examples/no-todo-without-issue.sh +0 -0
- package/examples/no-unused-import.sh +0 -0
- package/examples/no-var-keyword.sh +0 -0
- package/examples/no-verify-blocker.sh +12 -0
- package/examples/no-wget-piped-bash.sh +12 -0
- package/examples/no-wildcard-cors.sh +0 -0
- package/examples/no-wildcard-delete.sh +0 -0
- package/examples/no-wildcard-import.sh +0 -0
- package/examples/no-with-statement.sh +0 -0
- package/examples/no-write-outside-src.sh +0 -0
- package/examples/no-xml-external-entity.sh +0 -0
- package/examples/non-english-quality-warner.sh +156 -0
- package/examples/notify-waiting.sh +1 -1
- package/examples/npm-audit-warn.sh +0 -0
- package/examples/npm-global-install-guard.sh +12 -0
- package/examples/npm-publish-guard.sh +12 -0
- package/examples/npm-script-injection.sh +0 -0
- package/examples/npm-supply-chain-guard.sh +0 -0
- package/examples/nuxt-config-guard.sh +1 -0
- package/examples/oauth-refresh-monitor.sh +210 -0
- package/examples/opus-degradation-tracker.sh +187 -0
- package/examples/opus48-routine-task-warning.sh +196 -0
- package/examples/opus48-thinking-wedge-advisor.sh +143 -0
- package/examples/output-credential-scan.sh +1 -1
- package/examples/output-secret-mask.sh +31 -9
- package/examples/output-token-spike-detector.sh +145 -0
- package/examples/package-json-guard.sh +12 -0
- package/examples/package-lock-frozen.sh +12 -0
- package/examples/parallel-batch-size-limiter.sh +121 -0
- package/examples/parallel-cascade-detector.sh +116 -0
- package/examples/partial-view-claim-arrest.sh +174 -0
- package/examples/path-deny-bash-guard.sh +12 -0
- package/examples/path-traversal-guard.sh +12 -0
- package/examples/per-prompt-token-cap.sh +124 -0
- package/examples/permission-audit-log.sh +1 -1
- package/examples/permission-denial-enforcer.sh +12 -0
- package/examples/permission-entry-validator.sh +0 -0
- package/examples/persisted-1m-model-advisor.sh +88 -0
- package/examples/php-lint-on-edit.sh +1 -1
- package/examples/pii-upload-guard.sh +12 -0
- package/examples/pip-publish-guard.sh +13 -0
- package/examples/pip-requirements-guard.sh +12 -0
- package/examples/pip-venv-required.sh +12 -0
- package/examples/plan-mode-edit-guard.sh +12 -0
- package/examples/plan-mode-enforcer.sh +12 -0
- package/examples/plan-mode-strict-guard.sh +12 -0
- package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
- package/examples/plugin-process-cleanup.sh +0 -0
- package/examples/polyglot-rm-guard.sh +12 -0
- package/examples/post-compact-safety.sh +12 -0
- package/examples/post-edit-disk-verify.sh +152 -0
- package/examples/powershell-remove-item-guard.sh +85 -0
- package/examples/pr-description-check.sh +0 -0
- package/examples/pr-duplicate-guard.sh +13 -0
- package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
- package/examples/pre-compact-knowledge-save.sh +0 -0
- package/examples/pre-compact-transcript-backup.sh +0 -0
- package/examples/pre-execution-claim-detector.sh +179 -0
- package/examples/prefer-builtin-tools.sh +10 -1
- package/examples/prefer-const.sh +0 -0
- package/examples/prefer-dedicated-tools.sh +12 -0
- package/examples/prefer-optional-chaining.sh +0 -0
- package/examples/prisma-migrate-guard.sh +24 -7
- package/examples/production-port-kill-guard.sh +12 -0
- package/examples/prompt-injection-guard.sh +2 -1
- package/examples/prompt-usage-logger.sh +0 -0
- package/examples/protect-claudemd.sh +12 -0
- package/examples/protect-dotfiles.sh +12 -0
- package/examples/proxy-capture-suggester.sh +159 -0
- package/examples/public-artefact-socratic-narrowing.sh +232 -0
- package/examples/public-repo-push-guard.sh +12 -0
- package/examples/push-requires-test-pass-record.sh +0 -0
- package/examples/push-requires-test-pass.sh +12 -0
- package/examples/quota-anomaly-detector.sh +173 -0
- package/examples/quota-reset-audit.sh +58 -0
- package/examples/quoted-flag-approver.sh +99 -10
- package/examples/rails-migration-guard.sh +12 -0
- package/examples/rate-limit-guard.sh +0 -0
- package/examples/read-all-files-enforcer.sh +0 -0
- package/examples/read-budget-guard.sh +12 -0
- package/examples/read-loop-detector.sh +59 -0
- package/examples/read-once-guard.sh +96 -0
- package/examples/read-only-mode.sh +12 -0
- package/examples/readme-exists-check.sh +0 -0
- package/examples/record-read-coverage.sh +73 -0
- package/examples/redirect-fragment-warner.sh +149 -0
- package/examples/redis-flushall-guard.sh +13 -0
- package/examples/redundant-read-blocker.sh +132 -0
- package/examples/refusal-arrest-gate.sh +248 -0
- package/examples/registry-publish-guard.sh +13 -1
- package/examples/remote-control-billing-classifier.sh +135 -0
- package/examples/replace-all-guard.sh +12 -0
- package/examples/repo-visibility-guard.sh +12 -0
- package/examples/reroute-after-block-guard.sh +150 -0
- package/examples/response-budget-guard.sh +0 -0
- package/examples/resume-drift-watcher.sh +57 -0
- package/examples/rg-replace-flag-detector.sh +125 -0
- package/examples/rhetorical-verification-prompt-detector.sh +102 -0
- package/examples/ripgrep-permission-fix.sh +0 -0
- package/examples/rm-safety-net.sh +151 -8
- package/examples/role-tool-guard.sh +12 -0
- package/examples/route-handler-emptiness-gate.sh +324 -0
- package/examples/ruby-lint-on-edit.sh +1 -1
- package/examples/runtime-binary-change-detector.sh +102 -0
- package/examples/same-command-repeat-detector.sh +196 -0
- package/examples/same-correction-arrest.sh +169 -0
- package/examples/sandbox-denywrite-enforcer.sh +78 -0
- package/examples/sandbox-relative-path-audit.sh +83 -25
- package/examples/sandbox-write-verify.sh +12 -0
- package/examples/schema-migration-guard.sh +0 -0
- package/examples/scope-expansion-receipt.sh +178 -0
- package/examples/scope-guard.sh +88 -9
- package/examples/secret-file-read-guard.sh +12 -0
- package/examples/secret-file-write-guard.sh +150 -0
- package/examples/self-modify-bypass-guard.sh +0 -0
- package/examples/sensitive-file-read-guard.sh +23 -3
- package/examples/sensitive-log-guard.sh +1 -0
- package/examples/server-side-prompt-injection-detector.sh +69 -0
- package/examples/session-agent-cost-limiter.sh +12 -0
- package/examples/session-backup-on-start.sh +1 -1
- package/examples/session-cost-alert.sh +12 -0
- package/examples/session-drift-guard.sh +12 -0
- package/examples/session-duration-guard.sh +25 -2
- package/examples/session-end-logger.sh +0 -0
- package/examples/session-health-monitor.sh +0 -0
- package/examples/session-index-repair.sh +1 -1
- package/examples/session-memory-watchdog.sh +1 -0
- package/examples/session-permission-reset-guard.sh +12 -0
- package/examples/session-persistence-verifier.sh +93 -0
- package/examples/session-plugin-pin-watch.sh +68 -0
- package/examples/session-rate-monitor.sh +176 -0
- package/examples/session-resume-env-fix.sh +0 -0
- package/examples/session-start-quota-status.sh +193 -0
- package/examples/session-start-safety-check.sh +55 -3
- package/examples/session-state-saver.sh +0 -0
- package/examples/session-summary-stop.sh +1 -1
- package/examples/session-summary.sh +0 -0
- package/examples/session-token-counter.sh +1 -1
- package/examples/settings-hooks-key-restorer.sh +99 -0
- package/examples/settings-json-health-check.sh +57 -0
- package/examples/settings-json-model-guard.sh +0 -0
- package/examples/settings-regression-tester.sh +188 -0
- package/examples/shell-config-truncation-guard.sh +12 -0
- package/examples/shell-wrapper-guard.sh +12 -0
- package/examples/skill-cumulative-size-detector.sh +104 -0
- package/examples/skill-description-drop-detector.sh +148 -0
- package/examples/skill-gate.sh +0 -0
- package/examples/skill-truncation-detector.sh +154 -0
- package/examples/skills-context-recorder.sh +167 -0
- package/examples/skills-load-verifier.sh +96 -0
- package/examples/skills-settings-validator.sh +139 -0
- package/examples/sonnet-45-deprecation-helper.sh +85 -0
- package/examples/spec-file-scope-guard.sh +12 -0
- package/examples/spring-profile-guard.sh +1 -0
- package/examples/spurious-malformed-notice-detector.sh +247 -0
- package/examples/sql-bulk-delete-warn.sh +88 -0
- package/examples/sql-injection-detect.sh +0 -0
- package/examples/ssh-key-protect.sh +12 -0
- package/examples/staged-secret-scan.sh +22 -1
- package/examples/stale-temp-settings-detector.sh +86 -0
- package/examples/standing-rule-session-surfacer.sh +137 -0
- package/examples/stop-hook-sigterm-wrapper.sh +182 -0
- package/examples/stop-transcript-write-health.sh +64 -0
- package/examples/strict-allowlist.sh +57 -15
- package/examples/strip-coauthored-by.sh +50 -10
- package/examples/subagent-blast-radius-guard.sh +184 -0
- package/examples/subagent-boundary-precheck.sh +126 -0
- package/examples/subagent-budget-guard.sh +12 -0
- package/examples/subagent-claudemd-inject.sh +0 -0
- package/examples/subagent-closure-verify-gate.sh +164 -0
- package/examples/subagent-destructive-git-guard.sh +120 -0
- package/examples/subagent-error-detector.sh +0 -0
- package/examples/subagent-forged-system-reminder-guard.sh +156 -0
- package/examples/subagent-identity-leak-guard.sh +102 -0
- package/examples/subagent-identity-reassertion.sh +51 -0
- package/examples/subagent-inheritance-tester.sh +179 -0
- package/examples/subagent-permission-mode-guard.sh +110 -0
- package/examples/subagent-scope-guard.sh +12 -0
- package/examples/subagent-spawn-verification-enforcer.sh +102 -0
- package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
- package/examples/subagent-tool-call-limiter.sh +87 -15
- package/examples/subcommand-chain-guard.sh +12 -0
- package/examples/subscription-api-billing-warner.sh +160 -0
- package/examples/subscription-bypass-detector.sh +152 -0
- package/examples/svelte-lint-on-edit.sh +1 -0
- package/examples/swift-build-on-edit.sh +1 -1
- package/examples/symlink-guard.sh +27 -2
- package/examples/symlink-protect.sh +1 -0
- package/examples/system-dir-protection-guard.sh +73 -8
- package/examples/system-message-workaround.sh +38 -13
- package/examples/system-package-guard.sh +12 -0
- package/examples/systemd-service-guard.sh +12 -0
- package/examples/task-integrity-guard.sh +12 -0
- package/examples/temp-file-cleanup.sh +1 -1
- package/examples/temporal-suggestion-detector.sh +135 -0
- package/examples/terraform-guard.sh +27 -6
- package/examples/test-after-edit.sh +1 -1
- package/examples/test-before-push.sh +12 -0
- package/examples/test-coverage-reminder.sh +24 -1
- package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
- package/examples/thinking-stall-detector.sh +61 -0
- package/examples/timezone-guard.sh +0 -0
- package/examples/tmp-output-size-guard.sh +0 -0
- package/examples/todo-check.sh +1 -1
- package/examples/token-budget-guard.sh +12 -0
- package/examples/token-budget-per-task.sh +12 -0
- package/examples/token-usage-tracker.sh +7 -1
- package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
- package/examples/tokenizer-ratio-alert.sh +104 -0
- package/examples/tool-call-rate-limiter.sh +0 -0
- package/examples/tool-result-correlation-checker.sh +167 -0
- package/examples/tool-result-size-guard.sh +132 -0
- package/examples/tool-retry-budget-guard.sh +12 -0
- package/examples/transcript-contamination-detector.sh +138 -0
- package/examples/trustfall-mcp-injection-guard.sh +103 -0
- package/examples/ultrareview-large-diff-advisor.sh +184 -0
- package/examples/unbounded-output-guard.sh +94 -0
- package/examples/uncommitted-changes-stop.sh +1 -0
- package/examples/uncommitted-discard-guard.sh +23 -5
- package/examples/uncommitted-work-guard.sh +12 -0
- package/examples/usage-warn.sh +0 -0
- package/examples/user-account-guard.sh +12 -0
- package/examples/userprompt-submit-receipt.sh +123 -0
- package/examples/variable-expansion-guard.sh +12 -0
- package/examples/verify-after-publish-reminder.sh +93 -0
- package/examples/verify-before-commit.sh +12 -0
- package/examples/version-bump-detector.sh +156 -0
- package/examples/version-regression-warner.sh +144 -0
- package/examples/vue-lint-on-edit.sh +1 -0
- package/examples/warn-cron-cost-trap.sh +173 -0
- package/examples/webfetch-runaway-guard.sh +89 -0
- package/examples/wellness-break-reminder.sh +118 -0
- package/examples/windows-destructive-command-guard.sh +177 -0
- package/examples/windows-path-guard.sh +12 -0
- package/examples/windows-python-stub-detector.sh +63 -0
- package/examples/work-hours-guard.sh +12 -0
- package/examples/working-directory-fence.sh +12 -0
- package/examples/workspace-lease-guard.sh +205 -0
- package/examples/worktree-create-log.sh +1 -0
- package/examples/worktree-delete-guard.sh +12 -0
- package/examples/worktree-edit-boundary-guard.sh +127 -0
- package/examples/worktree-escape-write-guard.sh +114 -0
- package/examples/worktree-hook-linker.sh +0 -0
- package/examples/worktree-hooks-path-fix.sh +111 -0
- package/examples/worktree-parent-write-guard.sh +43 -0
- package/examples/worktree-project-unify.sh +2 -1
- package/examples/worktree-remove-uncommitted-guard.sh +13 -0
- package/examples/worktree-unmerged-guard.sh +7 -1
- package/examples/write-byte-integrity-verifier.sh +190 -0
- package/examples/write-empty-content-guard.sh +67 -0
- package/examples/write-nul-corruption-detector.sh +61 -0
- package/examples/write-overwrite-confirm.sh +160 -14
- package/examples/write-secret-guard.sh +27 -5
- package/examples/write-shrink-guard.sh +12 -0
- package/examples/write-test-ratio.sh +0 -0
- package/examples/wsl-host-disk-space-guard.sh +97 -0
- package/examples/xml-format-leak-detector.sh +266 -0
- package/examples/yaml-syntax-check.sh +12 -0
- package/hooks/hooks.json +6 -6
- package/index.mjs +1699 -183
- package/mission.md +2 -0
- package/package.json +4 -4
- package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
- package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
- package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
- package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
- package/scripts/agents-md-sync-setup.sh +156 -0
- package/scripts/autonomy-blocked-summary.sh +148 -0
- package/scripts/build-search-index.py +43 -0
- package/scripts/build-sitemap.py +119 -0
- package/scripts/cc-doctor.sh +192 -0
- package/scripts/check-hook-event-names.py +127 -0
- package/scripts/check-misfire-instrument.sh +64 -0
- package/scripts/claim-verify-audit.sh +467 -0
- package/scripts/cowork-claudemd-helper.sh +136 -0
- package/scripts/june-15-deprecated-model-scan.sh +111 -0
- package/scripts/measure-heredoc-shapes.sh +67 -0
- package/scripts/measure-literal-match-misfire.sh +110 -0
- package/scripts/probe-scope-guard-branches.sh +48 -0
- package/scripts/probe-skip-line-both-ways.sh +65 -0
- package/scripts/receipts-aggregate.py +199 -0
- package/scripts/session-forensic-audit.py +360 -0
- package/scripts.json +9 -9
- package/scripts.json.bak-2026-07-27-find +13 -0
- package/skills/safety-setup/SKILL.md +5 -5
- package/tests/approve-side-remaining-two.test.sh +129 -0
- package/tests/approver-list-granularity.test.sh +145 -0
- package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
- package/tests/audit-ci-gate.test.sh +87 -0
- package/tests/audit-cross-layer-claudemd.test.sh +170 -0
- package/tests/audit-fail-open-parse.test.sh +100 -0
- package/tests/auto-approve-compound-tail.test.sh +194 -0
- package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
- package/tests/auto-mode-quoted-targets.test.sh +127 -0
- package/tests/auto-mode-unquoted-targets.test.sh +112 -0
- package/tests/bash-secret-output-detector-detects.test.sh +102 -0
- package/tests/blindspots-cross-layer.test.sh +177 -0
- package/tests/block-database-wipe.test.sh +64 -0
- package/tests/bundled-short-flags-bypass.test.sh +85 -0
- package/tests/cd-git-allow-compound-tail.test.sh +67 -0
- package/tests/chown-guard-filesystem-root.test.sh +64 -0
- package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
- package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
- package/tests/core-scripts-parser-fallback.test.sh +140 -0
- package/tests/destructive-guard-bare-glob.test.sh +74 -0
- package/tests/destructive-guard-every-operand.test.sh +100 -0
- package/tests/destructive-guard-find-deletion.test.sh +114 -0
- package/tests/destructive-guard-flag-order.test.sh +106 -0
- package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
- package/tests/destructive-guard-quoted-target.test.sh +89 -0
- package/tests/destructive-guard-separators.test.sh +105 -0
- package/tests/destructive-guard-variable-target.test.sh +98 -0
- package/tests/destructive-guard-wrapped-command.test.sh +91 -0
- package/tests/doctor-hook-disabling-env.test.sh +92 -0
- package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
- package/tests/example-guards-wrapped-command.test.sh +169 -0
- package/tests/file-edit-backup.test.sh +93 -0
- package/tests/git-filter-repo-guard.test.sh +60 -0
- package/tests/git-global-options-bypass.test.sh +141 -0
- package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
- package/tests/git-maintenance-guard.test.sh +83 -0
- package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
- package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
- package/tests/git-submodule-guard.test.sh +50 -0
- package/tests/grep-pcre-portability.test.sh +155 -0
- package/tests/hook-registration-matches-input.test.sh +73 -0
- package/tests/hook-trigger-matches-envelope.test.sh +178 -0
- package/tests/install-does-not-claim-protection.test.sh +110 -0
- package/tests/install-example-standalone-tools.test.sh +139 -0
- package/tests/line-continuation-bypass.test.sh +114 -0
- package/tests/mcp-config-poisoning-audit.test.sh +106 -0
- package/tests/nested-background-agent-guard.test.sh +58 -0
- package/tests/no-unqualified-safety-claims.test.sh +114 -0
- package/tests/option-eating-grep-patterns.test.sh +130 -0
- package/tests/outdated-core-guards.test.sh +134 -0
- package/tests/outdated-report.test.sh +155 -0
- package/tests/output-secret-mask-warns.test.sh +73 -0
- package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
- package/tests/plugins-word-order.test.sh +126 -0
- package/tests/powershell-remove-item-guard.test.sh +85 -0
- package/tests/project-dir-naming.test.sh +103 -0
- package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
- package/tests/reroute-after-block-guard.test.sh +104 -0
- package/tests/secret-guard-documented-promises.test.sh +97 -0
- package/tests/session-plugin-pin-watch.test.sh +45 -0
- package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
- package/tests/shield-no-silent-adoption.test.py +110 -0
- package/tests/shield-no-silent-adoption.test.sh +46 -0
- package/tests/stop-transcript-write-health.test.sh +46 -0
- package/tests/system-dir-guard-root-erased.test.sh +66 -0
- package/tests/test-account-billing-log.sh +100 -0
- package/tests/test-account-routing-preflight.sh +77 -0
- package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
- package/tests/test-agent-view-quota-warn.sh +184 -0
- package/tests/test-agents-md-edit-drift-warner.sh +176 -0
- package/tests/test-agents-md-loader.sh +204 -0
- package/tests/test-agents-md-sync-checker.sh +125 -0
- package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
- package/tests/test-allowlist.sh +60 -0
- package/tests/test-always-allow-pattern-suggester.sh +147 -0
- package/tests/test-anthropic-base-url-guard.sh +88 -0
- package/tests/test-articulated-scope-capture.sh +139 -0
- package/tests/test-attachment-traversal-guard.sh +168 -0
- package/tests/test-aup-block-pattern-logger.sh +315 -0
- package/tests/test-aup-false-positive-helper.sh +188 -0
- package/tests/test-aup-large-tool-output-warner.sh +370 -0
- package/tests/test-aup-retry-loop-guard.sh +341 -0
- package/tests/test-auth-expiry-reminder.sh +303 -0
- package/tests/test-auth-macos-sleep-detector.sh +254 -0
- package/tests/test-auth-path-detector.sh +232 -0
- package/tests/test-auth-status-checker.sh +233 -0
- package/tests/test-authorized-reconfirmation-detector.sh +280 -0
- package/tests/test-background-cost-launch-guard.sh +62 -0
- package/tests/test-bash-allowlist-secondary-check.sh +143 -0
- package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
- package/tests/test-bash-project-fence.sh +127 -0
- package/tests/test-bg-permission-prompt-warner.sh +221 -0
- package/tests/test-binary-read-detector.sh +173 -0
- package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
- package/tests/test-bulk-delete-target-resolution.sh +49 -0
- package/tests/test-bypass-mode-effective-verifier.sh +179 -0
- package/tests/test-cache-creation-drift-detector.sh +244 -0
- package/tests/test-cache-residue-detector.sh +429 -0
- package/tests/test-cache-tier-logger.sh +59 -0
- package/tests/test-cache-ttl-eviction-detector.sh +282 -0
- package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
- package/tests/test-claim-verify-detector.sh +222 -0
- package/tests/test-claim-vs-caveat-checker.sh +134 -0
- package/tests/test-claude-code-version-pin-advisor.sh +353 -0
- package/tests/test-claude-md-reinjector.sh +173 -0
- package/tests/test-claude-md-size-monitor.sh +107 -0
- package/tests/test-claude-update-budget-guard.sh +132 -0
- package/tests/test-claude-update-smart.sh +91 -0
- package/tests/test-claudemd-tool-prohibition.sh +239 -0
- package/tests/test-cli-config-pinning-detector.sh +233 -0
- package/tests/test-cliff-countdown-advisor.sh +138 -0
- package/tests/test-closure-word-verify-gate.sh +158 -0
- package/tests/test-commit-all-scope-guard.sh +73 -0
- package/tests/test-commitment-carry-forward-arrest.sh +250 -0
- package/tests/test-compact-circuit-breaker.sh +134 -0
- package/tests/test-compact-dispatch-watchdog.sh +147 -0
- package/tests/test-completion-claim-without-verification-detector.sh +326 -0
- package/tests/test-compound-bash-permission-resolver.sh +264 -0
- package/tests/test-compound-command-deny-enforcer.sh +67 -0
- package/tests/test-context-length-budget.sh +68 -0
- package/tests/test-context-usage-drift-alert.sh +52 -22
- package/tests/test-cost-incident-self-audit.sh +94 -0
- package/tests/test-cowork-claude-md-load-checker.sh +257 -0
- package/tests/test-cowork-claudemd-helper.sh +141 -0
- package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
- package/tests/test-cowork-hook-absence-warner.sh +230 -0
- package/tests/test-cowork-model-picker-advisor.sh +317 -0
- package/tests/test-credential-exfil-guard.sh +62 -0
- package/tests/test-cron-create-receipt.sh +165 -0
- package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
- package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
- package/tests/test-daily-cost-guard.sh +131 -0
- package/tests/test-deny-rule-integrity-verifier.sh +288 -0
- package/tests/test-deployment-readback-gate.sh +92 -0
- package/tests/test-deployment-readback-gh-adapter.sh +163 -0
- package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
- package/tests/test-dispatch-allowlist-preflight.sh +385 -0
- package/tests/test-dispatch-liveness-watchdog.sh +319 -0
- package/tests/test-dispatch-receipt.sh +314 -0
- package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
- package/tests/test-echo-probe-spam-detector.sh +143 -0
- package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
- package/tests/test-ephemeral-container-detector.sh +251 -0
- package/tests/test-evidence-claim-gate.sh +291 -0
- package/tests/test-exploration-budget-guard.sh +164 -0
- package/tests/test-extended-thinking-loop-guard.sh +289 -0
- package/tests/test-extended-thinking-resume-warning.sh +240 -0
- package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
- package/tests/test-fabricated-command-detector.sh +296 -0
- package/tests/test-false-disk-full-guard.sh +36 -0
- package/tests/test-feature-deprecation-detector.sh +117 -0
- package/tests/test-forbidden-response-phrase-detector.sh +246 -0
- package/tests/test-git-operations-require-approval.sh +53 -0
- package/tests/test-git-push-blast-radius-guard.sh +115 -0
- package/tests/test-goal-iteration-limit-warner.sh +128 -0
- package/tests/test-growthbook-flag-monitor.sh +428 -0
- package/tests/test-halt-signal-detector.sh +120 -0
- package/tests/test-hook-self-disable-detector.sh +232 -0
- package/tests/test-iteration-quality-degradation-detector.sh +244 -0
- package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
- package/tests/test-marketplace-plugins.sh +193 -0
- package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
- package/tests/test-mcp-orphan-leak-warner.sh +71 -0
- package/tests/test-mcp-permissions-ask-warner.sh +207 -0
- package/tests/test-mcp-routine-approval-detector.sh +229 -0
- package/tests/test-mcp-startup-bloat-detector.sh +141 -0
- package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
- package/tests/test-memory-chain-audit.sh +59 -0
- package/tests/test-memory-orphan-detector.sh +227 -0
- package/tests/test-model-swap-suggester.sh +368 -0
- package/tests/test-model-version-lock.sh +83 -0
- package/tests/test-multi-file-plan-routing-gate.sh +277 -0
- package/tests/test-multi-window-auth-drift-detector.sh +262 -0
- package/tests/test-nested-spawn-inflight-guard.sh +281 -0
- package/tests/test-no-force-flag.sh +49 -0
- package/tests/test-non-english-quality-warner.sh +229 -0
- package/tests/test-oauth-refresh-monitor.sh +311 -0
- package/tests/test-opus-degradation-tracker.sh +274 -0
- package/tests/test-opus48-routine-task-warning.sh +201 -0
- package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
- package/tests/test-output-token-spike-detector.sh +315 -0
- package/tests/test-parallel-batch-size-limiter.sh +228 -0
- package/tests/test-parallel-cascade-detector.sh +191 -0
- package/tests/test-partial-view-claim-arrest.sh +272 -0
- package/tests/test-per-prompt-token-cap.sh +136 -0
- package/tests/test-persisted-1m-model-advisor.sh +71 -0
- package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
- package/tests/test-post-edit-disk-verify.sh +294 -0
- package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
- package/tests/test-pre-execution-claim-detector.sh +366 -0
- package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
- package/tests/test-proxy-capture-suggester.sh +214 -0
- package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
- package/tests/test-quota-anomaly-detector.sh +321 -0
- package/tests/test-quota-reset-audit.sh +81 -0
- package/tests/test-read-loop-detector.sh +137 -0
- package/tests/test-read-once-guard.sh +85 -0
- package/tests/test-receipts-aggregate.sh +143 -0
- package/tests/test-redirect-fragment-warner.sh +130 -0
- package/tests/test-redundant-read-blocker.sh +155 -0
- package/tests/test-refusal-arrest-gate.sh +303 -0
- package/tests/test-remote-control-billing-classifier.sh +125 -0
- package/tests/test-resume-drift-watcher.sh +65 -0
- package/tests/test-rg-replace-flag-detector.sh +175 -0
- package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
- package/tests/test-rm-safety-net.sh +115 -0
- package/tests/test-route-handler-emptiness-gate.sh +300 -0
- package/tests/test-runtime-binary-change-detector.sh +196 -0
- package/tests/test-same-command-repeat-detector.sh +165 -0
- package/tests/test-same-correction-arrest.sh +165 -0
- package/tests/test-scope-expansion-receipt.sh +207 -0
- package/tests/test-server-side-prompt-injection-detector.sh +181 -0
- package/tests/test-session-persistence-verifier.sh +128 -0
- package/tests/test-session-rate-monitor.sh +284 -0
- package/tests/test-session-start-quota-status.sh +210 -0
- package/tests/test-session-start-safety-check.sh +138 -0
- package/tests/test-settings-hooks-key-restorer.sh +257 -0
- package/tests/test-settings-json-health-check.sh +70 -0
- package/tests/test-settings-regression-tester.sh +197 -0
- package/tests/test-skill-cumulative-size-detector.sh +198 -0
- package/tests/test-skill-description-drop-detector.sh +236 -0
- package/tests/test-skill-truncation-detector.sh +263 -0
- package/tests/test-skills-context-recorder.sh +329 -0
- package/tests/test-skills-load-verifier.sh +184 -0
- package/tests/test-skills-settings-validator.sh +242 -0
- package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
- package/tests/test-spurious-malformed-notice-detector.sh +290 -0
- package/tests/test-sql-bulk-delete-warn.sh +123 -0
- package/tests/test-ssh-key-protect.sh +81 -0
- package/tests/test-stale-temp-settings-detector.sh +161 -0
- package/tests/test-standing-rule-session-surfacer.sh +215 -0
- package/tests/test-starter-hooks-manifest.sh +96 -0
- package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
- package/tests/test-strict-allowlist.sh +72 -0
- package/tests/test-subagent-boundary-precheck.sh +137 -0
- package/tests/test-subagent-closure-verify-gate.sh +193 -0
- package/tests/test-subagent-destructive-git-guard.sh +86 -0
- package/tests/test-subagent-identity-leak-guard.sh +62 -0
- package/tests/test-subagent-identity-reassertion.sh +61 -0
- package/tests/test-subagent-inheritance-tester.sh +319 -0
- package/tests/test-subagent-permission-mode-guard.sh +61 -0
- package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
- package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
- package/tests/test-subagent-tool-call-limiter.sh +97 -0
- package/tests/test-subscription-api-billing-warner.sh +138 -0
- package/tests/test-subscription-bypass-detector.sh +255 -0
- package/tests/test-temporal-suggestion-detector.sh +183 -0
- package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
- package/tests/test-thinking-stall-detector.sh +151 -0
- package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
- package/tests/test-tokenizer-ratio-alert.sh +93 -0
- package/tests/test-tool-result-correlation-checker.sh +264 -0
- package/tests/test-tool-result-size-guard.sh +121 -0
- package/tests/test-transcript-contamination-detector.sh +264 -0
- package/tests/test-trigger-header-parsing.sh +151 -0
- package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
- package/tests/test-userprompt-submit-receipt.sh +181 -0
- package/tests/test-verify-after-publish-reminder.sh +184 -0
- package/tests/test-version-bump-detector.sh +212 -0
- package/tests/test-version-regression-warner.sh +165 -0
- package/tests/test-warn-cron-cost-trap.sh +82 -0
- package/tests/test-webfetch-runaway-guard.sh +77 -0
- package/tests/test-wellness-break-reminder.sh +138 -0
- package/tests/test-windows-destructive-command-guard.sh +169 -0
- package/tests/test-windows-python-stub-detector.sh +146 -0
- package/tests/test-worktree-edit-boundary-guard.sh +219 -0
- package/tests/test-write-byte-integrity-verifier.sh +192 -0
- package/tests/test-xml-format-leak-detector.sh +299 -0
- package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
- package/tests/workspace-lease-guard.test.sh +144 -0
- package/tests/worktree-escape-write-guard.test.sh +68 -0
- package/tests/worktree-hooks-path-fix.test.sh +181 -0
- package/tests/worktree-parent-write-guard.test.sh +51 -0
- package/tests/write-empty-content-guard.test.sh +39 -0
- package/tests/write-nul-corruption-detector.test.sh +29 -0
- package/tests/write-overwrite-unread-content.test.sh +178 -0
- package/tests/wsl-host-disk-space-guard.test.sh +55 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# completion-claim-without-verification-detector.sh — Stop hook
|
|
3
|
+
# Trigger: Stop
|
|
4
|
+
# Matcher: ""
|
|
5
|
+
#
|
|
6
|
+
# Solves: Issue #60177 (mike-prokhorov, 2026-05-18) — "Claude marks tasks
|
|
7
|
+
# done without testing — 12 days, 51 commits, still broken (Opus
|
|
8
|
+
# 4.x)". Across approximately fifty sessions over twelve days, the
|
|
9
|
+
# agent repeatedly said "done, ready to test" without running any
|
|
10
|
+
# verification step. Approximately 70% of the period's commits
|
|
11
|
+
# were fix-of-prior-commit rather than progress. The user's
|
|
12
|
+
# post-incident framing: a four-level honesty ladder where
|
|
13
|
+
# L0 = file exists, L1 = smoke-tested locally, L2 = runs in
|
|
14
|
+
# staging, L3 = user-approved. The agent defaulted to claiming
|
|
15
|
+
# the highest aspirational level (L3-ish "done, ready to test")
|
|
16
|
+
# without having reached even L1.
|
|
17
|
+
#
|
|
18
|
+
# Class of failure: claim-vs-reality divergence at the completion-signal
|
|
19
|
+
# layer. The agent's response surface emits a definitive
|
|
20
|
+
# completion claim ("done", "ready to test", "fixed",
|
|
21
|
+
# "succeeded", "完了") that the underlying tool history does not
|
|
22
|
+
# support. The user trusts the claim, attempts to use the
|
|
23
|
+
# deliverable, and discovers the gap downstream — often after
|
|
24
|
+
# expensive context loss.
|
|
25
|
+
#
|
|
26
|
+
# HOW IT WORKS:
|
|
27
|
+
# On Stop, the hook reads the session transcript and looks at the
|
|
28
|
+
# final assistant message for completion-claim markers. If a claim
|
|
29
|
+
# is detected, it then scans the recent tool-use history (the last
|
|
30
|
+
# FORTY tool calls in this session) for verification-shaped tools:
|
|
31
|
+
# Bash invocations that run a test command (pytest / npm test /
|
|
32
|
+
# go test / cargo test / curl / status check / smoke / verify),
|
|
33
|
+
# Read on log files, or Grep against an output destination.
|
|
34
|
+
# If a completion claim was emitted but no verification-shaped tool
|
|
35
|
+
# appears in the recent window, the hook writes an advisory line to
|
|
36
|
+
# stderr and logs the detection. The hook never blocks the Stop.
|
|
37
|
+
#
|
|
38
|
+
# WHY THIS MATTERS:
|
|
39
|
+
# The 60177 failure shape is one of the most expensive in the
|
|
40
|
+
# tracker. Every "done, ready to test" without verification spends
|
|
41
|
+
# the operator's attention budget on a falsified completion, often
|
|
42
|
+
# triggers a re-run cycle that burns API credits, and erodes the
|
|
43
|
+
# trust margin that lets the agent operate autonomously at all.
|
|
44
|
+
# Most prevention efforts focus on slowing the agent down with
|
|
45
|
+
# permission prompts on individual tool calls. This hook works in
|
|
46
|
+
# the opposite direction: it lets the agent run freely and only
|
|
47
|
+
# surfaces a warning when the *completion claim* contradicts the
|
|
48
|
+
# *recent tool history*.
|
|
49
|
+
#
|
|
50
|
+
# TRIGGER: Stop
|
|
51
|
+
# MATCHER: ""
|
|
52
|
+
#
|
|
53
|
+
# CONFIGURATION:
|
|
54
|
+
# CC_COMPLETION_CLAIM_DISABLE=1 disable the hook entirely
|
|
55
|
+
# CC_COMPLETION_CLAIM_LOG=path append detection events
|
|
56
|
+
# (default ~/.claude/logs/completion-claim.log)
|
|
57
|
+
# CC_COMPLETION_CLAIM_WINDOW=N scan window size in tool calls
|
|
58
|
+
# (default 40)
|
|
59
|
+
#
|
|
60
|
+
# SAFETY:
|
|
61
|
+
# - Read-only on the transcript; never modifies any session state.
|
|
62
|
+
# - Emits an advisory line via stderr; does not block Stop.
|
|
63
|
+
# - Exits 0 always; never prevents the session from ending.
|
|
64
|
+
# - Uses jq for transcript parsing; falls back silently if jq is
|
|
65
|
+
# not installed (Claude Code requires jq for hook input parsing
|
|
66
|
+
# so this is rarely a real problem).
|
|
67
|
+
#
|
|
68
|
+
# REFERENCES:
|
|
69
|
+
# - anthropics/claude-code#60177 (mike-prokhorov, 2026-05-18) — the
|
|
70
|
+
# canonical case with the L0/L1/L2/L3 ladder framing
|
|
71
|
+
# - companion hook: rhetorical-verification-prompt-detector.sh
|
|
72
|
+
# (catches the input-side rhetorical-question failure, while this
|
|
73
|
+
# hook catches the output-side completion-claim failure)
|
|
74
|
+
set -u
|
|
75
|
+
|
|
76
|
+
[ "${CC_COMPLETION_CLAIM_DISABLE:-}" = "1" ] && exit 0
|
|
77
|
+
|
|
78
|
+
LOG_DIR="${HOME}/.claude/logs"
|
|
79
|
+
LOG_FILE="${CC_COMPLETION_CLAIM_LOG:-${LOG_DIR}/completion-claim.log}"
|
|
80
|
+
mkdir -p "$LOG_DIR" 2>/dev/null
|
|
81
|
+
|
|
82
|
+
WINDOW="${CC_COMPLETION_CLAIM_WINDOW:-40}"
|
|
83
|
+
|
|
84
|
+
INPUT=$(cat)
|
|
85
|
+
TRANSCRIPT=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
86
|
+
[ -z "$TRANSCRIPT" ] && exit 0
|
|
87
|
+
[ ! -r "$TRANSCRIPT" ] && exit 0
|
|
88
|
+
|
|
89
|
+
# Extract text of the last assistant message in the transcript.
|
|
90
|
+
# Each JSONL line of type=assistant has message.content as an array of
|
|
91
|
+
# blocks; we collect blocks of type=text.
|
|
92
|
+
LAST_TEXT=$(tac "$TRANSCRIPT" 2>/dev/null \
|
|
93
|
+
| grep -m1 '"type":"assistant"' \
|
|
94
|
+
| jq -r '
|
|
95
|
+
if (.message.content | type) == "array" then
|
|
96
|
+
[.message.content[] | select(.type=="text") | .text] | join("\n")
|
|
97
|
+
else
|
|
98
|
+
""
|
|
99
|
+
end
|
|
100
|
+
' 2>/dev/null || true)
|
|
101
|
+
|
|
102
|
+
[ -z "$LAST_TEXT" ] && exit 0
|
|
103
|
+
|
|
104
|
+
# Detection patterns — completion-claim markers.
|
|
105
|
+
# Conservative on purpose: only catch phrasing that strongly implies a
|
|
106
|
+
# definitive *done* assertion. Hedged phrasing ("seems to work",
|
|
107
|
+
# "I think this is ready", "this should be done") deliberately does not
|
|
108
|
+
# trigger — that hedged surface form is the honest one we want to keep.
|
|
109
|
+
EN_PATTERNS='\b(done|complete|completed|ready to test|fixed|fixed it|all set|good to go|works now|working now|deployed|shipped)\b|task (is )?(now )?(done|complete|finished)|implementation (is )?(now )?(done|complete|finished)|i.?ve (finished|completed|implemented|fixed)|successfully (implemented|completed|fixed|deployed)|the (fix|change|feature|implementation) is (now )?(working|done|complete|deployed)'
|
|
110
|
+
|
|
111
|
+
JA_PATTERNS='完了(しました|です)?|終わりました|完成(しました|です)?|準備(が )?完了|修正(済|完了|しました)|実装(完了|済|しました)|デプロイ(完了|済|しました)|動作(確認済|しました)?|テスト(してください|可能です)|動きます|動いています'
|
|
112
|
+
|
|
113
|
+
# Hedge detection — if the message contains hedging markers, treat it as
|
|
114
|
+
# NOT a definitive completion claim. Honest hedging is the surface form we
|
|
115
|
+
# want to preserve.
|
|
116
|
+
EN_HEDGE='\b(i think|i believe|i hope|hopefully|maybe|possibly|might be|might have|should be|should have|seems to|appears to|looks like|i\b.*not sure|haven.?t (tested|verified|checked|run)|did not (test|verify|check|run)|did.?nt (test|verify|check|run)|could you (verify|check|confirm|test)|please (verify|check|confirm|test))\b'
|
|
117
|
+
JA_HEDGE='と思います|だと思う|多分|たぶん|おそらく|かもしれ(ない|ません)|未確認|確認していません|テストしていません|確認していない|確認してください|テストしてください|チェックしてください'
|
|
118
|
+
|
|
119
|
+
# If hedging is present, exit silently — the surface form is honest.
|
|
120
|
+
if echo "$LAST_TEXT" | grep -qiE "$EN_HEDGE"; then
|
|
121
|
+
exit 0
|
|
122
|
+
fi
|
|
123
|
+
if echo "$LAST_TEXT" | grep -qE "$JA_HEDGE"; then
|
|
124
|
+
exit 0
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
MATCHED_CLAIM=""
|
|
128
|
+
|
|
129
|
+
if echo "$LAST_TEXT" | grep -qiE "$EN_PATTERNS"; then
|
|
130
|
+
MATCHED_CLAIM=$(echo "$LAST_TEXT" | grep -oiE "$EN_PATTERNS" | head -1)
|
|
131
|
+
elif echo "$LAST_TEXT" | grep -qE "$JA_PATTERNS"; then
|
|
132
|
+
MATCHED_CLAIM=$(echo "$LAST_TEXT" | grep -oE "$JA_PATTERNS" | head -1)
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
[ -z "$MATCHED_CLAIM" ] && exit 0
|
|
136
|
+
|
|
137
|
+
# Scan the last WINDOW tool-use entries for verification-shaped tools.
|
|
138
|
+
# We accept any of the following as evidence that some verification was
|
|
139
|
+
# attempted in the session's recent history:
|
|
140
|
+
# - Bash invocations whose command matches verification commands
|
|
141
|
+
# - Read of a log file
|
|
142
|
+
# - Grep over an output destination
|
|
143
|
+
# This list is intentionally permissive: the goal is to catch the
|
|
144
|
+
# "claimed done without doing anything to check" pattern, not to grade
|
|
145
|
+
# every session on the quality of its tests.
|
|
146
|
+
VERIFY_COMMAND_PATTERN='pytest|unittest|npm (run )?test|yarn test|go test|cargo test|cargo check|jest|mocha|rspec|phpunit|composer test|mix test|gradle test|mvn test|make test|make check|bin/test|bin/rspec|bundle exec rspec|bundle exec rake test|curl |wget |httpie|http |status check|smoke|verify|sanity|tail -[fn]|less |cat .*\.log|grep .*\.log|systemctl status|docker (ps|logs)|kubectl (get|logs|describe)|psql -c|sqlite3 .*SELECT|redis-cli|nmap |ping |ssh .*-c|ssh .*uptime|ssh .*systemctl|ssh .*docker|ssh .*tail|gh run|gh workflow|git diff --check|git status|node -e .*assert|python -c .*assert|ruby -e .*raise'
|
|
147
|
+
|
|
148
|
+
VERIFY_TOOL_PATTERN='"name":"Bash"|"name":"Read"|"name":"Grep"|"name":"Glob"'
|
|
149
|
+
|
|
150
|
+
# Read the last WINDOW tool_use entries from the transcript.
|
|
151
|
+
# Each tool_use is inside a message.content block of type=tool_use.
|
|
152
|
+
RECENT_TOOL_USES=$(tac "$TRANSCRIPT" 2>/dev/null \
|
|
153
|
+
| grep '"tool_use"' \
|
|
154
|
+
| head -n "$WINDOW")
|
|
155
|
+
|
|
156
|
+
# Did any recent Bash command match a verification-shaped command?
|
|
157
|
+
VERIFICATION_FOUND="0"
|
|
158
|
+
if [ -n "$RECENT_TOOL_USES" ]; then
|
|
159
|
+
# Bash commands
|
|
160
|
+
BASH_COMMANDS=$(printf '%s\n' "$RECENT_TOOL_USES" \
|
|
161
|
+
| jq -r '
|
|
162
|
+
select(.message.content) |
|
|
163
|
+
.message.content[]? |
|
|
164
|
+
select(.type=="tool_use" and .name=="Bash") |
|
|
165
|
+
.input.command // empty
|
|
166
|
+
' 2>/dev/null || true)
|
|
167
|
+
|
|
168
|
+
if [ -n "$BASH_COMMANDS" ] && echo "$BASH_COMMANDS" | grep -qiE "$VERIFY_COMMAND_PATTERN"; then
|
|
169
|
+
VERIFICATION_FOUND="1"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# Read calls (we treat any Read in the window as plausible verification)
|
|
173
|
+
if [ "$VERIFICATION_FOUND" = "0" ]; then
|
|
174
|
+
if printf '%s\n' "$RECENT_TOOL_USES" | grep -q '"name":"Read"'; then
|
|
175
|
+
# Be stricter: only count Read of log files / output files as verification
|
|
176
|
+
READ_PATHS=$(printf '%s\n' "$RECENT_TOOL_USES" \
|
|
177
|
+
| jq -r '
|
|
178
|
+
select(.message.content) |
|
|
179
|
+
.message.content[]? |
|
|
180
|
+
select(.type=="tool_use" and .name=="Read") |
|
|
181
|
+
.input.file_path // empty
|
|
182
|
+
' 2>/dev/null || true)
|
|
183
|
+
if echo "$READ_PATHS" | grep -qiE '\.log|/log/|output|result|coverage|junit|test.*report|/tmp/'; then
|
|
184
|
+
VERIFICATION_FOUND="1"
|
|
185
|
+
fi
|
|
186
|
+
fi
|
|
187
|
+
fi
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
[ "$VERIFICATION_FOUND" = "1" ] && exit 0
|
|
191
|
+
|
|
192
|
+
# Detection: completion claim emitted, no verification in recent window.
|
|
193
|
+
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
194
|
+
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null || echo "unknown")
|
|
195
|
+
|
|
196
|
+
# Log the detection
|
|
197
|
+
{
|
|
198
|
+
printf '[%s] completion-claim-without-verification session=%s claim=%q window=%s\n' \
|
|
199
|
+
"$TS" "$SESSION_ID" "$MATCHED_CLAIM" "$WINDOW"
|
|
200
|
+
} >> "$LOG_FILE" 2>/dev/null || true
|
|
201
|
+
|
|
202
|
+
# Emit advisory to stderr — Claude Code surfaces this to the user.
|
|
203
|
+
cat >&2 << EOF
|
|
204
|
+
[completion-claim-without-verification] The assistant just emitted a completion claim ("$MATCHED_CLAIM") but the last $WINDOW tool calls in this session do not include a verification-shaped tool use (no pytest / npm test / curl / status check / log read). This pattern matches anthropics/claude-code#60177 (12 days, 51 commits, 0 working product). Consider asking the assistant which check actually ran, or run a verification command yourself before acting on the claim.
|
|
205
|
+
EOF
|
|
206
|
+
|
|
207
|
+
exit 0
|
|
@@ -20,6 +20,18 @@
|
|
|
20
20
|
#
|
|
21
21
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
22
22
|
|
|
23
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
24
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
25
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
26
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
27
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
28
|
+
_nojq_warned="/tmp/cc-nojq-warned-composer-guard-$PPID"
|
|
29
|
+
[ -f "$_nojq_warned" ] || {
|
|
30
|
+
echo "WARNING [composer-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
31
|
+
: > "$_nojq_warned"
|
|
32
|
+
}
|
|
33
|
+
fi
|
|
34
|
+
|
|
23
35
|
INPUT=$(cat)
|
|
24
36
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
25
37
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# compound-bash-permission-resolver.sh — Per-component allow-rule check for compound bash
|
|
3
|
+
#
|
|
4
|
+
# Solves: Cluster 6 Axis 1 — wildcard rules like Bash(git status:*) match
|
|
5
|
+
# a bare `git status` but not `cd repo && git status`, even though
|
|
6
|
+
# the rule should logically cover the second. The operator who
|
|
7
|
+
# configured the rule sees a permission prompt with no way to tell
|
|
8
|
+
# whether their rule "should have" covered.
|
|
9
|
+
#
|
|
10
|
+
# Issues addressed: #28240 (180 reactions), #32985 (24 reactions),
|
|
11
|
+
# meta-issue #30519 Axis 1.
|
|
12
|
+
#
|
|
13
|
+
# How it works: PreToolUse hook on Bash. When the command contains a
|
|
14
|
+
# compound separator (&&, ||, ;, |), the hook splits it into components
|
|
15
|
+
# and checks each component against the Bash() patterns configured in
|
|
16
|
+
# permissions.allow across the four standard settings locations.
|
|
17
|
+
#
|
|
18
|
+
# The advisory tells the operator one of two things:
|
|
19
|
+
# - all N components match an existing pattern individually, so the
|
|
20
|
+
# prompt is the Axis 1 false positive — safe to approve, but
|
|
21
|
+
# "Always Allow" will save the verbatim compound, not the patterns
|
|
22
|
+
# - K of N components match, the remainder do not — the prompt is
|
|
23
|
+
# firing on a genuinely new tool surface
|
|
24
|
+
#
|
|
25
|
+
# This hook NEVER blocks. It always exits 0. It only reads settings.
|
|
26
|
+
#
|
|
27
|
+
# Heuristic limitations: the splitter does not understand shell quoting,
|
|
28
|
+
# heredocs, or subshell expansions ($(...)). Compounds embedded in
|
|
29
|
+
# quoted arguments may be misparsed. The advisory is conservative:
|
|
30
|
+
# when ambiguous, it counts an unmatched segment as uncovered, which
|
|
31
|
+
# nudges the operator toward inspection rather than blind approval.
|
|
32
|
+
#
|
|
33
|
+
# Environment variables:
|
|
34
|
+
# CC_COMPOUND_RESOLVER_DISABLE=1 — disable the advisory entirely
|
|
35
|
+
# CC_COMPOUND_RESOLVER_VERBOSE=1 — print resolver breakdown
|
|
36
|
+
#
|
|
37
|
+
# TRIGGER: PreToolUse
|
|
38
|
+
# MATCHER: "Bash"
|
|
39
|
+
|
|
40
|
+
set -uo pipefail
|
|
41
|
+
|
|
42
|
+
INPUT=$(cat)
|
|
43
|
+
|
|
44
|
+
# Fail-open on missing input or jq parse errors.
|
|
45
|
+
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
46
|
+
[ -z "$COMMAND" ] && exit 0
|
|
47
|
+
|
|
48
|
+
[ "${CC_COMPOUND_RESOLVER_DISABLE:-0}" = "1" ] && exit 0
|
|
49
|
+
|
|
50
|
+
# Detect compound separator. Order matters: check && and || before single |.
|
|
51
|
+
IS_COMPOUND=0
|
|
52
|
+
case "$COMMAND" in
|
|
53
|
+
*"&&"*|*"||"*|*";"*) IS_COMPOUND=1 ;;
|
|
54
|
+
esac
|
|
55
|
+
# Single pipe (not part of ||): look for "|" with no adjacent "|".
|
|
56
|
+
if [ "$IS_COMPOUND" = "0" ] && \
|
|
57
|
+
printf '%s' "$COMMAND" | grep -qE '([^|]\|[^|]|^\|[^|]|[^|]\|$)'; then
|
|
58
|
+
IS_COMPOUND=1
|
|
59
|
+
fi
|
|
60
|
+
[ "$IS_COMPOUND" = "0" ] && exit 0
|
|
61
|
+
|
|
62
|
+
# Collect Bash() allow patterns from all four standard settings locations.
|
|
63
|
+
PATTERNS_FILE=$(mktemp)
|
|
64
|
+
trap 'rm -f "$PATTERNS_FILE"' EXIT
|
|
65
|
+
for CFG in \
|
|
66
|
+
"${HOME}/.claude/settings.json" \
|
|
67
|
+
"${HOME}/.claude/settings.local.json" \
|
|
68
|
+
"./.claude/settings.json" \
|
|
69
|
+
"./.claude/settings.local.json"; do
|
|
70
|
+
[ -f "$CFG" ] || continue
|
|
71
|
+
jq -r '.permissions.allow // [] | .[] | select(type == "string" and startswith("Bash("))' \
|
|
72
|
+
"$CFG" 2>/dev/null >> "$PATTERNS_FILE" || true
|
|
73
|
+
done
|
|
74
|
+
|
|
75
|
+
# If no Bash() patterns are configured, the resolver has nothing to say.
|
|
76
|
+
[ ! -s "$PATTERNS_FILE" ] && exit 0
|
|
77
|
+
|
|
78
|
+
# Split COMMAND on compound separators (&& || ; |) into one-per-line segments.
|
|
79
|
+
# Order: collapse && and || to newlines first so single | doesn't get
|
|
80
|
+
# erroneously split inside ||.
|
|
81
|
+
SEGMENTS=$(printf '%s' "$COMMAND" \
|
|
82
|
+
| sed -E 's/&&/\n/g; s/\|\|/\n/g; s/;/\n/g' \
|
|
83
|
+
| sed 's/|/\n/g')
|
|
84
|
+
|
|
85
|
+
COVERED_COUNT=0
|
|
86
|
+
TOTAL=0
|
|
87
|
+
UNCOVERED_LIST=""
|
|
88
|
+
|
|
89
|
+
while IFS= read -r SEG; do
|
|
90
|
+
SEG=$(printf '%s' "$SEG" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')
|
|
91
|
+
[ -z "$SEG" ] && continue
|
|
92
|
+
|
|
93
|
+
# Strip leading env-var assignments (FOO=bar BAZ=qux cmd ...).
|
|
94
|
+
WORK="$SEG"
|
|
95
|
+
while printf '%s' "$WORK" | grep -qE '^[A-Z_][A-Z0-9_]*=[^[:space:]]+[[:space:]]+'; do
|
|
96
|
+
WORK=$(printf '%s' "$WORK" | sed -E 's/^[A-Z_][A-Z0-9_]*=[^[:space:]]+[[:space:]]+//')
|
|
97
|
+
done
|
|
98
|
+
|
|
99
|
+
read -r BIN ARG1 _ <<< "$WORK"
|
|
100
|
+
[ -z "${BIN:-}" ] && continue
|
|
101
|
+
|
|
102
|
+
TOTAL=$((TOTAL+1))
|
|
103
|
+
BIN_BASE=$(basename "$BIN")
|
|
104
|
+
|
|
105
|
+
MATCHED=0
|
|
106
|
+
# Subcommand-level pattern: Bash(<bin> <arg1>:*)
|
|
107
|
+
if [ -n "${ARG1:-}" ] && printf '%s' "$ARG1" | grep -qE '^[a-zA-Z][a-zA-Z0-9_-]*$'; then
|
|
108
|
+
if grep -Fxq "Bash($BIN_BASE $ARG1:*)" "$PATTERNS_FILE"; then
|
|
109
|
+
MATCHED=1
|
|
110
|
+
fi
|
|
111
|
+
fi
|
|
112
|
+
# Binary-level pattern fallback: Bash(<bin>:*)
|
|
113
|
+
if [ "$MATCHED" = "0" ] && grep -Fxq "Bash($BIN_BASE:*)" "$PATTERNS_FILE"; then
|
|
114
|
+
MATCHED=1
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
if [ "$MATCHED" = "1" ]; then
|
|
118
|
+
COVERED_COUNT=$((COVERED_COUNT+1))
|
|
119
|
+
else
|
|
120
|
+
UNCOVERED_LIST="${UNCOVERED_LIST}${BIN_BASE} "
|
|
121
|
+
fi
|
|
122
|
+
done <<< "$SEGMENTS"
|
|
123
|
+
|
|
124
|
+
# A "compound" with one or zero meaningful segments isn't worth flagging.
|
|
125
|
+
[ "$TOTAL" -lt 2 ] && exit 0
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
echo "[compound-bash-permission-resolver] Compound bash detected (${TOTAL} components)."
|
|
129
|
+
echo ""
|
|
130
|
+
if [ "$COVERED_COUNT" = "$TOTAL" ]; then
|
|
131
|
+
echo "All ${TOTAL} components match an existing Bash() allow pattern when evaluated"
|
|
132
|
+
echo "individually. The permission prompt is likely Cluster 6 Axis 1 — the matching"
|
|
133
|
+
echo "engine does not recompose compound bash against allow rules per-component."
|
|
134
|
+
echo "(meta-issue #30519 Axis 1; #28240 with 180 reactions)"
|
|
135
|
+
echo ""
|
|
136
|
+
echo "Safe to approve: each component is already covered standalone."
|
|
137
|
+
echo "Note: \"Always Allow\" will save the verbatim compound string,"
|
|
138
|
+
echo "not the per-component patterns — variants of this compound will re-prompt."
|
|
139
|
+
else
|
|
140
|
+
UNCOVERED_TRIMMED=$(printf '%s' "$UNCOVERED_LIST" | sed -E 's/[[:space:]]+$//')
|
|
141
|
+
echo "Coverage: ${COVERED_COUNT} of ${TOTAL} components match an allow pattern."
|
|
142
|
+
echo "Uncovered components (binary names): ${UNCOVERED_TRIMMED}"
|
|
143
|
+
echo ""
|
|
144
|
+
echo "The prompt is firing on the uncovered component(s) above, not on the"
|
|
145
|
+
echo "compound shape itself. Add Bash(<bin>:*) patterns for the uncovered"
|
|
146
|
+
echo "binaries to permissions.allow if you want to skip future prompts."
|
|
147
|
+
fi
|
|
148
|
+
if [ "${CC_COMPOUND_RESOLVER_VERBOSE:-0}" = "1" ]; then
|
|
149
|
+
PCOUNT=$(wc -l < "$PATTERNS_FILE")
|
|
150
|
+
echo ""
|
|
151
|
+
echo "(resolver breakdown: total=${TOTAL} covered=${COVERED_COUNT} patterns_loaded=${PCOUNT})"
|
|
152
|
+
fi
|
|
153
|
+
} >&2
|
|
154
|
+
|
|
155
|
+
# Always exit 0 — this hook never blocks.
|
|
156
|
+
exit 0
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# compound-command-deny-enforcer.sh — Enforce deny rules across compound commands
|
|
4
|
+
# ================================================================
|
|
5
|
+
# PURPOSE:
|
|
6
|
+
# Claude Code's permission system does not catch compound commands.
|
|
7
|
+
# `Bash(git push:*)` in `ask`/`deny` does not match `cd /path && git push`.
|
|
8
|
+
#
|
|
9
|
+
# The harness strips idempotent `cd` prefixes (when cd target == cwd),
|
|
10
|
+
# but `cd /different/path && <denied-cmd>` is NOT stripped, and the
|
|
11
|
+
# permission system evaluates the pre-split string starting with `cd`,
|
|
12
|
+
# matching no deny/ask rule.
|
|
13
|
+
#
|
|
14
|
+
# Reported repeatedly since December 2025:
|
|
15
|
+
# #13371, #28784, #29491, #20085, #37621, and #59498 (May 2026).
|
|
16
|
+
#
|
|
17
|
+
# This hook enforces deny rules at the component level: it splits
|
|
18
|
+
# compound commands and blocks if ANY component matches the deny list.
|
|
19
|
+
#
|
|
20
|
+
# Operator-side fix while the upstream issue remains unresolved.
|
|
21
|
+
#
|
|
22
|
+
# TRIGGER: PreToolUse
|
|
23
|
+
# MATCHER: "Bash"
|
|
24
|
+
#
|
|
25
|
+
# HOW IT WORKS:
|
|
26
|
+
# 1. Splits command on &&, ||, ;
|
|
27
|
+
# 2. Strips leading cd <path> tokens from each component
|
|
28
|
+
# 3. Checks each remaining component against the deny patterns
|
|
29
|
+
# 4. If ANY component matches any pattern → exit 2 (block)
|
|
30
|
+
# 5. Otherwise → exit 0 (no opinion, defer to next hook)
|
|
31
|
+
#
|
|
32
|
+
# CONFIGURATION:
|
|
33
|
+
# Default patterns cover the most common irreversible operations.
|
|
34
|
+
# To add patterns, edit DEFAULT_DENY array below or read from a config file.
|
|
35
|
+
#
|
|
36
|
+
# WHAT THIS HOOK DOES NOT DO:
|
|
37
|
+
# - Replace settings.json deny rules — it complements them by catching
|
|
38
|
+
# the cd-prefixed compound bypass that settings.json misses.
|
|
39
|
+
# - Block all compound commands — only those where a component matches
|
|
40
|
+
# the deny list.
|
|
41
|
+
# - Approve safe commands — that is compound-command-approver.sh's job.
|
|
42
|
+
#
|
|
43
|
+
# RELATED:
|
|
44
|
+
# - compound-command-approver.sh (auto-approves safe compound chains)
|
|
45
|
+
# - banned-command-guard.sh (blocks single banned commands)
|
|
46
|
+
# - GitHub issues #13371, #28784, #29491, #20085, #37621, #59498
|
|
47
|
+
# ================================================================
|
|
48
|
+
|
|
49
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
50
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
51
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
52
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
53
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
54
|
+
_nojq_warned="/tmp/cc-nojq-warned-compound-command-deny-enforcer-$PPID"
|
|
55
|
+
[ -f "$_nojq_warned" ] || {
|
|
56
|
+
echo "WARNING [compound-command-deny-enforcer]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
57
|
+
: > "$_nojq_warned"
|
|
58
|
+
}
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
INPUT=$(cat)
|
|
62
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null || echo "")
|
|
63
|
+
|
|
64
|
+
[ -z "$COMMAND" ] && exit 0
|
|
65
|
+
|
|
66
|
+
# Default deny patterns — irreversible operations the operator should
|
|
67
|
+
# always be prompted about, even when reached via cd-prefixed compound.
|
|
68
|
+
# Each entry is a POSIX ERE matched against each component after cd-stripping.
|
|
69
|
+
DEFAULT_DENY=(
|
|
70
|
+
'git[[:space:]]+push([[:space:]]|$)'
|
|
71
|
+
'git[[:space:]]+reset[[:space:]]+--hard'
|
|
72
|
+
'git[[:space:]]+clean[[:space:]]+-[a-z]*f'
|
|
73
|
+
'git[[:space:]]+filter-(repo|branch)'
|
|
74
|
+
'rm[[:space:]]+-[a-z]*r[a-z]*f'
|
|
75
|
+
'dd[[:space:]]+if=.*of='
|
|
76
|
+
'mkfs(\.|[[:space:]])'
|
|
77
|
+
'>[[:space:]]*/dev/sd[a-z]'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# The rm rule above matches `rm -rf <anything>`, so it also denied the most
|
|
81
|
+
# ordinary cleanup a developer types: `rm -rf node_modules`, `rm -rf dist`,
|
|
82
|
+
# `rm -rf build`, `rm -rf .next`. Measured 2026-08-10: all four exited 2 here,
|
|
83
|
+
# while rm-safety-net and auto-mode-safety-enforcer let the same commands
|
|
84
|
+
# through. A guard that blocks `rm -rf node_modules` does not get tightened by
|
|
85
|
+
# the user — it gets removed, and the cd-prefixed bypass this hook exists for
|
|
86
|
+
# comes back with it.
|
|
87
|
+
#
|
|
88
|
+
# --- why there is no mention-vs-invocation gate here --------------------------
|
|
89
|
+
# auto-mode-safety-enforcer got one in PR #1009 and it works there. It was tried
|
|
90
|
+
# here too and had to be taken out: this hook's deny patterns cover far more than
|
|
91
|
+
# a list of destructive verbs can express, so a gate built from such a list let
|
|
92
|
+
# real things through. CI caught two on 2026-08-11 -- a git subcommand that was
|
|
93
|
+
# not on the list, and a redirect writing to a device. A gate that cannot name
|
|
94
|
+
# everything the hook judges does not narrow the guard, it loosens it.
|
|
95
|
+
#
|
|
96
|
+
# The cost of not having one is a false positive: naming a dangerous command
|
|
97
|
+
# inside quotes (a commit message, an echo into a note) is blocked here. That is
|
|
98
|
+
# recorded in tests/quoted-safe-targets-and-mentions.test.sh as current
|
|
99
|
+
# behaviour. Fixing it means driving the gate off the deny patterns themselves,
|
|
100
|
+
# not off a verb list.
|
|
101
|
+
|
|
102
|
+
# The safe-target list and the match form are taken verbatim from
|
|
103
|
+
# rm-safety-net.sh rather than invented here, so the two hooks cannot drift
|
|
104
|
+
# into disagreeing about what "safe" means.
|
|
105
|
+
SAFE_RM_TARGETS="node_modules|dist|build|__pycache__|\.cache|\.pytest_cache|coverage|\.nyc_output|\.next|\.nuxt|tmp|temp"
|
|
106
|
+
|
|
107
|
+
# Returns 0 only when the component is an rm whose operands are ALL safe.
|
|
108
|
+
# Every operand is inspected, not just the last one: rm-safety-net documents
|
|
109
|
+
# that checking only `awk '{print $NF}'` lets `rm -rf /home/user/data node_modules`
|
|
110
|
+
# pass on its safe last argument. Path traversal disqualifies the whole
|
|
111
|
+
# component, and an rm with no operand at all is never treated as safe.
|
|
112
|
+
rm_targets_all_safe() {
|
|
113
|
+
local comp="$1" arg seen=0
|
|
114
|
+
case "$comp" in *'..'*) return 1 ;; esac
|
|
115
|
+
set -f
|
|
116
|
+
for arg in $(echo "$comp" | sed -E 's/^[[:space:]]*(sudo[[:space:]]+)?rm[[:space:]]+//'); do
|
|
117
|
+
case "$arg" in
|
|
118
|
+
-*) continue ;; # flags
|
|
119
|
+
esac
|
|
120
|
+
seen=1
|
|
121
|
+
# Quotes are dropped before the comparison. The safe list is a list of
|
|
122
|
+
# names, and a name written as "node_modules" is the same name. Without
|
|
123
|
+
# this, every quoted cleanup fell through to the deny patterns.
|
|
124
|
+
# Measured 2026-08-11: four ordinary quoted cleanups were blocked.
|
|
125
|
+
if ! printf '%s' "$arg" | tr -d "\"'" | grep -qE "^(\./)?(${SAFE_RM_TARGETS})/?$"; then
|
|
126
|
+
set +f
|
|
127
|
+
return 1
|
|
128
|
+
fi
|
|
129
|
+
done
|
|
130
|
+
set +f
|
|
131
|
+
[ "$seen" -eq 1 ]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Split on &&, ||, ;
|
|
135
|
+
SPLIT=$(echo "$COMMAND" | sed -E 's/(&&|\|\||;)/\n/g')
|
|
136
|
+
|
|
137
|
+
# Strip leading "cd <path>" from a component
|
|
138
|
+
strip_cd() {
|
|
139
|
+
echo "$1" | sed -E 's/^[[:space:]]*cd[[:space:]]+([^[:space:]&|;]+|"[^"]*"|'\''[^'\'']*'\'')[[:space:]]*//'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Iterate components and check each against deny patterns.
|
|
143
|
+
# Use a here-string + for loop so exit 2 propagates (subshell pipe loses it).
|
|
144
|
+
EXIT_CODE=0
|
|
145
|
+
while IFS= read -r component; do
|
|
146
|
+
[ -z "$component" ] && continue
|
|
147
|
+
|
|
148
|
+
stripped=$(strip_cd "$component")
|
|
149
|
+
[ -z "$stripped" ] && continue
|
|
150
|
+
|
|
151
|
+
for pattern in "${DEFAULT_DENY[@]}"; do
|
|
152
|
+
if echo "$stripped" | grep -qE "$pattern"; then
|
|
153
|
+
# Only the rm rule has a safe-target exemption. The other rules
|
|
154
|
+
# (git push, reset --hard, dd, mkfs, …) have no benign form that
|
|
155
|
+
# this hook should silently allow.
|
|
156
|
+
if [ "$pattern" = 'rm[[:space:]]+-[a-z]*r[a-z]*f' ] && rm_targets_all_safe "$stripped"; then
|
|
157
|
+
continue
|
|
158
|
+
fi
|
|
159
|
+
cat >&2 <<EOF
|
|
160
|
+
BLOCKED: Compound-command deny enforcer matched a denied operation.
|
|
161
|
+
|
|
162
|
+
Full command: $COMMAND
|
|
163
|
+
Component: $stripped
|
|
164
|
+
Matched rule: $pattern
|
|
165
|
+
|
|
166
|
+
This hook catches the cd-prefixed compound bypass documented in
|
|
167
|
+
https://github.com/anthropics/claude-code/issues/59498 (and historical
|
|
168
|
+
#13371, #28784, #29491, #20085, #37621). Settings.json deny rules do
|
|
169
|
+
not match cd-prefixed compounds because the harness does not strip
|
|
170
|
+
cd <path> when path differs from cwd; the permission system then
|
|
171
|
+
evaluates the pre-split string starting with cd and matches no rule.
|
|
172
|
+
|
|
173
|
+
To unblock for one command, run the components separately:
|
|
174
|
+
cd /path
|
|
175
|
+
<denied-command>
|
|
176
|
+
EOF
|
|
177
|
+
EXIT_CODE=2
|
|
178
|
+
break 2
|
|
179
|
+
fi
|
|
180
|
+
done
|
|
181
|
+
done <<< "$SPLIT"
|
|
182
|
+
|
|
183
|
+
exit "$EXIT_CODE"
|
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
# TRIGGER: PreToolUse
|
|
18
18
|
# MATCHER: "Bash"
|
|
19
19
|
|
|
20
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
21
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
22
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
23
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
24
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
25
|
+
_nojq_warned="/tmp/cc-nojq-warned-compound-inject-guard-$PPID"
|
|
26
|
+
[ -f "$_nojq_warned" ] || {
|
|
27
|
+
echo "WARNING [compound-inject-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
28
|
+
: > "$_nojq_warned"
|
|
29
|
+
}
|
|
30
|
+
fi
|
|
31
|
+
|
|
20
32
|
INPUT=$(cat)
|
|
21
33
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
22
34
|
[ -z "$COMMAND" ] && exit 0
|
|
@@ -15,6 +15,18 @@
|
|
|
15
15
|
# TRIGGER: PreToolUse
|
|
16
16
|
# MATCHER: "Edit|Write"
|
|
17
17
|
|
|
18
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
19
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
20
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
21
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
22
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
23
|
+
_nojq_warned="/tmp/cc-nojq-warned-concurrent-edit-lock-$PPID"
|
|
24
|
+
[ -f "$_nojq_warned" ] || {
|
|
25
|
+
echo "WARNING [concurrent-edit-lock]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
26
|
+
: > "$_nojq_warned"
|
|
27
|
+
}
|
|
28
|
+
fi
|
|
29
|
+
|
|
18
30
|
INPUT=$(cat)
|
|
19
31
|
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
20
32
|
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
@@ -10,6 +10,18 @@
|
|
|
10
10
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
11
11
|
# ================================================================
|
|
12
12
|
|
|
13
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
14
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
15
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
16
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
17
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
18
|
+
_nojq_warned="/tmp/cc-nojq-warned-conflict-marker-guard-$PPID"
|
|
19
|
+
[ -f "$_nojq_warned" ] || {
|
|
20
|
+
echo "WARNING [conflict-marker-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
21
|
+
: > "$_nojq_warned"
|
|
22
|
+
}
|
|
23
|
+
fi
|
|
24
|
+
|
|
13
25
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
14
26
|
[ -z "$COMMAND" ] && exit 0
|
|
15
27
|
|
|
File without changes
|