cc-safe-setup 1.7.2 → 1.8.0

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
@@ -136,11 +136,12 @@ Need custom hooks beyond the 8 built-in ones? See [`examples/`](examples/) for r
136
136
  - **edit-guard.sh** — Block Edit/Write to protected files (defense-in-depth for [#37210](https://github.com/anthropics/claude-code/issues/37210))
137
137
  - **auto-approve-build.sh** — Auto-approve npm/yarn/cargo/go/python build, test, and lint commands
138
138
  - **auto-approve-docker.sh** — Auto-approve docker build, compose, ps, logs, and other safe commands
139
+ - **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))
139
140
 
140
141
  ## Learn More
141
142
 
142
143
  - [Official Hooks Reference](https://code.claude.com/docs/en/hooks) — Claude Code hooks documentation
143
- - [Hooks Cookbook](https://github.com/yurukusa/claude-code-hooks/blob/main/COOKBOOK.md) — 10 ready-to-use recipes from real GitHub Issues
144
+ - [Hooks Cookbook](https://github.com/yurukusa/claude-code-hooks/blob/main/COOKBOOK.md) — 11 ready-to-use recipes from real GitHub Issues
144
145
  - [Japanese guide (Qiita)](https://qiita.com/yurukusa/items/a9714b33f5d974e8f1e8) — この記事の日本語解説
145
146
  - [The incident that inspired this tool](https://github.com/anthropics/claude-code/issues/36339) — NTFS junction rm -rf
146
147
 
@@ -0,0 +1,70 @@
1
+ #!/bin/bash
2
+ # block-database-wipe.sh — Block destructive database commands
3
+ #
4
+ # Prevents accidental database destruction from commands like:
5
+ # - Laravel: migrate:fresh, migrate:reset, db:wipe
6
+ # - Django: flush, sqlflush
7
+ # - Rails: db:drop, db:reset
8
+ # - Raw SQL: DROP DATABASE, TRUNCATE
9
+ # - PostgreSQL: dropdb
10
+ #
11
+ # Born from GitHub Issue #37405 (SQLite database wiped)
12
+ # and #37439 (Laravel migrate:fresh on production DB)
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/block-database-wipe.sh" }]
21
+ # }]
22
+ # }
23
+ # }
24
+
25
+ INPUT=$(cat)
26
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
27
+
28
+ [[ -z "$COMMAND" ]] && exit 0
29
+
30
+ # Laravel destructive commands
31
+ if echo "$COMMAND" | grep -qiE 'artisan\s+(migrate:fresh|migrate:reset|db:wipe|db:seed\s+--force)'; then
32
+ echo "BLOCKED: Destructive Laravel database command" >&2
33
+ echo "Command: $COMMAND" >&2
34
+ exit 2
35
+ fi
36
+
37
+ # Laravel --env flag without corresponding .env file
38
+ if echo "$COMMAND" | grep -qE 'artisan.*--env='; then
39
+ ENV_NAME=$(echo "$COMMAND" | grep -oP '(?<=--env=)\w+')
40
+ if [ -n "$ENV_NAME" ] && [ ! -f ".env.$ENV_NAME" ]; then
41
+ echo "BLOCKED: .env.$ENV_NAME does not exist. Command would fall back to .env (possibly production)" >&2
42
+ exit 2
43
+ fi
44
+ fi
45
+
46
+ # Django destructive commands
47
+ if echo "$COMMAND" | grep -qiE 'manage\.py\s+(flush|sqlflush)'; then
48
+ echo "BLOCKED: Destructive Django database command" >&2
49
+ exit 2
50
+ fi
51
+
52
+ # Rails destructive commands
53
+ if echo "$COMMAND" | grep -qiE 'rake\s+db:(drop|reset)|rails\s+db:(drop|reset)'; then
54
+ echo "BLOCKED: Destructive Rails database command" >&2
55
+ exit 2
56
+ fi
57
+
58
+ # Raw SQL destructive commands
59
+ if echo "$COMMAND" | grep -qiE 'DROP\s+(DATABASE|TABLE|SCHEMA)|TRUNCATE\s+TABLE|DELETE\s+FROM\s+\w+\s*;?\s*$'; then
60
+ echo "BLOCKED: Destructive SQL command" >&2
61
+ exit 2
62
+ fi
63
+
64
+ # PostgreSQL CLI
65
+ if echo "$COMMAND" | grep -qE '^\s*dropdb\s'; then
66
+ echo "BLOCKED: dropdb command" >&2
67
+ exit 2
68
+ fi
69
+
70
+ exit 0
package/index.mjs CHANGED
@@ -65,6 +65,7 @@ const HOOKS = {
65
65
  const HELP = process.argv.includes('--help') || process.argv.includes('-h');
66
66
  const STATUS = process.argv.includes('--status') || process.argv.includes('-s');
67
67
  const VERIFY = process.argv.includes('--verify') || process.argv.includes('-v');
68
+ const EXAMPLES = process.argv.includes('--examples') || process.argv.includes('-e');
68
69
 
69
70
  if (HELP) {
70
71
  console.log(`
@@ -76,6 +77,7 @@ if (HELP) {
76
77
  npx cc-safe-setup --verify Test each hook with sample inputs
77
78
  npx cc-safe-setup --dry-run Preview without installing
78
79
  npx cc-safe-setup --uninstall Remove all installed hooks
80
+ npx cc-safe-setup --examples List available example hooks
79
81
  npx cc-safe-setup --help Show this help
80
82
 
81
83
  Hooks installed:
@@ -248,10 +250,42 @@ async function verify() {
248
250
  console.log();
249
251
  }
250
252
 
253
+ function examples() {
254
+ const examplesDir = join(__dirname, 'examples');
255
+ const EXAMPLE_DESCRIPTIONS = {
256
+ 'auto-approve-build.sh': 'Auto-approve npm/yarn/cargo/go build, test, lint commands',
257
+ 'auto-approve-docker.sh': 'Auto-approve docker build, compose, ps, logs commands',
258
+ 'auto-approve-git-read.sh': 'Auto-approve git status/log/diff even with -C flags',
259
+ 'auto-approve-ssh.sh': 'Auto-approve safe SSH commands (uptime, whoami, etc.)',
260
+ 'block-database-wipe.sh': 'Block destructive DB commands (migrate:fresh, DROP DATABASE)',
261
+ 'edit-guard.sh': 'Block Edit/Write to protected files (.env, credentials)',
262
+ 'enforce-tests.sh': 'Warn when source files change without test files',
263
+ 'notify-waiting.sh': 'Desktop notification when Claude waits for input',
264
+ };
265
+
266
+ console.log();
267
+ console.log(c.bold + ' cc-safe-setup --examples' + c.reset);
268
+ console.log(c.dim + ' Custom hooks beyond the 8 built-in ones' + c.reset);
269
+ console.log();
270
+
271
+ for (const [file, desc] of Object.entries(EXAMPLE_DESCRIPTIONS)) {
272
+ const fullPath = join(examplesDir, file);
273
+ const exists = existsSync(fullPath);
274
+ console.log(' ' + c.green + '*' + c.reset + ' ' + c.bold + file + c.reset);
275
+ console.log(' ' + c.dim + desc + c.reset);
276
+ }
277
+
278
+ console.log();
279
+ console.log(c.dim + ' Copy any example to ~/.claude/hooks/ and add to settings.json.' + c.reset);
280
+ console.log(c.dim + ' Source: ' + c.blue + 'https://github.com/yurukusa/cc-safe-setup/tree/main/examples' + c.reset);
281
+ console.log();
282
+ }
283
+
251
284
  async function main() {
252
285
  if (UNINSTALL) return uninstall();
253
286
  if (VERIFY) return verify();
254
287
  if (STATUS) return status();
288
+ if (EXAMPLES) return examples();
255
289
 
256
290
  console.log();
257
291
  console.log(c.bold + ' cc-safe-setup' + c.reset);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
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": {