cc-safe-setup 1.8.2 → 1.8.3

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/README.md CHANGED
@@ -140,11 +140,13 @@ Need custom hooks beyond the 8 built-in ones? See [`examples/`](examples/) for r
140
140
  - **block-database-wipe.sh** — Block destructive database commands: Laravel `migrate:fresh`, Django `flush`, Rails `db:drop`, raw `DROP DATABASE` ([#37405](https://github.com/anthropics/claude-code/issues/37405) [#37439](https://github.com/anthropics/claude-code/issues/37439))
141
141
  - **auto-approve-python.sh** — Auto-approve pytest, mypy, ruff, black, isort, flake8, pylint commands
142
142
  - **auto-snapshot.sh** — Auto-save file snapshots before edits for rollback protection ([#37386](https://github.com/anthropics/claude-code/issues/37386) [#37457](https://github.com/anthropics/claude-code/issues/37457))
143
+ - **allowlist.sh** — Block everything not explicitly approved — inverse permission model ([#37471](https://github.com/anthropics/claude-code/issues/37471))
144
+ - **protect-dotfiles.sh** — Block modifications to `~/.bashrc`, `~/.aws/`, `~/.ssh/` and chezmoi without diff ([#37478](https://github.com/anthropics/claude-code/issues/37478))
143
145
 
144
146
  ## Learn More
145
147
 
146
148
  - [Official Hooks Reference](https://code.claude.com/docs/en/hooks) — Claude Code hooks documentation
147
- - [Hooks Cookbook](https://github.com/yurukusa/claude-code-hooks/blob/main/COOKBOOK.md) — 12 ready-to-use recipes from real GitHub Issues
149
+ - [Hooks Cookbook](https://github.com/yurukusa/claude-code-hooks/blob/main/COOKBOOK.md) — 13 ready-to-use recipes from real GitHub Issues
148
150
  - [Japanese guide (Qiita)](https://qiita.com/yurukusa/items/a9714b33f5d974e8f1e8) — この記事の日本語解説
149
151
  - [The incident that inspired this tool](https://github.com/anthropics/claude-code/issues/36339) — NTFS junction rm -rf
150
152
 
@@ -0,0 +1,37 @@
1
+ # Example Hooks
2
+
3
+ Custom hooks beyond the 8 built-in ones. Copy any file to `~/.claude/hooks/` and add to `settings.json`.
4
+
5
+ | Hook | Purpose | Related Issue |
6
+ |------|---------|---------------|
7
+ | **allowlist.sh** | Block everything not explicitly approved (inverse model) | [#37471](https://github.com/anthropics/claude-code/issues/37471) |
8
+ | **auto-approve-build.sh** | Auto-approve npm/yarn/cargo/go build, test, lint | |
9
+ | **auto-approve-docker.sh** | Auto-approve docker build, compose, ps, logs | |
10
+ | **auto-approve-git-read.sh** | Auto-approve `git status/log/diff` even with `-C` flags | [#36900](https://github.com/anthropics/claude-code/issues/36900) |
11
+ | **auto-approve-python.sh** | Auto-approve pytest, mypy, ruff, black, isort | |
12
+ | **auto-approve-ssh.sh** | Auto-approve safe SSH commands (uptime, whoami) | |
13
+ | **auto-snapshot.sh** | Save file snapshots before edits (rollback protection) | [#37386](https://github.com/anthropics/claude-code/issues/37386) |
14
+ | **block-database-wipe.sh** | Block destructive DB commands (Laravel, Django, Rails) | [#37405](https://github.com/anthropics/claude-code/issues/37405) |
15
+ | **edit-guard.sh** | Block Edit/Write to protected files | [#37210](https://github.com/anthropics/claude-code/issues/37210) |
16
+ | **enforce-tests.sh** | Warn when source changes without test changes | |
17
+ | **notify-waiting.sh** | Desktop notification when Claude waits for input | |
18
+ | **protect-dotfiles.sh** | Block modifications to ~/.bashrc, ~/.aws/, ~/.ssh/ | [#37478](https://github.com/anthropics/claude-code/issues/37478) |
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ # 1. Copy example to hooks directory
24
+ cp examples/block-database-wipe.sh ~/.claude/hooks/
25
+
26
+ # 2. Make executable
27
+ chmod +x ~/.claude/hooks/block-database-wipe.sh
28
+
29
+ # 3. Add to settings.json
30
+ # See each file's header comment for the JSON configuration
31
+ ```
32
+
33
+ ## List from CLI
34
+
35
+ ```bash
36
+ npx cc-safe-setup --examples
37
+ ```
@@ -0,0 +1,64 @@
1
+ #!/bin/bash
2
+ # allowlist.sh — Only allow explicitly approved commands
3
+ #
4
+ # Inverts the default permission model: everything is blocked
5
+ # unless it matches an approved pattern. This is the opposite
6
+ # of cc-safe-setup's destructive-guard (which blocks specific
7
+ # dangerous commands).
8
+ #
9
+ # Use case: Highly sensitive environments where you want to
10
+ # enumerate exactly what Claude Code can do.
11
+ #
12
+ # Born from GitHub Issue #37471 (Immutable session manifest)
13
+ #
14
+ # Usage: Add to settings.json as a PreToolUse hook
15
+ #
16
+ # {
17
+ # "hooks": {
18
+ # "PreToolUse": [{
19
+ # "matcher": "Bash",
20
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/allowlist.sh" }]
21
+ # }]
22
+ # }
23
+ # }
24
+
25
+ INPUT=$(cat)
26
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
27
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
28
+
29
+ # Only gate Bash commands
30
+ [[ "$TOOL" != "Bash" ]] && exit 0
31
+ [[ -z "$COMMAND" ]] && exit 0
32
+
33
+ # ========================================
34
+ # ALLOWLIST — add your approved patterns
35
+ # ========================================
36
+ ALLOWED=(
37
+ # Git (read-only + commit, but not push/reset/clean)
38
+ "^\s*git (add|commit|diff|log|status|branch|show|stash|rev-parse|tag)"
39
+ # Package managers (install + read-only)
40
+ "^\s*npm (test|run|install|ci|ls|outdated)"
41
+ "^\s*pip (install|list|show|freeze)"
42
+ # Build/test/lint
43
+ "^\s*pytest"
44
+ "^\s*python3? -m (pytest|py_compile|unittest)"
45
+ "^\s*node --check"
46
+ "^\s*(ruff|black|isort|flake8|pylint|mypy|eslint|prettier)"
47
+ # Safe read-only commands
48
+ "^\s*(cat|head|tail|wc|sort|grep|find|ls|pwd|echo|date|which|whoami)"
49
+ "^\s*(curl -s|wget -q)"
50
+ # Directory navigation
51
+ "^\s*(cd|mkdir|touch)"
52
+ )
53
+
54
+ for pattern in "${ALLOWED[@]}"; do
55
+ if echo "$COMMAND" | grep -qE "$pattern"; then
56
+ exit 0 # Approved
57
+ fi
58
+ done
59
+
60
+ # Not in allowlist — block
61
+ echo "BLOCKED: Command not in allowlist" >&2
62
+ echo "Command: $COMMAND" >&2
63
+ echo "To approve, add a pattern to ~/.claude/hooks/allowlist.sh" >&2
64
+ exit 2
@@ -0,0 +1,81 @@
1
+ #!/bin/bash
2
+ # protect-dotfiles.sh — Block destructive operations on home directory config files
3
+ #
4
+ # Solves: Claude Code overwriting .bashrc, deleting .aws/, running
5
+ # chezmoi/stow without diffing first (#37478, #33391)
6
+ #
7
+ # Covers: Edit/Write to dotfiles, Bash commands that modify them
8
+ #
9
+ # Usage: Add to settings.json as a PreToolUse hook
10
+ #
11
+ # {
12
+ # "hooks": {
13
+ # "PreToolUse": [{
14
+ # "matcher": "",
15
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/protect-dotfiles.sh" }]
16
+ # }]
17
+ # }
18
+ # }
19
+
20
+ INPUT=$(cat)
21
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
22
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
23
+ CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
24
+
25
+ # === Check 1: Edit/Write to dotfiles ===
26
+ if [[ "$TOOL" == "Edit" || "$TOOL" == "Write" ]]; then
27
+ HOME_DIR=$(eval echo "~")
28
+ PROTECTED_DOTFILES=(
29
+ ".bashrc" ".bash_profile" ".bash_logout"
30
+ ".zshrc" ".zprofile" ".zshenv"
31
+ ".profile" ".login"
32
+ ".gitconfig" ".gitignore_global"
33
+ ".ssh/config" ".ssh/authorized_keys"
34
+ ".aws/config" ".aws/credentials"
35
+ ".npmrc" ".yarnrc"
36
+ ".env" ".env.local" ".env.production"
37
+ )
38
+ for dotfile in "${PROTECTED_DOTFILES[@]}"; do
39
+ if [[ "$FILE" == "${HOME_DIR}/${dotfile}" ]]; then
40
+ echo "BLOCKED: Cannot modify ~/${dotfile}" >&2
41
+ echo "This is a critical config file. Edit it manually." >&2
42
+ exit 2
43
+ fi
44
+ done
45
+ # Block writing to any ~/.ssh/ or ~/.aws/ files
46
+ if [[ "$FILE" == "${HOME_DIR}/.ssh/"* || "$FILE" == "${HOME_DIR}/.aws/"* ]]; then
47
+ echo "BLOCKED: Cannot modify files in ${FILE%/*}/" >&2
48
+ exit 2
49
+ fi
50
+ fi
51
+
52
+ # === Check 2: Bash commands that modify dotfiles ===
53
+ if [[ "$TOOL" == "Bash" && -n "$CMD" ]]; then
54
+ # Skip echo/printf (string output, not actual modification)
55
+ if echo "$CMD" | grep -qE '^\s*(echo|printf|cat\s*<<)'; then
56
+ exit 0
57
+ fi
58
+
59
+ # Block chezmoi/stow apply without --dry-run
60
+ if echo "$CMD" | grep -qE '(chezmoi\s+(init|apply|update)|stow\s)' && \
61
+ ! echo "$CMD" | grep -qE '(--dry-run|--diff|-n\b|diff)'; then
62
+ echo "BLOCKED: Run 'chezmoi diff' or '--dry-run' first" >&2
63
+ echo "Command: $CMD" >&2
64
+ exit 2
65
+ fi
66
+
67
+ # Block rm on dotfile directories
68
+ if echo "$CMD" | grep -qE 'rm\s.*\.(ssh|aws|gnupg|config|local)'; then
69
+ echo "BLOCKED: Cannot delete dotfile directory" >&2
70
+ exit 2
71
+ fi
72
+
73
+ # Block cp/mv overwriting dotfiles without backup
74
+ if echo "$CMD" | grep -qE '(cp|mv)\s.*\.(bashrc|zshrc|profile|gitconfig)' && \
75
+ ! echo "$CMD" | grep -qE '(--backup|-b)'; then
76
+ echo "BLOCKED: Use --backup flag when overwriting dotfiles" >&2
77
+ exit 2
78
+ fi
79
+ fi
80
+
81
+ exit 0
package/index.mjs CHANGED
@@ -263,6 +263,8 @@ function examples() {
263
263
  'notify-waiting.sh': 'Desktop notification when Claude waits for input',
264
264
  'auto-approve-python.sh': 'Auto-approve pytest, mypy, ruff, black, isort commands',
265
265
  'auto-snapshot.sh': 'Auto-save file snapshots before edits (rollback protection)',
266
+ 'allowlist.sh': 'Block everything not in allowlist (inverse permission model)',
267
+ 'protect-dotfiles.sh': 'Block modifications to ~/.bashrc, ~/.aws/, ~/.ssh/',
266
268
  };
267
269
 
268
270
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "description": "One command to make Claude Code safe for autonomous operation. 8 hooks: destructive blocker, branch guard, force-push protection, secret leak prevention, syntax checks, and more.",
5
5
  "main": "index.mjs",
6
6
  "bin": {