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