cc-safe-setup 2.0.8 → 2.1.1

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.
Files changed (3) hide show
  1. package/README.md +12 -0
  2. package/index.mjs +174 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -128,6 +128,18 @@ Or start with the free hooks: [claude-code-hooks](https://github.com/yurukusa/cl
128
128
 
129
129
  ## Examples
130
130
 
131
+ ## Safety Audit
132
+
133
+ Check what's missing in your setup:
134
+
135
+ ```bash
136
+ npx cc-safe-setup --audit
137
+ ```
138
+
139
+ Analyzes 9 safety dimensions and gives you a score (0-100) with one-command fixes for each risk.
140
+
141
+ ## Examples
142
+
131
143
  Need custom hooks beyond the 8 built-in ones? Install any example with one command:
132
144
 
133
145
  ```bash
package/index.mjs CHANGED
@@ -68,6 +68,7 @@ const VERIFY = process.argv.includes('--verify') || process.argv.includes('-v');
68
68
  const EXAMPLES = process.argv.includes('--examples') || process.argv.includes('-e');
69
69
  const INSTALL_EXAMPLE_IDX = process.argv.findIndex(a => a === '--install-example');
70
70
  const INSTALL_EXAMPLE = INSTALL_EXAMPLE_IDX !== -1 ? process.argv[INSTALL_EXAMPLE_IDX + 1] : null;
71
+ const AUDIT = process.argv.includes('--audit');
71
72
 
72
73
  if (HELP) {
73
74
  console.log(`
@@ -81,6 +82,7 @@ if (HELP) {
81
82
  npx cc-safe-setup --uninstall Remove all installed hooks
82
83
  npx cc-safe-setup --examples List 25 example hooks (5 categories)
83
84
  npx cc-safe-setup --install-example <name> Install a specific example
85
+ npx cc-safe-setup --audit Analyze your setup and recommend missing protections
84
86
  npx cc-safe-setup --help Show this help
85
87
 
86
88
  Hooks installed:
@@ -396,12 +398,184 @@ async function installExample(name) {
396
398
  console.log();
397
399
  }
398
400
 
401
+ async function audit() {
402
+ console.log();
403
+ console.log(c.bold + ' cc-safe-setup --audit' + c.reset);
404
+ console.log(c.dim + ' Analyzing your Claude Code safety setup...' + c.reset);
405
+ console.log();
406
+
407
+ const risks = [];
408
+ const good = [];
409
+
410
+ // 1. Check if any PreToolUse hooks exist
411
+ let settings = {};
412
+ if (existsSync(SETTINGS_PATH)) {
413
+ try { settings = JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8')); } catch(e) {}
414
+ }
415
+ const preHooks = (settings.hooks?.PreToolUse || []);
416
+ const postHooks = (settings.hooks?.PostToolUse || []);
417
+ const stopHooks = (settings.hooks?.Stop || []);
418
+
419
+ if (preHooks.length === 0) {
420
+ risks.push({
421
+ severity: 'CRITICAL',
422
+ issue: 'No PreToolUse hooks — destructive commands (rm -rf, git reset --hard) can run unchecked',
423
+ fix: 'npx cc-safe-setup'
424
+ });
425
+ } else {
426
+ good.push('PreToolUse hooks installed (' + preHooks.length + ')');
427
+ }
428
+
429
+ // 2. Check for destructive command protection
430
+ const allHookCommands = preHooks.map(h => h.hooks?.map(hh => hh.command || '').join(' ') || '').join(' ');
431
+ if (!allHookCommands.match(/destructive|guard|block|rm|reset/i)) {
432
+ risks.push({
433
+ severity: 'HIGH',
434
+ issue: 'No destructive command blocker detected — rm -rf /, git reset --hard could execute',
435
+ fix: 'npx cc-safe-setup (installs destructive-guard)'
436
+ });
437
+ } else {
438
+ good.push('Destructive command protection detected');
439
+ }
440
+
441
+ // 3. Check for branch protection
442
+ if (!allHookCommands.match(/branch|push|main|master/i)) {
443
+ risks.push({
444
+ severity: 'HIGH',
445
+ issue: 'No branch push protection — code could be pushed directly to main/master',
446
+ fix: 'npx cc-safe-setup (installs branch-guard)'
447
+ });
448
+ } else {
449
+ good.push('Branch push protection detected');
450
+ }
451
+
452
+ // 4. Check for secret leak protection
453
+ if (!allHookCommands.match(/secret|env|credential/i)) {
454
+ risks.push({
455
+ severity: 'HIGH',
456
+ issue: 'No secret leak protection — .env files could be committed via git add .',
457
+ fix: 'npx cc-safe-setup (installs secret-guard)'
458
+ });
459
+ } else {
460
+ good.push('Secret leak protection detected');
461
+ }
462
+
463
+ // 5. Check for database wipe protection
464
+ if (!allHookCommands.match(/database|wipe|migrate|prisma/i)) {
465
+ risks.push({
466
+ severity: 'MEDIUM',
467
+ issue: 'No database wipe protection — migrate:fresh, prisma migrate reset could wipe data',
468
+ fix: 'npx cc-safe-setup --install-example block-database-wipe'
469
+ });
470
+ } else {
471
+ good.push('Database wipe protection detected');
472
+ }
473
+
474
+ // 6. Check for syntax checking
475
+ if (postHooks.length === 0) {
476
+ risks.push({
477
+ severity: 'MEDIUM',
478
+ issue: 'No PostToolUse hooks — no automatic syntax checking after edits',
479
+ fix: 'npx cc-safe-setup (installs syntax-check)'
480
+ });
481
+ } else {
482
+ good.push('PostToolUse hooks installed (' + postHooks.length + ')');
483
+ }
484
+
485
+ // 7. Check for CLAUDE.md
486
+ const CC_DIR = join(HOME, '.claude');
487
+ const claudeMdPaths = ['CLAUDE.md', '.claude/CLAUDE.md', join(CC_DIR, 'CLAUDE.md')];
488
+ const hasClaudeMd = claudeMdPaths.some(p => existsSync(p));
489
+ if (!hasClaudeMd) {
490
+ risks.push({
491
+ severity: 'MEDIUM',
492
+ issue: 'No CLAUDE.md found — Claude has no project-specific instructions',
493
+ fix: 'Create CLAUDE.md with project rules and conventions'
494
+ });
495
+ } else {
496
+ good.push('CLAUDE.md found');
497
+ }
498
+
499
+ // 8. Check for dotfile protection
500
+ if (!allHookCommands.match(/dotfile|bashrc|protect/i)) {
501
+ risks.push({
502
+ severity: 'LOW',
503
+ issue: 'No dotfile protection — ~/.bashrc, ~/.aws/ could be modified',
504
+ fix: 'npx cc-safe-setup --install-example protect-dotfiles'
505
+ });
506
+ }
507
+
508
+ // 9. Check for scope guard
509
+ if (!allHookCommands.match(/scope|traversal|outside/i)) {
510
+ risks.push({
511
+ severity: 'LOW',
512
+ issue: 'No scope guard — files outside project directory could be modified',
513
+ fix: 'npx cc-safe-setup --install-example scope-guard'
514
+ });
515
+ }
516
+
517
+ // Display results
518
+ if (good.length > 0) {
519
+ console.log(c.bold + ' ✓ What\'s working:' + c.reset);
520
+ for (const g of good) {
521
+ console.log(' ' + c.green + '✓' + c.reset + ' ' + g);
522
+ }
523
+ console.log();
524
+ }
525
+
526
+ if (risks.length === 0) {
527
+ console.log(c.green + c.bold + ' No risks detected. Your setup looks solid.' + c.reset);
528
+ } else {
529
+ console.log(c.bold + ' ⚠ Risks found (' + risks.length + '):' + c.reset);
530
+ console.log();
531
+ for (const r of risks) {
532
+ const severityColor = r.severity === 'CRITICAL' ? c.red : r.severity === 'HIGH' ? c.red : c.yellow;
533
+ console.log(' ' + severityColor + '[' + r.severity + ']' + c.reset + ' ' + r.issue);
534
+ console.log(' ' + c.dim + ' Fix: ' + r.fix + c.reset);
535
+ }
536
+ }
537
+
538
+ console.log();
539
+ const score = Math.max(0, 100 - risks.reduce((sum, r) => {
540
+ if (r.severity === 'CRITICAL') return sum + 30;
541
+ if (r.severity === 'HIGH') return sum + 20;
542
+ if (r.severity === 'MEDIUM') return sum + 10;
543
+ return sum + 5;
544
+ }, 0));
545
+ console.log(c.bold + ' Safety Score: ' + (score >= 80 ? c.green : score >= 50 ? c.yellow : c.red) + score + '/100' + c.reset);
546
+
547
+ // --audit --fix: auto-fix what we can
548
+ if (process.argv.includes('--fix') && risks.length > 0) {
549
+ console.log();
550
+ console.log(c.bold + ' Applying fixes...' + c.reset);
551
+ const { execSync } = await import('child_process');
552
+ for (const r of risks) {
553
+ if (r.fix.startsWith('npx cc-safe-setup')) {
554
+ try {
555
+ const cmd = r.fix.replace('npx cc-safe-setup', 'node ' + process.argv[1]);
556
+ console.log(' ' + c.dim + '→ ' + r.fix + c.reset);
557
+ execSync(cmd, { stdio: 'inherit' });
558
+ } catch(e) {
559
+ console.log(' ' + c.red + ' Failed: ' + e.message + c.reset);
560
+ }
561
+ }
562
+ }
563
+ console.log();
564
+ console.log(c.green + ' Re-run --audit to verify fixes.' + c.reset);
565
+ } else if (risks.length > 0) {
566
+ console.log();
567
+ console.log(c.dim + ' Run with --fix to auto-apply: npx cc-safe-setup --audit --fix' + c.reset);
568
+ }
569
+ console.log();
570
+ }
571
+
399
572
  async function main() {
400
573
  if (UNINSTALL) return uninstall();
401
574
  if (VERIFY) return verify();
402
575
  if (STATUS) return status();
403
576
  if (EXAMPLES) return examples();
404
577
  if (INSTALL_EXAMPLE) return installExample(INSTALL_EXAMPLE);
578
+ if (AUDIT) return audit();
405
579
 
406
580
  console.log();
407
581
  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": "2.0.8",
3
+ "version": "2.1.1",
4
4
  "description": "One command to make Claude Code safe for autonomous operation. 8 built-in hooks + 25 installable examples. Destructive blocker, branch guard, database wipe protection, dotfile guard, and more.",
5
5
  "main": "index.mjs",
6
6
  "bin": {