cc-safe-setup 29.6.32 → 29.6.36
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/COOKBOOK.md +70 -0
- package/README.md +6 -2
- package/examples/absolute-rule-enforcer.sh +42 -0
- package/examples/allow-claude-settings.sh +2 -0
- package/examples/allow-git-hooks-dir.sh +2 -0
- package/examples/allow-protected-dirs.sh +2 -0
- package/examples/allowlist.sh +2 -0
- package/examples/ansible-vault-guard.sh +2 -0
- package/examples/auto-approve-build.sh +2 -0
- package/examples/auto-approve-compound-git.sh +2 -0
- package/examples/auto-approve-docker.sh +2 -0
- package/examples/auto-approve-git-read.sh +2 -0
- package/examples/auto-approve-python.sh +2 -0
- package/examples/auto-approve-readonly-tools.sh +2 -0
- package/examples/auto-approve-ssh.sh +2 -0
- package/examples/auto-approve-test.sh +2 -0
- package/examples/auto-checkpoint.sh +2 -0
- package/examples/auto-git-checkpoint.sh +2 -0
- package/examples/auto-mode-safe-commands.sh +2 -0
- package/examples/auto-snapshot.sh +2 -0
- package/examples/backup-before-refactor.sh +2 -0
- package/examples/banned-command-guard.sh +3 -3
- package/examples/bash-domain-allowlist.sh +72 -0
- package/examples/bash-safety-auto-deny.sh +56 -0
- package/examples/bash-secret-output-detector.sh +68 -0
- package/examples/bash-timeout-guard.sh +2 -0
- package/examples/bashrc-safety-check.sh +59 -0
- package/examples/bg-task-cooldown-guard.sh +46 -0
- package/examples/block-database-wipe.sh +2 -0
- package/examples/branch-name-check.sh +2 -0
- package/examples/branch-naming-convention.sh +2 -0
- package/examples/cargo-publish-guard.sh +2 -0
- package/examples/check-abort-controller.sh +2 -0
- package/examples/check-accessibility.sh +2 -0
- package/examples/check-aria-labels.sh +2 -0
- package/examples/check-async-await-consistency.sh +2 -0
- package/examples/check-before-act-enforcer.sh +47 -0
- package/examples/check-charset-meta.sh +2 -0
- package/examples/check-cleanup-effect.sh +2 -0
- package/examples/check-content-type.sh +2 -0
- package/examples/check-controlled-input.sh +2 -0
- package/examples/check-cookie-flags.sh +2 -0
- package/examples/check-cors-config.sh +2 -0
- package/examples/check-csp-headers.sh +2 -0
- package/examples/check-csrf-protection.sh +2 -0
- package/examples/check-debounce.sh +2 -0
- package/examples/check-dependency-age.sh +2 -0
- package/examples/check-dependency-license.sh +2 -0
- package/examples/check-dockerfile-best-practice.sh +2 -0
- package/examples/check-error-boundaries.sh +2 -0
- package/examples/check-error-class.sh +2 -0
- package/examples/check-error-handling.sh +2 -0
- package/examples/check-error-logging.sh +2 -0
- package/examples/check-error-message.sh +2 -0
- package/examples/check-error-page.sh +2 -0
- package/examples/check-error-stack.sh +2 -0
- package/examples/check-favicon.sh +2 -0
- package/examples/check-form-validation.sh +2 -0
- package/examples/check-git-hooks-compat.sh +2 -0
- package/examples/check-https-redirect.sh +2 -0
- package/examples/check-image-optimization.sh +2 -0
- package/examples/check-input-validation.sh +2 -0
- package/examples/check-key-prop.sh +2 -0
- package/examples/check-lang-attribute.sh +2 -0
- package/examples/check-lazy-loading.sh +2 -0
- package/examples/check-loading-state.sh +2 -0
- package/examples/check-memo-deps.sh +2 -0
- package/examples/check-meta-description.sh +2 -0
- package/examples/check-npm-scripts-exist.sh +2 -0
- package/examples/check-null-check.sh +2 -0
- package/examples/check-package-size.sh +2 -0
- package/examples/check-pagination.sh +2 -0
- package/examples/check-port-availability.sh +2 -0
- package/examples/check-promise-all.sh +2 -0
- package/examples/check-prop-types.sh +2 -0
- package/examples/check-rate-limiting.sh +2 -0
- package/examples/check-responsive-design.sh +2 -0
- package/examples/check-retry-logic.sh +2 -0
- package/examples/check-return-types.sh +2 -0
- package/examples/check-semantic-html.sh +2 -0
- package/examples/check-semantic-versioning.sh +2 -0
- package/examples/check-suspense-fallback.sh +2 -0
- package/examples/check-test-naming.sh +2 -0
- package/examples/check-timeout-cleanup.sh +2 -0
- package/examples/check-tls-version.sh +2 -0
- package/examples/check-type-coercion.sh +2 -0
- package/examples/check-unsubscribe.sh +2 -0
- package/examples/check-viewport-meta.sh +2 -0
- package/examples/check-worker-terminate.sh +2 -0
- package/examples/checkpoint-tamper-guard.sh +2 -0
- package/examples/chmod-guard.sh +2 -0
- package/examples/chown-guard.sh +2 -0
- package/examples/ci-workflow-guard.sh +59 -0
- package/examples/classifier-fallback-allow.sh +2 -0
- package/examples/claude-cache-gc.sh +15 -0
- package/examples/claudeignore-enforce-guard.sh +60 -0
- package/examples/claudemd-enforcer.sh +2 -0
- package/examples/claudemd-violation-detector.sh +36 -0
- package/examples/clear-command-confirm-guard.sh +21 -0
- package/examples/commit-message-check.sh +2 -0
- package/examples/compact-blocker.sh +25 -0
- package/examples/composer-guard.sh +2 -0
- package/examples/compound-command-allow.sh +2 -0
- package/examples/consecutive-failure-circuit-breaker.sh +49 -0
- package/examples/console-log-count.sh +2 -0
- package/examples/context-compact-advisor.sh +16 -0
- package/examples/core-file-protect-guard.sh +91 -0
- package/examples/cors-star-warn.sh +2 -0
- package/examples/credential-exfil-guard.sh +2 -0
- package/examples/credential-file-cat-guard.sh +2 -0
- package/examples/cron-modification-guard.sh +40 -0
- package/examples/cwd-drift-detector.sh +47 -0
- package/examples/cwd-project-boundary-guard.sh +50 -0
- package/examples/denied-action-retry-guard.sh +41 -0
- package/examples/dependency-install-guard.sh +2 -0
- package/examples/deploy-guard.sh +2 -0
- package/examples/deploy-path-verify-guard.sh +62 -0
- package/examples/deployment-verify-guard.sh +81 -0
- package/examples/django-migrate-guard.sh +2 -0
- package/examples/docker-volume-guard.sh +2 -0
- package/examples/dockerfile-latest-guard.sh +2 -0
- package/examples/dotenv-commit-guard.sh +44 -0
- package/examples/dotenv-example-sync.sh +55 -0
- package/examples/dotnet-build-on-edit.sh +2 -0
- package/examples/drizzle-migrate-guard.sh +2 -0
- package/examples/edit-counter-test-gate.sh +44 -0
- package/examples/edit-error-counter.sh +2 -0
- package/examples/edit-guard.sh +2 -0
- package/examples/edit-old-string-validator.sh +37 -0
- package/examples/edit-retry-loop-guard.sh +2 -0
- package/examples/edit-verify.sh +2 -0
- package/examples/encoding-preserve-guard.sh +34 -0
- package/examples/enforce-tests.sh +2 -0
- package/examples/env-inherit-guard.sh +2 -0
- package/examples/env-inline-secret-guard.sh +36 -0
- package/examples/env-prod-guard.sh +2 -0
- package/examples/env-required-check.sh +2 -0
- package/examples/env-var-check.sh +2 -0
- package/examples/expo-eject-guard.sh +2 -0
- package/examples/export-overwrite-guard.sh +29 -0
- package/examples/file-change-tracker.sh +2 -0
- package/examples/file-change-undo-tracker.sh +46 -0
- package/examples/file-recycle-bin.sh +48 -0
- package/examples/file-size-limit.sh +2 -0
- package/examples/five-hundred-milestone.sh +2 -0
- package/examples/flask-debug-guard.sh +2 -0
- package/examples/gem-push-guard.sh +2 -0
- package/examples/git-checkout-safety-guard.sh +2 -0
- package/examples/git-config-guard.sh +2 -0
- package/examples/git-crypt-worktree-guard.sh +36 -0
- package/examples/git-hook-bypass-guard.sh +2 -0
- package/examples/git-merge-conflict-prevent.sh +2 -0
- package/examples/git-message-length.sh +2 -0
- package/examples/git-operations-require-approval.sh +99 -0
- package/examples/git-show-flag-sanitizer.sh +41 -0
- package/examples/git-stash-before-danger.sh +2 -0
- package/examples/git-submodule-guard.sh +2 -0
- package/examples/git-tag-guard.sh +2 -0
- package/examples/github-actions-secret-guard.sh +59 -0
- package/examples/gitignore-check.sh +2 -0
- package/examples/gitops-drift-guard.sh +53 -0
- package/examples/go-mod-tidy-warn.sh +2 -0
- package/examples/hallucination-url-check.sh +2 -0
- package/examples/hardcoded-ip-guard.sh +2 -0
- package/examples/headless-empty-result-guard.sh +46 -0
- package/examples/headless-stop-guard.sh +43 -0
- package/examples/helm-install-guard.sh +2 -0
- package/examples/issue-draft-redact-guard.sh +45 -0
- package/examples/java-compile-on-edit.sh +2 -0
- package/examples/k8s-production-guard.sh +77 -0
- package/examples/laravel-artisan-guard.sh +2 -0
- package/examples/large-file-guard.sh +2 -0
- package/examples/line-ending-guard.sh +30 -0
- package/examples/log-level-guard.sh +2 -0
- package/examples/magic-number-warn.sh +2 -0
- package/examples/max-edit-size-guard.sh +2 -0
- package/examples/max-file-count-guard.sh +2 -0
- package/examples/max-file-delete-count.sh +2 -0
- package/examples/max-function-length.sh +2 -0
- package/examples/max-import-count.sh +2 -0
- package/examples/max-subagent-count.sh +2 -0
- package/examples/mcp-orphan-process-guard.sh +39 -0
- package/examples/mcp-server-allowlist.sh +45 -0
- package/examples/mcp-tool-audit-log.sh +41 -0
- package/examples/mcp-tool-guard.sh +2 -0
- package/examples/migration-verify-guard.sh +44 -0
- package/examples/monorepo-scope-guard.sh +2 -0
- package/examples/network-exfil-guard.sh +61 -0
- package/examples/network-guard.sh +2 -0
- package/examples/nextjs-env-guard.sh +2 -0
- package/examples/no-absolute-import.sh +2 -0
- package/examples/no-alert-confirm-prompt.sh +2 -0
- package/examples/no-any-type.sh +2 -0
- package/examples/no-any-typescript.sh +2 -0
- package/examples/no-assignment-in-condition.sh +2 -0
- package/examples/no-callback-hell.sh +2 -0
- package/examples/no-catch-all-route.sh +2 -0
- package/examples/no-circular-dependency.sh +2 -0
- package/examples/no-class-in-functional.sh +2 -0
- package/examples/no-cleartext-storage.sh +2 -0
- package/examples/no-commented-code.sh +2 -0
- package/examples/no-commit-fixup.sh +2 -0
- package/examples/no-console-assert.sh +2 -0
- package/examples/no-console-error-swallow.sh +2 -0
- package/examples/no-console-in-prod.sh +2 -0
- package/examples/no-console-log.sh +2 -0
- package/examples/no-console-time.sh +2 -0
- package/examples/no-cors-wildcard.sh +2 -0
- package/examples/no-curl-upload.sh +2 -0
- package/examples/no-dangerouslySetInnerHTML.sh +2 -0
- package/examples/no-dangling-await.sh +2 -0
- package/examples/no-debug-in-commit.sh +2 -0
- package/examples/no-deep-nesting.sh +2 -0
- package/examples/no-deep-relative-import.sh +2 -0
- package/examples/no-default-credentials.sh +2 -0
- package/examples/no-deprecated-api.sh +2 -0
- package/examples/no-direct-dom-manipulation.sh +2 -0
- package/examples/no-disabled-test.sh +2 -0
- package/examples/no-document-cookie.sh +2 -0
- package/examples/no-document-write.sh +2 -0
- package/examples/no-empty-function.sh +2 -0
- package/examples/no-eval-in-template.sh +2 -0
- package/examples/no-eval-template.sh +2 -0
- package/examples/no-eval.sh +2 -0
- package/examples/no-exec-user-input.sh +2 -0
- package/examples/no-expose-internal-ids.sh +2 -0
- package/examples/no-floating-promises.sh +2 -0
- package/examples/no-force-install.sh +2 -0
- package/examples/no-git-rebase-public.sh +2 -0
- package/examples/no-global-state.sh +2 -0
- package/examples/no-hardcoded-port.sh +2 -0
- package/examples/no-hardcoded-url.sh +2 -0
- package/examples/no-helmet-missing.sh +2 -0
- package/examples/no-http-url.sh +2 -0
- package/examples/no-http-without-https.sh +2 -0
- package/examples/no-index-as-key.sh +2 -0
- package/examples/no-infinite-scroll-mem.sh +2 -0
- package/examples/no-inline-event-handler.sh +2 -0
- package/examples/no-inline-handler.sh +2 -0
- package/examples/no-inline-style.sh +2 -0
- package/examples/no-inline-styles.sh +2 -0
- package/examples/no-innerhtml.sh +2 -0
- package/examples/no-install-global.sh +2 -0
- package/examples/no-jwt-in-url.sh +2 -0
- package/examples/no-large-commit.sh +2 -0
- package/examples/no-localhost-expose.sh +2 -0
- package/examples/no-long-switch.sh +2 -0
- package/examples/no-magic-number.sh +2 -0
- package/examples/no-md5-sha1.sh +2 -0
- package/examples/no-memory-leak-interval.sh +2 -0
- package/examples/no-mixed-line-endings.sh +2 -0
- package/examples/no-mutation-in-reducer.sh +2 -0
- package/examples/no-mutation-observer-leak.sh +2 -0
- package/examples/no-nested-subscribe.sh +2 -0
- package/examples/no-nested-ternary.sh +2 -0
- package/examples/no-network-exfil.sh +2 -0
- package/examples/no-new-array-fill.sh +2 -0
- package/examples/no-object-freeze-mutation.sh +2 -0
- package/examples/no-open-redirect.sh +2 -0
- package/examples/no-output-truncation.sh +44 -0
- package/examples/no-package-downgrade.sh +2 -0
- package/examples/no-package-lock-edit.sh +2 -0
- package/examples/no-path-join-user-input.sh +2 -0
- package/examples/no-port-bind.sh +2 -0
- package/examples/no-process-exit.sh +2 -0
- package/examples/no-prototype-pollution.sh +2 -0
- package/examples/no-push-without-ci.sh +2 -0
- package/examples/no-raw-ref.sh +2 -0
- package/examples/no-redundant-fragment.sh +2 -0
- package/examples/no-render-in-loop.sh +2 -0
- package/examples/no-root-user-docker.sh +2 -0
- package/examples/no-root-write.sh +2 -0
- package/examples/no-secrets-in-args.sh +2 -0
- package/examples/no-secrets-in-logs.sh +2 -0
- package/examples/no-sensitive-log.sh +2 -0
- package/examples/no-side-effects-in-render.sh +2 -0
- package/examples/no-sleep-in-hooks.sh +2 -0
- package/examples/no-star-import-python.sh +2 -0
- package/examples/no-string-concat-sql.sh +2 -0
- package/examples/no-sudo-guard.sh +2 -0
- package/examples/no-sync-external-call.sh +2 -0
- package/examples/no-sync-fs.sh +2 -0
- package/examples/no-table-layout.sh +2 -0
- package/examples/no-throw-string.sh +2 -0
- package/examples/no-todo-in-merge.sh +2 -0
- package/examples/no-todo-in-production.sh +2 -0
- package/examples/no-todo-without-issue.sh +2 -0
- package/examples/no-triple-slash-ref.sh +2 -0
- package/examples/no-unreachable-code.sh +2 -0
- package/examples/no-unused-import.sh +2 -0
- package/examples/no-unused-state.sh +2 -0
- package/examples/no-var-keyword.sh +2 -0
- package/examples/no-wildcard-cors.sh +2 -0
- package/examples/no-wildcard-import.sh +2 -0
- package/examples/no-window-location.sh +2 -0
- package/examples/no-with-statement.sh +2 -0
- package/examples/no-write-outside-src.sh +2 -0
- package/examples/no-xml-external-entity.sh +2 -0
- package/examples/notify-waiting.sh +2 -0
- package/examples/npm-audit-warn.sh +2 -0
- package/examples/npm-publish-guard.sh +2 -0
- package/examples/npm-script-injection.sh +2 -0
- package/examples/npm-supply-chain-guard.sh +92 -0
- package/examples/nuxt-config-guard.sh +2 -0
- package/examples/output-secret-mask.sh +2 -0
- package/examples/package-json-guard.sh +2 -0
- package/examples/parallel-session-guard.sh +2 -0
- package/examples/path-traversal-guard.sh +2 -0
- package/examples/permission-audit-log.sh +2 -0
- package/examples/permission-entry-validator.sh +48 -0
- package/examples/permission-pattern-auto-allow.sh +50 -0
- package/examples/php-lint-on-edit.sh +2 -0
- package/examples/pip-publish-guard.sh +2 -0
- package/examples/plain-language-danger-warn.sh +37 -0
- package/examples/plan-mode-enforcer.sh +2 -0
- package/examples/plugin-process-cleanup.sh +50 -0
- package/examples/polyglot-rm-guard.sh +59 -0
- package/examples/pr-description-check.sh +2 -0
- package/examples/pre-compact-knowledge-save.sh +53 -0
- package/examples/pre-compact-transcript-export.sh +85 -0
- package/examples/prefer-builtin-tools.sh +2 -0
- package/examples/prefer-const.sh +2 -0
- package/examples/prefer-dedicated-tools.sh +55 -0
- package/examples/prefer-optional-chaining.sh +2 -0
- package/examples/prisma-migrate-guard.sh +2 -0
- package/examples/prompt-injection-detector.sh +2 -0
- package/examples/prompt-length-guard.sh +2 -0
- package/examples/protect-dotfiles.sh +2 -0
- package/examples/public-repo-push-guard.sh +58 -0
- package/examples/push-requires-test-pass-record.sh +2 -0
- package/examples/push-requires-test-pass.sh +2 -0
- package/examples/rails-migration-guard.sh +2 -0
- package/examples/rate-limit-guard.sh +2 -0
- package/examples/read-all-files-enforcer.sh +51 -0
- package/examples/read-audit-log.sh +34 -0
- package/examples/readme-exists-check.sh +2 -0
- package/examples/redis-flushall-guard.sh +2 -0
- package/examples/rm-safety-net.sh +2 -0
- package/examples/role-tool-guard.sh +69 -0
- package/examples/ruby-lint-on-edit.sh +2 -0
- package/examples/schema-migration-guard.sh +57 -0
- package/examples/scope-guard.sh +2 -0
- package/examples/secret-file-read-guard.sh +74 -0
- package/examples/self-modify-bypass-guard.sh +54 -0
- package/examples/sensitive-log-guard.sh +2 -0
- package/examples/session-checkpoint.sh +2 -0
- package/examples/session-duration-guard.sh +51 -0
- package/examples/session-end-logger.sh +57 -0
- package/examples/session-error-rate-monitor.sh +65 -0
- package/examples/session-health-monitor.sh +61 -0
- package/examples/session-memory-watchdog.sh +17 -0
- package/examples/session-permission-reset-guard.sh +39 -0
- package/examples/session-resume-env-fix.sh +49 -0
- package/examples/session-state-saver.sh +2 -0
- package/examples/session-summary-stop.sh +2 -0
- package/examples/session-summary.sh +2 -0
- package/examples/session-token-counter.sh +2 -0
- package/examples/settings-auto-backup.sh +53 -0
- package/examples/settings-mutation-detector.sh +45 -0
- package/examples/shell-wrapper-guard.sh +2 -0
- package/examples/skill-gate.sh +2 -0
- package/examples/skill-injection-detector.sh +41 -0
- package/examples/spec-file-scope-guard.sh +69 -0
- package/examples/spring-profile-guard.sh +2 -0
- package/examples/sql-injection-detect.sh +2 -0
- package/examples/subagent-budget-guard.sh +2 -0
- package/examples/subagent-claudemd-inject.sh +45 -0
- package/examples/subagent-context-size-guard.sh +26 -0
- package/examples/subagent-tool-call-limiter.sh +48 -0
- package/examples/svelte-lint-on-edit.sh +2 -0
- package/examples/swift-build-on-edit.sh +2 -0
- package/examples/symlink-protect.sh +12 -0
- package/examples/system-message-workaround.sh +44 -0
- package/examples/system-package-guard.sh +2 -0
- package/examples/temp-file-cleanup-stop.sh +28 -0
- package/examples/temp-file-cleanup.sh +2 -0
- package/examples/terminal-state-restore.sh +23 -0
- package/examples/test-after-edit.sh +2 -0
- package/examples/test-before-commit.sh +13 -14
- package/examples/test-before-push.sh +2 -0
- package/examples/test-exit-code-verify.sh +2 -0
- package/examples/timeout-guard.sh +2 -0
- package/examples/timezone-guard.sh +2 -0
- package/examples/tmp-output-size-guard.sh +46 -0
- package/examples/todo-check.sh +2 -0
- package/examples/todo-deadline-warn.sh +48 -0
- package/examples/token-budget-per-task.sh +55 -0
- package/examples/token-spike-alert.sh +51 -0
- package/examples/token-usage-tracker.sh +14 -0
- package/examples/turbo-cache-guard.sh +2 -0
- package/examples/uncommitted-changes-stop.sh +2 -0
- package/examples/uncommitted-work-shield.sh +37 -0
- package/examples/usage-warn.sh +2 -0
- package/examples/verify-before-commit.sh +2 -0
- package/examples/virtual-cwd-helper.sh +40 -0
- package/examples/vue-lint-on-edit.sh +2 -0
- package/examples/webfetch-domain-allow.sh +96 -0
- package/examples/worktree-delete-guard.sh +43 -0
- package/examples/worktree-memory-guard.sh +47 -0
- package/examples/worktree-path-validator.sh +42 -0
- package/examples/worktree-project-unify.sh +19 -0
- package/examples/worktree-unmerged-guard.sh +2 -0
- package/examples/write-overwrite-confirm.sh +40 -0
- package/examples/write-secret-guard.sh +2 -0
- package/examples/write-shrink-guard.sh +46 -0
- package/examples/write-test-ratio.sh +2 -0
- package/index.mjs +631 -138
- package/package.json +2 -2
- package/scripts/generate-categories.mjs +206 -0
- package/scripts.json +4 -1
- package/test.sh.new_tests +0 -0
- package/test.sh.patch +0 -0
- package/tests/test-core-file-protect-guard.sh +73 -0
- package/tests/test-deployment-verify-guard.sh +74 -0
- package/tests/test-git-operations-require-approval.sh +65 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# deploy-path-verify-guard.sh — Verify deployment target path before writes
|
|
3
|
+
#
|
|
4
|
+
# Solves: Writing files to wrong filesystem path in Docker setups (#40421).
|
|
5
|
+
# Claude wrote to host /srv/ instead of Docker mount /opt/acestream/public/
|
|
6
|
+
# three times, each time claiming deployment was successful.
|
|
7
|
+
#
|
|
8
|
+
# How it works: Before writing to paths matching CC_DEPLOY_PATHS pattern,
|
|
9
|
+
# verifies the target is actually mounted/accessible. Catches host-vs-container
|
|
10
|
+
# path confusion.
|
|
11
|
+
#
|
|
12
|
+
# CONFIG:
|
|
13
|
+
# CC_DEPLOY_PATHS="/srv:/opt/acestream/public:/var/www"
|
|
14
|
+
# CC_DEPLOY_VERIFY_CMD="docker inspect --format '{{.Mounts}}' mycontainer"
|
|
15
|
+
#
|
|
16
|
+
# TRIGGER: PreToolUse
|
|
17
|
+
# MATCHER: "Bash|Write"
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
23
|
+
|
|
24
|
+
DEPLOY_PATHS="${CC_DEPLOY_PATHS:-/srv:/var/www:/opt}"
|
|
25
|
+
|
|
26
|
+
# For Write tool, check file_path
|
|
27
|
+
if [ "$TOOL" = "Write" ]; then
|
|
28
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
29
|
+
[ -z "$FILE" ] && exit 0
|
|
30
|
+
|
|
31
|
+
IFS=':' read -ra PATHS <<< "$DEPLOY_PATHS"
|
|
32
|
+
for dp in "${PATHS[@]}"; do
|
|
33
|
+
if [[ "$FILE" == "$dp"* ]]; then
|
|
34
|
+
echo "WARNING: Writing to deployment path $dp." >&2
|
|
35
|
+
echo "File: $FILE" >&2
|
|
36
|
+
echo "" >&2
|
|
37
|
+
echo "Verify this is the correct target:" >&2
|
|
38
|
+
echo " - Is this inside a Docker container or on the host?" >&2
|
|
39
|
+
echo " - Run 'docker inspect' to check bind mounts first." >&2
|
|
40
|
+
# Warning only (exit 0), not blocking — change to exit 2 to block
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
done
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# For Bash tool, check commands that write to deploy paths
|
|
47
|
+
if [ "$TOOL" = "Bash" ]; then
|
|
48
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
49
|
+
[ -z "$COMMAND" ] && exit 0
|
|
50
|
+
|
|
51
|
+
IFS=':' read -ra PATHS <<< "$DEPLOY_PATHS"
|
|
52
|
+
for dp in "${PATHS[@]}"; do
|
|
53
|
+
if echo "$COMMAND" | grep -qE "(cp|mv|tee|cat.*>|echo.*>).*${dp}"; then
|
|
54
|
+
echo "WARNING: Bash command targets deployment path $dp." >&2
|
|
55
|
+
echo "Command: $COMMAND" >&2
|
|
56
|
+
echo "Verify the target path is correct (host vs container)." >&2
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
exit 0
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# deployment-verify-guard.sh — Warn if committing without post-deploy verification
|
|
4
|
+
# ================================================================
|
|
5
|
+
# PURPOSE:
|
|
6
|
+
# Claude Code sometimes reports "deployment successful" without
|
|
7
|
+
# actually verifying the deployment works. This hook tracks deploy
|
|
8
|
+
# commands and checks that functional verification was performed
|
|
9
|
+
# before the next git commit.
|
|
10
|
+
#
|
|
11
|
+
# How it works:
|
|
12
|
+
# 1. When a deploy command is detected, logs timestamp to a marker file
|
|
13
|
+
# 2. When verification commands (test, curl, log grep) run, clears the marker
|
|
14
|
+
# 3. When git commit is attempted after a deploy without verification,
|
|
15
|
+
# emits a warning (non-blocking, exit 0)
|
|
16
|
+
#
|
|
17
|
+
# See: https://github.com/anthropics/claude-code/issues/40861
|
|
18
|
+
#
|
|
19
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
20
|
+
#
|
|
21
|
+
# Configuration:
|
|
22
|
+
# CC_DEPLOY_COMMANDS — regex pattern for deploy commands
|
|
23
|
+
# Default: "systemctl restart|docker restart|docker-compose up|deploy|kubectl apply|terraform apply|heroku push"
|
|
24
|
+
#
|
|
25
|
+
# CC_VERIFY_COMMANDS — regex pattern for verification commands
|
|
26
|
+
# Default: "curl|wget|test |pytest|npm test|jest|mocha|rspec|go test|cargo test|make test|grep.*log|tail.*log|journalctl|docker logs|health"
|
|
27
|
+
# ================================================================
|
|
28
|
+
|
|
29
|
+
INPUT=$(cat)
|
|
30
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
31
|
+
|
|
32
|
+
[ -z "$COMMAND" ] && exit 0
|
|
33
|
+
|
|
34
|
+
MARKER="/tmp/cc-deploy-pending-$$"
|
|
35
|
+
|
|
36
|
+
# Configurable deploy command patterns
|
|
37
|
+
DEPLOY_PATTERN="${CC_DEPLOY_COMMANDS:-systemctl\s+restart|docker\s+restart|docker-compose\s+up|docker\s+compose\s+up|\bdeploy\b|kubectl\s+apply|terraform\s+apply|heroku\s+.*push|fly\s+deploy}"
|
|
38
|
+
|
|
39
|
+
# Configurable verify command patterns
|
|
40
|
+
VERIFY_PATTERN="${CC_VERIFY_COMMANDS:-\bcurl\b|\bwget\b|\btest\s|\bpytest\b|npm\s+test|\bjest\b|\bmocha\b|\brspec\b|go\s+test|cargo\s+test|make\s+test|grep.*log|tail.*log|\bjournalctl\b|docker\s+logs|\bhealth}"
|
|
41
|
+
|
|
42
|
+
# Skip echo/printf
|
|
43
|
+
echo "$COMMAND" | grep -qE '^\s*(echo|printf)\s' && exit 0
|
|
44
|
+
|
|
45
|
+
# Check if this is a deploy command
|
|
46
|
+
if echo "$COMMAND" | grep -qiE "$DEPLOY_PATTERN"; then
|
|
47
|
+
date +%s > "$MARKER"
|
|
48
|
+
echo "Deploy detected. Verification will be required before commit." >&2
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Check if this is a verification command — clear the deploy marker
|
|
53
|
+
if echo "$COMMAND" | grep -qiE "$VERIFY_PATTERN"; then
|
|
54
|
+
if [ -f "$MARKER" ]; then
|
|
55
|
+
rm -f "$MARKER"
|
|
56
|
+
fi
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Check if this is a git commit after an unverified deploy
|
|
61
|
+
if echo "$COMMAND" | grep -qE '\bgit\s+commit\b'; then
|
|
62
|
+
if [ -f "$MARKER" ]; then
|
|
63
|
+
DEPLOY_TIME=$(cat "$MARKER" 2>/dev/null || echo "unknown")
|
|
64
|
+
echo "WARNING: Committing after deployment without verification." >&2
|
|
65
|
+
echo "" >&2
|
|
66
|
+
echo "A deploy command was run (at timestamp $DEPLOY_TIME) but no" >&2
|
|
67
|
+
echo "verification command was detected since then." >&2
|
|
68
|
+
echo "" >&2
|
|
69
|
+
echo "Recommended verifications:" >&2
|
|
70
|
+
echo " curl http://localhost:<port>/health" >&2
|
|
71
|
+
echo " npm test / pytest / go test" >&2
|
|
72
|
+
echo " docker logs <container> | tail" >&2
|
|
73
|
+
echo " journalctl -u <service> --since '5 min ago'" >&2
|
|
74
|
+
echo "" >&2
|
|
75
|
+
echo "See: https://github.com/anthropics/claude-code/issues/40861" >&2
|
|
76
|
+
# Non-blocking — just warn
|
|
77
|
+
rm -f "$MARKER"
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
exit 0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dotenv-commit-guard.sh — Prevent committing .env files with secrets
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude adding .env files to git staging and committing them.
|
|
5
|
+
# Even with .gitignore, Claude can `git add -f .env` to force-add.
|
|
6
|
+
#
|
|
7
|
+
# How it works: PreToolUse hook on Bash that detects git add/commit
|
|
8
|
+
# commands including .env files and blocks them.
|
|
9
|
+
#
|
|
10
|
+
# TRIGGER: PreToolUse
|
|
11
|
+
# MATCHER: "Bash"
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
INPUT=$(cat)
|
|
16
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
17
|
+
[ -z "$COMMAND" ] && exit 0
|
|
18
|
+
|
|
19
|
+
# Check for git add with .env files
|
|
20
|
+
# Allow .env.example, .env.sample, .env.template
|
|
21
|
+
if echo "$COMMAND" | grep -qE 'git\s+add\s+.*\.env\.(example|sample|template)'; then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
if echo "$COMMAND" | grep -qE 'git\s+add\s+.*\.env'; then
|
|
25
|
+
echo "BLOCKED: Adding .env file to git staging." >&2
|
|
26
|
+
echo " .env files contain secrets and should not be committed." >&2
|
|
27
|
+
echo " Use .env.example with placeholder values instead." >&2
|
|
28
|
+
exit 2
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Check for git add -A/-f that might include .env
|
|
32
|
+
if echo "$COMMAND" | grep -qE 'git\s+add\s+(-A|--all|-f|--force)\b'; then
|
|
33
|
+
# Check if .env exists in the working directory
|
|
34
|
+
if [ -f ".env" ] || [ -f ".env.local" ] || [ -f ".env.production" ]; then
|
|
35
|
+
# Check if .gitignore excludes it
|
|
36
|
+
if ! git check-ignore -q .env 2>/dev/null; then
|
|
37
|
+
echo "WARNING: 'git add -A' with .env file not in .gitignore." >&2
|
|
38
|
+
echo " Add .env to .gitignore before staging all files." >&2
|
|
39
|
+
# Warning only for git add -A
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# dotenv-example-sync.sh — Warn when .env changes but .env.example doesn't
|
|
4
|
+
# ================================================================
|
|
5
|
+
# PURPOSE:
|
|
6
|
+
# When Claude edits .env (adding/removing variables), .env.example
|
|
7
|
+
# should be updated to match. This hook warns if .env was modified
|
|
8
|
+
# but .env.example still has different keys, preventing deployment
|
|
9
|
+
# failures when team members don't have the new variables.
|
|
10
|
+
#
|
|
11
|
+
# TRIGGER: PostToolUse
|
|
12
|
+
# MATCHER: "Edit|Write"
|
|
13
|
+
#
|
|
14
|
+
# DECISION: Advisory only (exit 0). Warns via stderr.
|
|
15
|
+
# ================================================================
|
|
16
|
+
|
|
17
|
+
INPUT=$(cat)
|
|
18
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
19
|
+
[ -z "$FILE" ] && exit 0
|
|
20
|
+
|
|
21
|
+
# Only trigger when .env is edited (not .env.example itself)
|
|
22
|
+
case "$(basename "$FILE")" in
|
|
23
|
+
.env|.env.local|.env.development|.env.production) ;;
|
|
24
|
+
*) exit 0 ;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
# Find corresponding .env.example
|
|
28
|
+
DIR=$(dirname "$FILE")
|
|
29
|
+
EXAMPLE=""
|
|
30
|
+
for candidate in "$DIR/.env.example" "$DIR/.env.sample" "$DIR/.env.template"; do
|
|
31
|
+
if [ -f "$candidate" ]; then
|
|
32
|
+
EXAMPLE="$candidate"
|
|
33
|
+
break
|
|
34
|
+
fi
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
[ -z "$EXAMPLE" ] && exit 0
|
|
38
|
+
[ ! -f "$FILE" ] && exit 0
|
|
39
|
+
|
|
40
|
+
# Extract variable names (lines with KEY=)
|
|
41
|
+
ENV_KEYS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$FILE" 2>/dev/null | sort -u)
|
|
42
|
+
EXAMPLE_KEYS=$(grep -oE '^[A-Z_][A-Z0-9_]*=' "$EXAMPLE" 2>/dev/null | sort -u)
|
|
43
|
+
|
|
44
|
+
# Find keys in .env but not in .env.example
|
|
45
|
+
MISSING=$(comm -23 <(echo "$ENV_KEYS") <(echo "$EXAMPLE_KEYS"))
|
|
46
|
+
|
|
47
|
+
if [ -n "$MISSING" ]; then
|
|
48
|
+
echo "⚠ .env has variables not in $(basename "$EXAMPLE"):" >&2
|
|
49
|
+
echo "$MISSING" | sed 's/=$//' | while read key; do
|
|
50
|
+
echo " + $key" >&2
|
|
51
|
+
done
|
|
52
|
+
echo " Update $(basename "$EXAMPLE") so teammates have the full variable list." >&2
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# edit-counter-test-gate.sh — Require testing after N consecutive edits
|
|
3
|
+
#
|
|
4
|
+
# Solves: Reactive cycling through fixes without testing (#40401).
|
|
5
|
+
# Opus writing 4 different fix approaches in sequence without
|
|
6
|
+
# verifying any of them actually work.
|
|
7
|
+
#
|
|
8
|
+
# How it works: PostToolUse hook on Edit that counts consecutive edits.
|
|
9
|
+
# After CC_MAX_EDITS_BEFORE_TEST (default 3) edits without a Bash
|
|
10
|
+
# command (assumed test/build), warns the model to test first.
|
|
11
|
+
#
|
|
12
|
+
# TRIGGER: PostToolUse
|
|
13
|
+
# MATCHER: "Edit|Bash"
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
INPUT=$(cat)
|
|
18
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
19
|
+
MAX_EDITS="${CC_MAX_EDITS_BEFORE_TEST:-3}"
|
|
20
|
+
COUNTER_FILE="/tmp/claude-edit-test-gate-${PPID:-0}"
|
|
21
|
+
|
|
22
|
+
case "$TOOL" in
|
|
23
|
+
Edit|Write)
|
|
24
|
+
# Increment edit counter
|
|
25
|
+
COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
|
|
26
|
+
COUNT=$((COUNT + 1))
|
|
27
|
+
echo "$COUNT" > "$COUNTER_FILE"
|
|
28
|
+
|
|
29
|
+
if [ "$COUNT" -ge "$MAX_EDITS" ]; then
|
|
30
|
+
echo "WARNING: $COUNT consecutive edits without testing." >&2
|
|
31
|
+
echo "" >&2
|
|
32
|
+
echo "Run your test/build command before making more changes." >&2
|
|
33
|
+
echo "Untested fixes compound — verify each approach works" >&2
|
|
34
|
+
echo "before trying the next one." >&2
|
|
35
|
+
# Warning only — change to exit 2 to block
|
|
36
|
+
fi
|
|
37
|
+
;;
|
|
38
|
+
Bash)
|
|
39
|
+
# Bash command (likely test/build) — reset counter
|
|
40
|
+
echo "0" > "$COUNTER_FILE"
|
|
41
|
+
;;
|
|
42
|
+
esac
|
|
43
|
+
|
|
44
|
+
exit 0
|
package/examples/edit-guard.sh
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# edit-old-string-validator.sh — Pre-validate Edit tool old_string exists
|
|
3
|
+
#
|
|
4
|
+
# Solves: Parallel Edit tool calls cascade-fail when one Edit's
|
|
5
|
+
# old_string doesn't match the file content (#22264).
|
|
6
|
+
# By catching mismatches before execution, sibling
|
|
7
|
+
# edits in the same batch can proceed normally.
|
|
8
|
+
#
|
|
9
|
+
# How it works: Reads the Edit tool input, checks if old_string
|
|
10
|
+
# exists in the target file. If not found, blocks with exit 2
|
|
11
|
+
# and a descriptive error message.
|
|
12
|
+
#
|
|
13
|
+
# TRIGGER: PreToolUse
|
|
14
|
+
# MATCHER: "Edit"
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
INPUT=$(cat)
|
|
18
|
+
|
|
19
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
20
|
+
OLD_STRING=$(echo "$INPUT" | jq -r '.tool_input.old_string // empty' 2>/dev/null)
|
|
21
|
+
|
|
22
|
+
# Skip if no file or old_string
|
|
23
|
+
[ -z "$FILE" ] && exit 0
|
|
24
|
+
[ -z "$OLD_STRING" ] && exit 0
|
|
25
|
+
|
|
26
|
+
# Skip if file doesn't exist (Edit tool will handle that error)
|
|
27
|
+
[ ! -f "$FILE" ] && exit 0
|
|
28
|
+
|
|
29
|
+
# Check if old_string exists in the file
|
|
30
|
+
if ! grep -qF "$OLD_STRING" "$FILE" 2>/dev/null; then
|
|
31
|
+
echo "BLOCKED: old_string not found in $FILE." >&2
|
|
32
|
+
echo "The file may have been modified by a prior edit in this batch." >&2
|
|
33
|
+
echo "Re-read the file to get the current content before retrying." >&2
|
|
34
|
+
exit 2
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
exit 0
|
package/examples/edit-verify.sh
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# encoding-preserve-guard.sh — Warn when file encoding changes
|
|
4
|
+
# ================================================================
|
|
5
|
+
# PURPOSE:
|
|
6
|
+
# Claude's Write tool always outputs UTF-8. When editing files
|
|
7
|
+
# that use different encodings (UTF-8 BOM, Latin-1, Shift-JIS),
|
|
8
|
+
# the encoding silently changes, potentially corrupting content.
|
|
9
|
+
# Common in legacy codebases, .csv exports, Windows batch files.
|
|
10
|
+
#
|
|
11
|
+
# TRIGGER: PreToolUse
|
|
12
|
+
# MATCHER: "Write|Edit"
|
|
13
|
+
# ================================================================
|
|
14
|
+
|
|
15
|
+
INPUT=$(cat)
|
|
16
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
17
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
18
|
+
|
|
19
|
+
[[ "$TOOL" != "Write" && "$TOOL" != "Edit" ]] && exit 0
|
|
20
|
+
[ -z "$FILE" ] || [ ! -f "$FILE" ] && exit 0
|
|
21
|
+
|
|
22
|
+
# Check for BOM (Byte Order Mark)
|
|
23
|
+
if head -c 3 "$FILE" 2>/dev/null | od -An -tx1 | grep -q "ef bb bf"; then
|
|
24
|
+
echo "WARNING: $FILE has UTF-8 BOM. Write tool may strip the BOM." >&2
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Check for non-UTF-8 encoding using file command
|
|
28
|
+
ENCODING=$(file -bi "$FILE" 2>/dev/null | grep -oP 'charset=\K\S+')
|
|
29
|
+
if [ -n "$ENCODING" ] && [ "$ENCODING" != "utf-8" ] && [ "$ENCODING" != "us-ascii" ]; then
|
|
30
|
+
echo "WARNING: $FILE uses $ENCODING encoding. Write tool outputs UTF-8." >&2
|
|
31
|
+
echo " This may corrupt non-ASCII characters in the file." >&2
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
exit 0
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
# Usage: Add to settings.json as a PostToolUse hook on "Edit|Write"
|
|
9
9
|
#
|
|
10
10
|
# Customize TEST_PATTERN for your project's test file naming convention.
|
|
11
|
+
#
|
|
12
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
11
13
|
|
|
12
14
|
INPUT=$(cat)
|
|
13
15
|
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# env-inline-secret-guard.sh — Block .env values from appearing in commands
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude reading .env and hardcoding secrets into inline scripts (#24185).
|
|
5
|
+
# API keys, database URLs, and tokens get embedded in bash commands,
|
|
6
|
+
# potentially leaking to logs, history, or screen recordings.
|
|
7
|
+
#
|
|
8
|
+
# How it works: PreToolUse hook on Bash that detects common secret patterns
|
|
9
|
+
# (API keys, tokens, connection strings) in command text.
|
|
10
|
+
# If found, blocks with exit 2 and suggests environment variable usage.
|
|
11
|
+
#
|
|
12
|
+
# TRIGGER: PreToolUse
|
|
13
|
+
# MATCHER: "Bash"
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
INPUT=$(cat)
|
|
18
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
19
|
+
[ -z "$COMMAND" ] && exit 0
|
|
20
|
+
|
|
21
|
+
# Detect inline secrets: known API key prefixes (20+ chars)
|
|
22
|
+
# sk- (OpenAI), ghp_/ghu_ (GitHub), AKIA (AWS)
|
|
23
|
+
if echo "$COMMAND" | grep -qE '(sk-[a-zA-Z0-9]{20,}|ghp_[a-zA-Z0-9]{36}|ghu_[a-zA-Z0-9]{36}|AKIA[0-9A-Z]{16}|xoxb-[0-9]+-[0-9]+-[a-zA-Z0-9]+)'; then
|
|
24
|
+
echo "BLOCKED: Possible secret/credential detected in command." >&2
|
|
25
|
+
echo "Use environment variables instead of inline secrets." >&2
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Detect generic long tokens in auth headers or parameters
|
|
30
|
+
if echo "$COMMAND" | grep -qE "(Authorization:|Bearer |token=|api[_-]?key=|secret=|password=)['\"]?[a-zA-Z0-9+/=_-]{32,}"; then
|
|
31
|
+
echo "BLOCKED: Long token/key detected inline in command." >&2
|
|
32
|
+
echo "Use environment variables or a secrets file instead." >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
exit 0
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
2
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$COMMAND" ] && exit 0
|
|
4
6
|
if echo "$COMMAND" | grep -qiE "(NODE_ENV|RAILS_ENV|FLASK_ENV)=production"; then echo "WARNING: Production env detected in command" >&2; fi
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "process\.env\.\w+\s*\|\|" || echo "$CONTENT" | grep -qE "process\.env\.\w+!" && echo "NOTE: Env var without default — add fallback" >&2
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# export-overwrite-guard.sh — Prevent /export from overwriting existing files
|
|
3
|
+
#
|
|
4
|
+
# Solves: /export command overwrites files without warning (#37595).
|
|
5
|
+
# Users lose existing files when Claude exports to the same path.
|
|
6
|
+
#
|
|
7
|
+
# How it works: PreToolUse hook on Write that checks if the target file
|
|
8
|
+
# exists and contains content. If so, warns before allowing overwrite.
|
|
9
|
+
#
|
|
10
|
+
# TRIGGER: PreToolUse
|
|
11
|
+
# MATCHER: "Write"
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
INPUT=$(cat)
|
|
16
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
17
|
+
[ -z "$FILE" ] && exit 0
|
|
18
|
+
|
|
19
|
+
# Check if file exists and has content
|
|
20
|
+
if [ -f "$FILE" ] && [ -s "$FILE" ]; then
|
|
21
|
+
SIZE=$(wc -c < "$FILE" 2>/dev/null || echo 0)
|
|
22
|
+
if [ "$SIZE" -gt 100 ]; then
|
|
23
|
+
echo "WARNING: Overwriting existing file '$FILE' ($SIZE bytes)." >&2
|
|
24
|
+
echo "Consider writing to a different path or backing up first." >&2
|
|
25
|
+
# Don't block — just warn via stderr
|
|
26
|
+
fi
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
exit 0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# file-change-undo-tracker.sh — Track file changes for easy undo
|
|
3
|
+
#
|
|
4
|
+
# Solves: After Claude makes unwanted changes across multiple files,
|
|
5
|
+
# users have no easy way to identify and revert all affected files.
|
|
6
|
+
# git diff works but only for tracked files.
|
|
7
|
+
#
|
|
8
|
+
# How it works: FileChanged hook that logs every file modification
|
|
9
|
+
# with timestamp and change type. Creates a revert script
|
|
10
|
+
# that can undo all changes from the current session.
|
|
11
|
+
#
|
|
12
|
+
# Usage: After session, run: bash /tmp/claude-undo-session.sh
|
|
13
|
+
#
|
|
14
|
+
# TRIGGER: FileChanged
|
|
15
|
+
# MATCHER: ""
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
INPUT=$(cat)
|
|
20
|
+
FILE=$(echo "$INPUT" | jq -r '.file // empty' 2>/dev/null)
|
|
21
|
+
EVENT=$(echo "$INPUT" | jq -r '.event // empty' 2>/dev/null)
|
|
22
|
+
|
|
23
|
+
[ -z "$FILE" ] && exit 0
|
|
24
|
+
|
|
25
|
+
LOG_FILE="/tmp/claude-file-changes-${PPID:-0}.log"
|
|
26
|
+
UNDO_FILE="/tmp/claude-undo-session-${PPID:-0}.sh"
|
|
27
|
+
TIMESTAMP=$(date +"%H:%M:%S")
|
|
28
|
+
|
|
29
|
+
# Log the change
|
|
30
|
+
echo "${TIMESTAMP} ${EVENT:-modified} ${FILE}" >> "$LOG_FILE"
|
|
31
|
+
|
|
32
|
+
# Track for undo (git-tracked files only)
|
|
33
|
+
if git ls-files --error-unmatch "$FILE" &>/dev/null 2>&1; then
|
|
34
|
+
# File is git-tracked — can be reverted with git checkout
|
|
35
|
+
if ! grep -qF "git checkout -- \"$FILE\"" "$UNDO_FILE" 2>/dev/null; then
|
|
36
|
+
echo "git checkout -- \"$FILE\" # ${EVENT:-modified} at ${TIMESTAMP}" >> "$UNDO_FILE"
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Count changes
|
|
41
|
+
COUNT=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0)
|
|
42
|
+
if [ "$((COUNT % 10))" -eq 0 ] && [ "$COUNT" -gt 0 ]; then
|
|
43
|
+
echo "Session file changes: $COUNT files modified. Undo: bash $UNDO_FILE" >&2
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
exit 0
|