cc-safe-setup 29.8.0 → 30.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-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 +12 -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/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-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-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-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,195 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# authorized-reconfirmation-detector.sh — Measure how often
|
|
3
|
+
# AskUserQuestion fires on an action that the operator's prior turn
|
|
4
|
+
# already authorized.
|
|
5
|
+
#
|
|
6
|
+
# Solves: anthropics/claude-code#61929 (Claude Code makes major design
|
|
7
|
+
# decisions silently but asks for confirmation on trivial things),
|
|
8
|
+
# specifically case (3) in the three-way split articulated in
|
|
9
|
+
# https://github.com/anthropics/claude-code/issues/61929#issuecomment-4549798175 :
|
|
10
|
+
#
|
|
11
|
+
# (1) Genuine fork — model has multiple plausible paths; AUQ is correct
|
|
12
|
+
# (2) Articulation-surface mis-bound — model has the answer (marks
|
|
13
|
+
# "(Recommended)") and uses AUQ to describe its choice rather than
|
|
14
|
+
# delegate it
|
|
15
|
+
# (3) Authorized re-confirmation — operator already said "do X" in the
|
|
16
|
+
# prior turn; model opens AUQ asking "Should I do X?" with
|
|
17
|
+
# "(Recommended) yes"
|
|
18
|
+
#
|
|
19
|
+
# This hook does not block. It measures. The output is one structured
|
|
20
|
+
# log line per detected case (3) — turn timestamp, AUQ question text,
|
|
21
|
+
# matched verb stem, user-message excerpt. That log file becomes the
|
|
22
|
+
# empirical foundation for the eventual UserPromptSubmit-side intent
|
|
23
|
+
# classifier (case 3's primary fix). Case (2) cannot be addressed at
|
|
24
|
+
# Stop without already having shown the menu; that one needs PreToolUse
|
|
25
|
+
# visibility into the AUQ preamble (#61983) to convert the menu into an
|
|
26
|
+
# inline articulation.
|
|
27
|
+
#
|
|
28
|
+
# Detection signature (all three required to log):
|
|
29
|
+
# a) An AskUserQuestion tool call exists in the latest assistant turn.
|
|
30
|
+
# b) At least one of its options carries a "(Recommended)" marker
|
|
31
|
+
# (English) or "推奨" (Japanese).
|
|
32
|
+
# c) The most recent user message contains a content word (length >= 4)
|
|
33
|
+
# that also appears in the AUQ question text. Common stopwords are
|
|
34
|
+
# filtered. This is the "operator already named the action" echo.
|
|
35
|
+
#
|
|
36
|
+
# False positives are intentionally tolerated for measurement — the
|
|
37
|
+
# detector emits an advisory log line, never an exit code, never a block.
|
|
38
|
+
# An operator may have authorized an irreversible action and still want
|
|
39
|
+
# AUQ to fire as a safety re-check; that case will show up in the log
|
|
40
|
+
# and informs the classifier's eventual exclusion list.
|
|
41
|
+
#
|
|
42
|
+
# Related:
|
|
43
|
+
# #61337 (mhernz) — /goal-mode authorization is structurally
|
|
44
|
+
# indistinguishable from prior-message authorization;
|
|
45
|
+
# the load-bearing axis that lets one classifier
|
|
46
|
+
# address both with the same signal.
|
|
47
|
+
# #61983 — preamble visibility constraint that blocks the
|
|
48
|
+
# PreToolUse-AUQ menu-to-articulation conversion
|
|
49
|
+
# (case 2 territory).
|
|
50
|
+
#
|
|
51
|
+
# TRIGGER: Stop
|
|
52
|
+
# MATCHER: ""
|
|
53
|
+
#
|
|
54
|
+
# CONFIGURATION (environment variables):
|
|
55
|
+
# CC_AUTH_RECONF_LOG log file path
|
|
56
|
+
# (default: ~/.claude/audit/authorized-reconfirmation.log)
|
|
57
|
+
# CC_AUTH_RECONF_DISABLE set to "1" to disable entirely
|
|
58
|
+
#
|
|
59
|
+
# USAGE (settings.json):
|
|
60
|
+
# {
|
|
61
|
+
# "hooks": {
|
|
62
|
+
# "Stop": [{
|
|
63
|
+
# "matcher": "",
|
|
64
|
+
# "hooks": [{
|
|
65
|
+
# "type": "command",
|
|
66
|
+
# "command": "~/.claude/hooks/authorized-reconfirmation-detector.sh"
|
|
67
|
+
# }]
|
|
68
|
+
# }]
|
|
69
|
+
# }
|
|
70
|
+
# }
|
|
71
|
+
|
|
72
|
+
set -uo pipefail
|
|
73
|
+
|
|
74
|
+
[ "${CC_AUTH_RECONF_DISABLE:-0}" = "1" ] && exit 0
|
|
75
|
+
|
|
76
|
+
INPUT=$(cat 2>/dev/null || true)
|
|
77
|
+
[ -z "$INPUT" ] && exit 0
|
|
78
|
+
|
|
79
|
+
LOG_FILE="${CC_AUTH_RECONF_LOG:-${HOME}/.claude/audit/authorized-reconfirmation.log}"
|
|
80
|
+
|
|
81
|
+
# Locate AskUserQuestion calls in the latest assistant turn.
|
|
82
|
+
# Transcript shape varies across Claude Code versions; try several keys.
|
|
83
|
+
AUQ_CALLS=$(printf '%s' "$INPUT" | jq -c '
|
|
84
|
+
def latest_assistant:
|
|
85
|
+
([ .transcript[]? | select(.role == "assistant") ] | .[-1])
|
|
86
|
+
// .last_assistant_message
|
|
87
|
+
// {};
|
|
88
|
+
def auq_filter(arr):
|
|
89
|
+
[ arr[]?
|
|
90
|
+
| select((.name // .tool_name // "") == "AskUserQuestion")
|
|
91
|
+
| (.input // .tool_input // {}) ];
|
|
92
|
+
(latest_assistant) as $a
|
|
93
|
+
| (auq_filter($a.tool_calls // [])) as $from_tc
|
|
94
|
+
| (auq_filter($a.content // [])) as $from_content
|
|
95
|
+
| ($from_tc + $from_content)
|
|
96
|
+
' 2>/dev/null)
|
|
97
|
+
|
|
98
|
+
# Nothing to measure if no AUQ this turn.
|
|
99
|
+
if [ -z "$AUQ_CALLS" ] || [ "$AUQ_CALLS" = "null" ] || [ "$AUQ_CALLS" = "[]" ]; then
|
|
100
|
+
exit 0
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Find the most recent user (operator) message text.
|
|
104
|
+
USER_TEXT=$(printf '%s' "$INPUT" | jq -r '
|
|
105
|
+
([ .transcript[]? | select(.role == "user") ] | .[-1]) as $u
|
|
106
|
+
| ($u.content
|
|
107
|
+
| if type == "string" then .
|
|
108
|
+
elif type == "array" then [ .[]? | (.text // .content // "") ] | join(" ")
|
|
109
|
+
else "" end)
|
|
110
|
+
' 2>/dev/null)
|
|
111
|
+
|
|
112
|
+
if [ -z "$USER_TEXT" ] || [ "$USER_TEXT" = "null" ]; then
|
|
113
|
+
USER_TEXT=$(printf '%s' "$INPUT" | jq -r '.last_user_message // empty' 2>/dev/null)
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# No user text → cannot compare → silent exit.
|
|
117
|
+
if [ -z "$USER_TEXT" ] || [ "$USER_TEXT" = "null" ]; then
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
|
|
122
|
+
|
|
123
|
+
# Lowercase the user text once.
|
|
124
|
+
UT=$(printf '%s' "$USER_TEXT" | tr '[:upper:]' '[:lower:]')
|
|
125
|
+
|
|
126
|
+
STOPWORDS='^(should|would|could|with|that|this|from|into|your|have|will|been|were|then|than|when|what|which|while|where|there|please|claude|about|just|like|some|also|even|only|over|under|after|before|both|each|same|other|those|these|right|wrong|maybe|going|doing|done|need|want|sure|okay|yeah|nope|true|false)$'
|
|
127
|
+
|
|
128
|
+
# Walk each AUQ call.
|
|
129
|
+
printf '%s' "$AUQ_CALLS" | jq -c '.[]' 2>/dev/null | while read -r CALL; do
|
|
130
|
+
# Skip empty calls.
|
|
131
|
+
[ -z "$CALL" ] || [ "$CALL" = "null" ] && continue
|
|
132
|
+
|
|
133
|
+
# Recommended-option marker check.
|
|
134
|
+
HAS_RECOMMENDED=$(printf '%s' "$CALL" | jq -r '
|
|
135
|
+
(.questions // []) | .[]? | (.options // []) | .[]?
|
|
136
|
+
| ((.label // "") + " " + (.description // ""))
|
|
137
|
+
' 2>/dev/null | grep -ciE '\(recommended\)|推奨|^recommended\b|\brecommended:' || true)
|
|
138
|
+
HAS_RECOMMENDED=${HAS_RECOMMENDED:-0}
|
|
139
|
+
|
|
140
|
+
# No recommended marker → likely case (1) genuine fork. Skip.
|
|
141
|
+
[ "$HAS_RECOMMENDED" -eq 0 ] && continue
|
|
142
|
+
|
|
143
|
+
# Enumerate every question text in this call.
|
|
144
|
+
QUESTIONS=$(printf '%s' "$CALL" | jq -r '
|
|
145
|
+
(.questions // [{question: (.question // "")}])
|
|
146
|
+
| .[]? | (.question // "")
|
|
147
|
+
| select(length > 0)
|
|
148
|
+
' 2>/dev/null)
|
|
149
|
+
|
|
150
|
+
[ -z "$QUESTIONS" ] && continue
|
|
151
|
+
|
|
152
|
+
while IFS= read -r Q; do
|
|
153
|
+
[ -z "$Q" ] && continue
|
|
154
|
+
|
|
155
|
+
# Content words (length >= 4, alpha) from the AUQ question.
|
|
156
|
+
QWORDS=$(printf '%s' "$Q" | tr '[:upper:]' '[:lower:]' \
|
|
157
|
+
| grep -oE '[a-z]{4,}' | sort -u \
|
|
158
|
+
| grep -vE "$STOPWORDS" || true)
|
|
159
|
+
|
|
160
|
+
[ -z "$QWORDS" ] && continue
|
|
161
|
+
|
|
162
|
+
# Find at least one content word that also appears in the user
|
|
163
|
+
# message.
|
|
164
|
+
MATCHED_WORD=""
|
|
165
|
+
while IFS= read -r W; do
|
|
166
|
+
[ -z "$W" ] && continue
|
|
167
|
+
if printf '%s' "$UT" | grep -qw "$W"; then
|
|
168
|
+
MATCHED_WORD="$W"
|
|
169
|
+
break
|
|
170
|
+
fi
|
|
171
|
+
done <<< "$QWORDS"
|
|
172
|
+
|
|
173
|
+
[ -z "$MATCHED_WORD" ] && continue
|
|
174
|
+
|
|
175
|
+
# Detected. Emit a structured log line.
|
|
176
|
+
TS=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
|
177
|
+
USER_EXCERPT=$(printf '%s' "$USER_TEXT" | tr '\n' ' ' | head -c 240)
|
|
178
|
+
ENTRY=$(jq -nc \
|
|
179
|
+
--arg ts "$TS" \
|
|
180
|
+
--arg q "$Q" \
|
|
181
|
+
--arg word "$MATCHED_WORD" \
|
|
182
|
+
--arg user_excerpt "$USER_EXCERPT" \
|
|
183
|
+
'{
|
|
184
|
+
timestamp: $ts,
|
|
185
|
+
event: "authorized_reconfirmation_detected",
|
|
186
|
+
auq_question: $q,
|
|
187
|
+
matched_word: $word,
|
|
188
|
+
user_excerpt: $user_excerpt
|
|
189
|
+
}' 2>/dev/null)
|
|
190
|
+
|
|
191
|
+
[ -n "$ENTRY" ] && echo "$ENTRY" >> "$LOG_FILE"
|
|
192
|
+
done <<< "$QUESTIONS"
|
|
193
|
+
done
|
|
194
|
+
|
|
195
|
+
exit 0
|
|
@@ -24,6 +24,45 @@ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
|
24
24
|
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
25
25
|
[ -z "$CMD" ] && exit 0
|
|
26
26
|
|
|
27
|
+
# Approve only when EVERY command position qualifies.
|
|
28
|
+
#
|
|
29
|
+
# The patterns below were anchored at `^\s*` and matched against the whole
|
|
30
|
+
# command string, so only the first command position was examined and the
|
|
31
|
+
# approval was then handed to the entire line: `npm test && sudo rm -rf app` was
|
|
32
|
+
# approved on the strength of its first word. Measured 2026-08-03 against the
|
|
33
|
+
# shipped copy. Same defect as PR #937 (allowlist.sh) and PR #940
|
|
34
|
+
# (cd-git-allow.sh), here on the approving side, where the decision is an
|
|
35
|
+
# explicit approval rather than a missed block.
|
|
36
|
+
#
|
|
37
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
38
|
+
# so anything that can hide a command from a string-level read (command
|
|
39
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
40
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
41
|
+
# hook only ever adds approval; it never blocks.
|
|
42
|
+
#
|
|
43
|
+
# The gate uses the union of the three patterns, so a chain of different
|
|
44
|
+
# approved kinds (`npm ci && npm test`) still passes; the if-chain below only
|
|
45
|
+
# picks which branch reports the approval.
|
|
46
|
+
cc_every_segment_matches() {
|
|
47
|
+
local pat="$1" cmd="$2" seg
|
|
48
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
49
|
+
while IFS= read -r seg; do
|
|
50
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
51
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
52
|
+
[ -z "$seg" ] && continue
|
|
53
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
54
|
+
done <<EOF
|
|
55
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
56
|
+
EOF
|
|
57
|
+
return 0
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
BUILD_SAFE_RE='^\s*(npm|yarn|pnpm|bun|npx)\s+(run\s+)?(build|test|lint|check|typecheck|format|dev|start|ci)'
|
|
61
|
+
BUILD_SAFE_RE="$BUILD_SAFE_RE"'|^\s*(cargo\s+(build|test|check|clippy|fmt)|go\s+(build|test|vet|fmt)|make\s+(build|test|check|lint))'
|
|
62
|
+
BUILD_SAFE_RE="$BUILD_SAFE_RE"'|^\s*(python|python3)\s+(-m\s+)?(pytest|unittest|mypy|ruff|black|isort|flake8)'
|
|
63
|
+
|
|
64
|
+
cc_every_segment_matches "$BUILD_SAFE_RE" "$CMD" || exit 0
|
|
65
|
+
|
|
27
66
|
# Auto-approve safe build/test/lint commands
|
|
28
67
|
if echo "$CMD" | grep -qE '^\s*(npm|yarn|pnpm|bun|npx)\s+(run\s+)?(build|test|lint|check|typecheck|format|dev|start|ci)'; then
|
|
29
68
|
echo '{"decision":"approve"}'
|
|
@@ -3,7 +3,37 @@
|
|
|
3
3
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
4
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
5
5
|
[ -z "$COMMAND" ] && exit 0
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
# Approve only when EVERY command position qualifies.
|
|
8
|
+
#
|
|
9
|
+
# The pattern below was anchored at `^\s*` and matched against the whole command
|
|
10
|
+
# string, so only the first command position was examined and the approval was
|
|
11
|
+
# then handed to the entire line: `cargo build && sudo rm -rf app` was approved
|
|
12
|
+
# on the strength of its first word. Measured 2026-08-03 against the shipped
|
|
13
|
+
# copy. Same defect as PR #937 (allowlist.sh) and PR #940 (cd-git-allow.sh),
|
|
14
|
+
# here on the approving side, where the decision is an explicit approval rather
|
|
15
|
+
# than a missed block.
|
|
16
|
+
#
|
|
17
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
18
|
+
# so anything that can hide a command from a string-level read (command
|
|
19
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
20
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
21
|
+
# hook only ever adds approval; it never blocks.
|
|
22
|
+
cc_every_segment_matches() {
|
|
23
|
+
local pat="$1" cmd="$2" seg
|
|
24
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
25
|
+
while IFS= read -r seg; do
|
|
26
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
27
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
28
|
+
[ -z "$seg" ] && continue
|
|
29
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
30
|
+
done <<EOF
|
|
31
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
32
|
+
EOF
|
|
33
|
+
return 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if cc_every_segment_matches '^\s*cargo\s+(build|test|check|clippy|fmt|run|bench|doc|clean)(\s|$)' "$COMMAND"; then
|
|
7
37
|
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"cargo command auto-approved"}}'
|
|
8
38
|
fi
|
|
9
39
|
exit 0
|
|
@@ -6,6 +6,41 @@ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
|
6
6
|
[ "$TOOL" != "Bash" ] && exit 0
|
|
7
7
|
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
8
8
|
[ -z "$CMD" ] && exit 0
|
|
9
|
+
|
|
10
|
+
# Approve only when EVERY command position qualifies.
|
|
11
|
+
#
|
|
12
|
+
# The patterns below were anchored at `^\s*` and matched against the whole
|
|
13
|
+
# command string, so only the first command position was examined and the
|
|
14
|
+
# approval was then handed to the entire line: `docker ps && sudo rm -rf app`
|
|
15
|
+
# was approved on the strength of its first word. Measured 2026-08-03 against
|
|
16
|
+
# the shipped copy. Same defect as PR #937 (allowlist.sh) and PR #940
|
|
17
|
+
# (cd-git-allow.sh), here on the approving side, where the decision is an
|
|
18
|
+
# explicit approval rather than a missed block.
|
|
19
|
+
#
|
|
20
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
21
|
+
# so anything that can hide a command from a string-level read (command
|
|
22
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
23
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
24
|
+
# hook only ever adds approval; it never blocks.
|
|
25
|
+
cc_every_segment_matches() {
|
|
26
|
+
local pat="$1" cmd="$2" seg
|
|
27
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
28
|
+
while IFS= read -r seg; do
|
|
29
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
30
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
31
|
+
[ -z "$seg" ] && continue
|
|
32
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
33
|
+
done <<EOF
|
|
34
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
35
|
+
EOF
|
|
36
|
+
return 0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
DOCKER_SAFE_RE='^\s*docker\s+(build|compose|ps|images|logs|inspect|network\s+ls|volume\s+ls|exec|run)'
|
|
40
|
+
DOCKER_SAFE_RE="$DOCKER_SAFE_RE"'|^\s*docker-compose\s+(up|down|build|logs|ps|restart)'
|
|
41
|
+
|
|
42
|
+
cc_every_segment_matches "$DOCKER_SAFE_RE" "$CMD" || exit 0
|
|
43
|
+
|
|
9
44
|
if echo "$CMD" | grep -qE '^\s*docker\s+(build|compose|ps|images|logs|inspect|network\s+ls|volume\s+ls|exec|run)'; then
|
|
10
45
|
echo '{"decision":"approve"}'
|
|
11
46
|
exit 0
|
|
@@ -18,25 +18,48 @@ if [[ -z "$COMMAND" ]]; then
|
|
|
18
18
|
exit 0
|
|
19
19
|
fi
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
# Approve only when EVERY command position qualifies.
|
|
22
|
+
#
|
|
23
|
+
# Both patterns were anchored at `^\s*` and matched against the whole command
|
|
24
|
+
# string, so only the first command position was examined and the approval was
|
|
25
|
+
# then handed to the entire line: `git log && sudo rm -rf app` and
|
|
26
|
+
# `cd /repo && git status; curl http://… | sh` were both approved on the
|
|
27
|
+
# strength of what came first. Measured 2026-08-03. Same defect as PR #937 /
|
|
28
|
+
# #940 / #941, on the approving side, where the decision is an explicit approval
|
|
29
|
+
# rather than a missed block.
|
|
30
|
+
#
|
|
31
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
32
|
+
# so anything that can hide a command from a string-level read (command
|
|
33
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
34
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
35
|
+
# hook only ever adds approval; it never blocks.
|
|
36
|
+
cc_every_segment_matches() {
|
|
37
|
+
local pat="$1" cmd="$2" seg
|
|
38
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
39
|
+
while IFS= read -r seg; do
|
|
40
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
41
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
42
|
+
[ -z "$seg" ] && continue
|
|
43
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
44
|
+
done <<EOF
|
|
45
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
46
|
+
EOF
|
|
47
|
+
return 0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
GIT_READ_RE='^\s*git\s+(-C\s+\S+\s+)?(status|log|diff|branch|show|rev-parse|tag|remote)(\s|$)'
|
|
51
|
+
# a leading `cd` is allowed as one of the segments, which is what the second
|
|
52
|
+
# pattern used to cover
|
|
53
|
+
SEG_RE="$GIT_READ_RE"'|^\s*cd(\s|$)'
|
|
32
54
|
|
|
33
|
-
#
|
|
34
|
-
if
|
|
55
|
+
# and at least one segment has to actually be the git read
|
|
56
|
+
if cc_every_segment_matches "$SEG_RE" "$COMMAND" \
|
|
57
|
+
&& printf '%s' "$COMMAND" | grep -qE '(^|[;&|])\s*git\s'; then
|
|
35
58
|
jq -n '{
|
|
36
59
|
hookSpecificOutput: {
|
|
37
60
|
hookEventName: "PreToolUse",
|
|
38
61
|
permissionDecision: "allow",
|
|
39
|
-
permissionDecisionReason: "
|
|
62
|
+
permissionDecisionReason: "git read-only auto-approved"
|
|
40
63
|
}
|
|
41
64
|
}'
|
|
42
65
|
exit 0
|
|
@@ -3,7 +3,36 @@
|
|
|
3
3
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
4
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
5
5
|
[ -z "$COMMAND" ] && exit 0
|
|
6
|
-
|
|
6
|
+
# Approve only when EVERY command position qualifies.
|
|
7
|
+
#
|
|
8
|
+
# The pattern below was anchored at `^\s*` and matched against the whole command
|
|
9
|
+
# string, so only the first command position was examined and the approval was
|
|
10
|
+
# then handed to the entire line: `go test ./... && sudo rm -rf app` was
|
|
11
|
+
# approved on the strength of its first word. Measured 2026-08-03 against the
|
|
12
|
+
# shipped copy. Same defect as PR #937 (allowlist.sh) and PR #940
|
|
13
|
+
# (cd-git-allow.sh), here on the approving side, where the decision is an
|
|
14
|
+
# explicit approval rather than a missed block.
|
|
15
|
+
#
|
|
16
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
17
|
+
# so anything that can hide a command from a string-level read (command
|
|
18
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
19
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
20
|
+
# hook only ever adds approval; it never blocks.
|
|
21
|
+
cc_every_segment_matches() {
|
|
22
|
+
local pat="$1" cmd="$2" seg
|
|
23
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
24
|
+
while IFS= read -r seg; do
|
|
25
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
26
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
27
|
+
[ -z "$seg" ] && continue
|
|
28
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
29
|
+
done <<EOF
|
|
30
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
31
|
+
EOF
|
|
32
|
+
return 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if cc_every_segment_matches '^\s*go\s+(build|test|vet|fmt|mod|run|generate|install|clean)(\s|$)' "$COMMAND"; then
|
|
7
36
|
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"go command auto-approved"}}'
|
|
8
37
|
fi
|
|
9
38
|
exit 0
|
|
@@ -3,7 +3,35 @@
|
|
|
3
3
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
4
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
5
5
|
[ -z "$COMMAND" ] && exit 0
|
|
6
|
-
|
|
6
|
+
# Approve only when EVERY command position qualifies.
|
|
7
|
+
#
|
|
8
|
+
# The pattern below was anchored at `^\s*` and matched against the whole command
|
|
9
|
+
# string, so only the first command position was examined and the approval was
|
|
10
|
+
# then handed to the entire line: `gradle build && sudo rm -rf app` was approved
|
|
11
|
+
# on the strength of its first word. Measured 2026-08-03. Same defect as
|
|
12
|
+
# PR #937 / #940 / #941, on the approving side, where the decision is an
|
|
13
|
+
# explicit approval rather than a missed block.
|
|
14
|
+
#
|
|
15
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
16
|
+
# so anything that can hide a command from a string-level read (command
|
|
17
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
18
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
19
|
+
# hook only ever adds approval; it never blocks.
|
|
20
|
+
cc_every_segment_matches() {
|
|
21
|
+
local pat="$1" cmd="$2" seg
|
|
22
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
23
|
+
while IFS= read -r seg; do
|
|
24
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
25
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
26
|
+
[ -z "$seg" ] && continue
|
|
27
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
28
|
+
done <<EOF
|
|
29
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
30
|
+
EOF
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if cc_every_segment_matches '^\s*(gradle|gradlew|./gradlew)\s+(build|test|check|assemble|clean|compileJava|compileKotlin|lint)(\s|$)' "$COMMAND"; then
|
|
7
35
|
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"gradle command auto-approved"}}'
|
|
8
36
|
fi
|
|
9
37
|
exit 0
|
|
@@ -3,7 +3,35 @@
|
|
|
3
3
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
4
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
5
5
|
[ -z "$COMMAND" ] && exit 0
|
|
6
|
-
|
|
6
|
+
# Approve only when EVERY command position qualifies.
|
|
7
|
+
#
|
|
8
|
+
# The pattern below was anchored at `^\s*` and matched against the whole command
|
|
9
|
+
# string, so only the first command position was examined and the approval was
|
|
10
|
+
# then handed to the entire line: `make test && sudo rm -rf app` was approved on
|
|
11
|
+
# the strength of its first word. Measured 2026-08-03. Same defect as
|
|
12
|
+
# PR #937 / #940 / #941, on the approving side, where the decision is an
|
|
13
|
+
# explicit approval rather than a missed block.
|
|
14
|
+
#
|
|
15
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
16
|
+
# so anything that can hide a command from a string-level read (command
|
|
17
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
18
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
19
|
+
# hook only ever adds approval; it never blocks.
|
|
20
|
+
cc_every_segment_matches() {
|
|
21
|
+
local pat="$1" cmd="$2" seg
|
|
22
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
23
|
+
while IFS= read -r seg; do
|
|
24
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
25
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
26
|
+
[ -z "$seg" ] && continue
|
|
27
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
28
|
+
done <<EOF
|
|
29
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
30
|
+
EOF
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if cc_every_segment_matches '^\s*make\s+(build|test|lint|format|check|clean|install|all|dev|start|run)(\s|$)' "$COMMAND"; then
|
|
7
35
|
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"make target auto-approved"}}'
|
|
8
36
|
fi
|
|
9
37
|
exit 0
|
|
@@ -3,7 +3,35 @@
|
|
|
3
3
|
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
4
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
5
5
|
[ -z "$COMMAND" ] && exit 0
|
|
6
|
-
|
|
6
|
+
# Approve only when EVERY command position qualifies.
|
|
7
|
+
#
|
|
8
|
+
# The pattern below was anchored at `^\s*` and matched against the whole command
|
|
9
|
+
# string, so only the first command position was examined and the approval was
|
|
10
|
+
# then handed to the entire line: `mvn test && sudo rm -rf app` was approved on
|
|
11
|
+
# the strength of its first word. Measured 2026-08-03. Same defect as
|
|
12
|
+
# PR #937 / #940 / #941, on the approving side, where the decision is an
|
|
13
|
+
# explicit approval rather than a missed block.
|
|
14
|
+
#
|
|
15
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
16
|
+
# so anything that can hide a command from a string-level read (command
|
|
17
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
18
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
19
|
+
# hook only ever adds approval; it never blocks.
|
|
20
|
+
cc_every_segment_matches() {
|
|
21
|
+
local pat="$1" cmd="$2" seg
|
|
22
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
23
|
+
while IFS= read -r seg; do
|
|
24
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
25
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
26
|
+
[ -z "$seg" ] && continue
|
|
27
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
28
|
+
done <<EOF
|
|
29
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
30
|
+
EOF
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if cc_every_segment_matches '^\s*(mvn|mvnw|./mvnw)\s+(compile|test|verify|package|clean|install)(\s|$)' "$COMMAND"; then
|
|
7
35
|
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"maven command auto-approved"}}'
|
|
8
36
|
fi
|
|
9
37
|
exit 0
|
|
@@ -15,13 +15,53 @@
|
|
|
15
15
|
# }
|
|
16
16
|
# }
|
|
17
17
|
#
|
|
18
|
-
# TRIGGER:
|
|
18
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
19
19
|
|
|
20
20
|
INPUT=$(cat)
|
|
21
21
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
22
22
|
|
|
23
23
|
[[ -z "$COMMAND" ]] && exit 0
|
|
24
24
|
|
|
25
|
+
# Approve only when EVERY command position qualifies.
|
|
26
|
+
#
|
|
27
|
+
# The patterns below were anchored at `^\s*` and matched against the whole
|
|
28
|
+
# command string, so only the first command position was examined and the
|
|
29
|
+
# approval was then handed to the entire line: `pytest && sudo rm -rf app` was
|
|
30
|
+
# approved on the strength of its first word. Measured 2026-08-03 against the
|
|
31
|
+
# shipped copy. Same defect as PR #937 (allowlist.sh) and PR #940
|
|
32
|
+
# (cd-git-allow.sh), here on the approving side, where the decision is an
|
|
33
|
+
# explicit approval rather than a missed block.
|
|
34
|
+
#
|
|
35
|
+
# Splitting on the separator characters is approximate — quotes are not parsed —
|
|
36
|
+
# so anything that can hide a command from a string-level read (command
|
|
37
|
+
# substitution, backticks) disqualifies the line outright. A line that does not
|
|
38
|
+
# qualify gets no decision, which leaves it to the normal permission flow. This
|
|
39
|
+
# hook only ever adds approval; it never blocks.
|
|
40
|
+
#
|
|
41
|
+
# The gate uses the union of the four patterns, so a chain of different approved
|
|
42
|
+
# kinds (`ruff check . && pytest`) still passes; the if-chain below only picks
|
|
43
|
+
# which reason to report.
|
|
44
|
+
cc_every_segment_matches() {
|
|
45
|
+
local pat="$1" cmd="$2" seg
|
|
46
|
+
case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
|
|
47
|
+
while IFS= read -r seg; do
|
|
48
|
+
seg="${seg#"${seg%%[![:space:]]*}"}"
|
|
49
|
+
seg="${seg%"${seg##*[![:space:]]}"}"
|
|
50
|
+
[ -z "$seg" ] && continue
|
|
51
|
+
printf '%s' "$seg" | grep -qE "$pat" || return 1
|
|
52
|
+
done <<EOF
|
|
53
|
+
$(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
|
|
54
|
+
EOF
|
|
55
|
+
return 0
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
PY_SAFE_RE='^\s*(pytest|python\s+-m\s+pytest|python\s+-m\s+unittest)(\s|$)'
|
|
59
|
+
PY_SAFE_RE="$PY_SAFE_RE"'|^\s*(ruff\s+(check|format)|black\s|isort\s|flake8\s|pylint\s|mypy\s|pyright\s)'
|
|
60
|
+
PY_SAFE_RE="$PY_SAFE_RE"'|^\s*(pip\s+list|pip\s+show|pip\s+freeze|pipdeptree)(\s|$)'
|
|
61
|
+
PY_SAFE_RE="$PY_SAFE_RE"'|^\s*python3?\s+-m\s+py_compile\s'
|
|
62
|
+
|
|
63
|
+
cc_every_segment_matches "$PY_SAFE_RE" "$COMMAND" || exit 0
|
|
64
|
+
|
|
25
65
|
# Python test runners
|
|
26
66
|
if echo "$COMMAND" | grep -qE '^\s*(pytest|python\s+-m\s+pytest|python\s+-m\s+unittest)(\s|$)'; then
|
|
27
67
|
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"Python test auto-approved"}}'
|