ship-safe 3.0.0 → 3.2.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.
@@ -1,139 +1,200 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Ship Safe CLI
5
- * =============
6
- *
7
- * Security toolkit for vibe coders and indie hackers.
8
- *
9
- * USAGE:
10
- * npx ship-safe scan [path] Scan for secrets in your codebase
11
- * npx ship-safe checklist Run the launch-day security checklist
12
- * npx ship-safe init Initialize security configs in your project
13
- * npx ship-safe fix Generate .env.example from found secrets
14
- * npx ship-safe guard Install pre-push git hook
15
- * npx ship-safe --help Show all commands
16
- */
17
-
18
- import { program } from 'commander';
19
- import chalk from 'chalk';
20
- import { readFileSync } from 'fs';
21
- import { fileURLToPath } from 'url';
22
- import { dirname, join } from 'path';
23
- import { scanCommand } from '../commands/scan.js';
24
- import { checklistCommand } from '../commands/checklist.js';
25
- import { initCommand } from '../commands/init.js';
26
- import { fixCommand } from '../commands/fix.js';
27
- import { guardCommand } from '../commands/guard.js';
28
- import { mcpCommand } from '../commands/mcp.js';
29
-
30
- // =============================================================================
31
- // CLI CONFIGURATION
32
- // =============================================================================
33
-
34
- // Read version from package.json
35
- const __filename = fileURLToPath(import.meta.url);
36
- const __dirname = dirname(__filename);
37
- const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
38
- const VERSION = packageJson.version;
39
-
40
- // Banner shown on help
41
- const banner = `
42
- ${chalk.cyan('███████╗██╗ ██╗██╗██████╗ ███████╗ █████╗ ███████╗███████╗')}
43
- ${chalk.cyan('██╔════╝██║ ██║██║██╔══██╗ ██╔════╝██╔══██╗██╔════╝██╔════╝')}
44
- ${chalk.cyan('███████╗███████║██║██████╔╝ ███████╗███████║█████╗ █████╗ ')}
45
- ${chalk.cyan('╚════██║██╔══██║██║██╔═══╝ ╚════██║██╔══██║██╔══╝ ██╔══╝ ')}
46
- ${chalk.cyan('███████║██║ ██║██║██║ ███████║██║ ██║██║ ███████╗')}
47
- ${chalk.cyan('╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝')}
48
-
49
- ${chalk.gray('Security toolkit for vibe coders. Secure your MVP in 5 minutes.')}
50
- `;
51
-
52
- // =============================================================================
53
- // PROGRAM SETUP
54
- // =============================================================================
55
-
56
- program
57
- .name('ship-safe')
58
- .description('Security toolkit for vibe coders and indie hackers')
59
- .version(VERSION)
60
- .addHelpText('before', banner);
61
-
62
- // -----------------------------------------------------------------------------
63
- // SCAN COMMAND
64
- // -----------------------------------------------------------------------------
65
- program
66
- .command('scan [path]')
67
- .description('Scan your codebase for leaked secrets (API keys, passwords, etc.)')
68
- .option('-v, --verbose', 'Show all files being scanned')
69
- .option('--no-color', 'Disable colored output')
70
- .option('--json', 'Output results as JSON (useful for CI)')
71
- .option('--sarif', 'Output results in SARIF format (for GitHub Code Scanning)')
72
- .option('--include-tests', 'Also scan test files (excluded by default to reduce false positives)')
73
- .action(scanCommand);
74
-
75
- // -----------------------------------------------------------------------------
76
- // CHECKLIST COMMAND
77
- // -----------------------------------------------------------------------------
78
- program
79
- .command('checklist')
80
- .description('Run through the launch-day security checklist interactively')
81
- .option('--no-interactive', 'Print checklist without prompts')
82
- .action(checklistCommand);
83
-
84
- // -----------------------------------------------------------------------------
85
- // INIT COMMAND
86
- // -----------------------------------------------------------------------------
87
- program
88
- .command('init')
89
- .description('Initialize security configs in your project')
90
- .option('-f, --force', 'Overwrite existing files')
91
- .option('--gitignore', 'Only copy .gitignore')
92
- .option('--headers', 'Only copy security headers config')
93
- .action(initCommand);
94
-
95
- // -----------------------------------------------------------------------------
96
- // FIX COMMAND
97
- // -----------------------------------------------------------------------------
98
- program
99
- .command('fix')
100
- .description('Scan for secrets and generate a .env.example with placeholder values')
101
- .option('--dry-run', 'Preview generated .env.example without writing it')
102
- .action(fixCommand);
103
-
104
- // -----------------------------------------------------------------------------
105
- // GUARD COMMAND
106
- // -----------------------------------------------------------------------------
107
- program
108
- .command('guard [action]')
109
- .description('Install a git hook to block pushes if secrets are found')
110
- .option('--pre-commit', 'Install as pre-commit hook instead of pre-push')
111
- .action(guardCommand);
112
-
113
- // -----------------------------------------------------------------------------
114
- // MCP SERVER COMMAND
115
- // -----------------------------------------------------------------------------
116
- program
117
- .command('mcp')
118
- .description('Start ship-safe as an MCP server (for Claude Desktop, Cursor, Windsurf, etc.)')
119
- .action(mcpCommand);
120
-
121
- // -----------------------------------------------------------------------------
122
- // PARSE AND RUN
123
- // -----------------------------------------------------------------------------
124
-
125
- // Show help if no command provided
126
- if (process.argv.length === 2) {
127
- console.log(banner);
128
- console.log(chalk.yellow('\nQuick start:\n'));
129
- console.log(chalk.white(' npx ship-safe scan . ') + chalk.gray('# Scan for secrets'));
130
- console.log(chalk.white(' npx ship-safe fix ') + chalk.gray('# Generate .env.example from secrets'));
131
- console.log(chalk.white(' npx ship-safe guard ') + chalk.gray('# Block git push if secrets found'));
132
- console.log(chalk.white(' npx ship-safe checklist ') + chalk.gray('# Run security checklist'));
133
- console.log(chalk.white(' npx ship-safe init ') + chalk.gray('# Add security configs to your project'));
134
- console.log(chalk.white('\n npx ship-safe --help ') + chalk.gray('# Show all options'));
135
- console.log();
136
- process.exit(0);
137
- }
138
-
139
- program.parse();
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Ship Safe CLI
5
+ * =============
6
+ *
7
+ * Security toolkit for vibe coders and indie hackers.
8
+ *
9
+ * USAGE:
10
+ * npx ship-safe scan [path] Scan for secrets in your codebase
11
+ * npx ship-safe checklist Run the launch-day security checklist
12
+ * npx ship-safe init Initialize security configs in your project
13
+ * npx ship-safe fix Generate .env.example from found secrets
14
+ * npx ship-safe guard Install pre-push git hook
15
+ * npx ship-safe --help Show all commands
16
+ */
17
+
18
+ import { program } from 'commander';
19
+ import chalk from 'chalk';
20
+ import { readFileSync } from 'fs';
21
+ import { fileURLToPath } from 'url';
22
+ import { dirname, join } from 'path';
23
+ import { scanCommand } from '../commands/scan.js';
24
+ import { checklistCommand } from '../commands/checklist.js';
25
+ import { initCommand } from '../commands/init.js';
26
+ import { fixCommand } from '../commands/fix.js';
27
+ import { guardCommand } from '../commands/guard.js';
28
+ import { mcpCommand } from '../commands/mcp.js';
29
+ import { remediateCommand } from '../commands/remediate.js';
30
+ import { rotateCommand } from '../commands/rotate.js';
31
+ import { agentCommand } from '../commands/agent.js';
32
+ import { depsCommand } from '../commands/deps.js';
33
+ import { scoreCommand } from '../commands/score.js';
34
+
35
+ // =============================================================================
36
+ // CLI CONFIGURATION
37
+ // =============================================================================
38
+
39
+ const DEFAULT_MODEL = 'claude-haiku-4-5-20251001';
40
+
41
+ // Read version from package.json
42
+ const __filename = fileURLToPath(import.meta.url);
43
+ const __dirname = dirname(__filename);
44
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
45
+ const VERSION = packageJson.version;
46
+
47
+ // Banner shown on help
48
+ const banner = `
49
+ ${chalk.cyan('███████╗██╗ ██╗██╗██████╗ ███████╗ █████╗ ███████╗███████╗')}
50
+ ${chalk.cyan('██╔════╝██║ ██║██║██╔══██╗ ██╔════╝██╔══██╗██╔════╝██╔════╝')}
51
+ ${chalk.cyan('███████╗███████║██║██████╔╝ ███████╗███████║█████╗ █████╗ ')}
52
+ ${chalk.cyan('╚════██║██╔══██║██║██╔═══╝ ╚════██║██╔══██║██╔══╝ ██╔══╝ ')}
53
+ ${chalk.cyan('███████║██║ ██║██║██║ ███████║██║ ██║██║ ███████╗')}
54
+ ${chalk.cyan('╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝')}
55
+
56
+ ${chalk.gray('Security toolkit for vibe coders. Secure your MVP in 5 minutes.')}
57
+ `;
58
+
59
+ // =============================================================================
60
+ // PROGRAM SETUP
61
+ // =============================================================================
62
+
63
+ program
64
+ .name('ship-safe')
65
+ .description('Security toolkit for vibe coders and indie hackers')
66
+ .version(VERSION)
67
+ .addHelpText('before', banner);
68
+
69
+ // -----------------------------------------------------------------------------
70
+ // SCAN COMMAND
71
+ // -----------------------------------------------------------------------------
72
+ program
73
+ .command('scan [path]')
74
+ .description('Scan your codebase for leaked secrets (API keys, passwords, etc.)')
75
+ .option('-v, --verbose', 'Show all files being scanned')
76
+ .option('--no-color', 'Disable colored output')
77
+ .option('--json', 'Output results as JSON (useful for CI)')
78
+ .option('--sarif', 'Output results in SARIF format (for GitHub Code Scanning)')
79
+ .option('--include-tests', 'Also scan test files (excluded by default to reduce false positives)')
80
+ .action(scanCommand);
81
+
82
+ // -----------------------------------------------------------------------------
83
+ // CHECKLIST COMMAND
84
+ // -----------------------------------------------------------------------------
85
+ program
86
+ .command('checklist')
87
+ .description('Run through the launch-day security checklist interactively')
88
+ .option('--no-interactive', 'Print checklist without prompts')
89
+ .action(checklistCommand);
90
+
91
+ // -----------------------------------------------------------------------------
92
+ // INIT COMMAND
93
+ // -----------------------------------------------------------------------------
94
+ program
95
+ .command('init')
96
+ .description('Initialize security configs in your project')
97
+ .option('-f, --force', 'Overwrite existing files')
98
+ .option('--gitignore', 'Only copy .gitignore')
99
+ .option('--headers', 'Only copy security headers config')
100
+ .option('--agents', 'Only add security rules to AI agent instruction files (CLAUDE.md, .cursor/rules/, .windsurfrules, copilot-instructions.md)')
101
+ .action(initCommand);
102
+
103
+ // -----------------------------------------------------------------------------
104
+ // FIX COMMAND
105
+ // -----------------------------------------------------------------------------
106
+ program
107
+ .command('fix')
108
+ .description('Scan for secrets and generate a .env.example with placeholder values')
109
+ .option('--dry-run', 'Preview generated .env.example without writing it')
110
+ .action(fixCommand);
111
+
112
+ // -----------------------------------------------------------------------------
113
+ // GUARD COMMAND
114
+ // -----------------------------------------------------------------------------
115
+ program
116
+ .command('guard [action]')
117
+ .description('Install a git hook to block pushes if secrets are found')
118
+ .option('--pre-commit', 'Install as pre-commit hook instead of pre-push')
119
+ .action(guardCommand);
120
+
121
+ // -----------------------------------------------------------------------------
122
+ // MCP SERVER COMMAND
123
+ // -----------------------------------------------------------------------------
124
+ program
125
+ .command('mcp')
126
+ .description('Start ship-safe as an MCP server (for Claude Desktop, Cursor, Windsurf, etc.)')
127
+ .action(mcpCommand);
128
+
129
+ // -----------------------------------------------------------------------------
130
+ // REMEDIATE COMMAND
131
+ // -----------------------------------------------------------------------------
132
+ program
133
+ .command('remediate [path]')
134
+ .description('Auto-fix hardcoded secrets: rewrite source code + write .env + update .gitignore')
135
+ .option('--dry-run', 'Preview changes without writing any files')
136
+ .option('--yes', 'Apply all fixes without prompting (for CI)')
137
+ .option('--stage', 'Also run git add on modified files after fixing')
138
+ .action(remediateCommand);
139
+
140
+ // -----------------------------------------------------------------------------
141
+ // ROTATE COMMAND
142
+ // -----------------------------------------------------------------------------
143
+ program
144
+ .command('rotate [path]')
145
+ .description('Revoke and rotate exposed secrets — opens provider dashboards with step-by-step guide')
146
+ .option('--provider <name>', 'Only rotate secrets for a specific provider (e.g. github, stripe, openai)')
147
+ .action(rotateCommand);
148
+
149
+ // -----------------------------------------------------------------------------
150
+ // AGENT COMMAND
151
+ // -----------------------------------------------------------------------------
152
+ program
153
+ .command('agent [path]')
154
+ .description('AI-powered security audit: scan, classify with Claude, auto-remediate confirmed secrets')
155
+ .option('--dry-run', 'Show classification and plan without writing any files')
156
+ .option('--model <model>', `Claude model to use (default: ${DEFAULT_MODEL})`)
157
+ .action(agentCommand);
158
+
159
+ // -----------------------------------------------------------------------------
160
+ // DEPS COMMAND
161
+ // -----------------------------------------------------------------------------
162
+ program
163
+ .command('deps [path]')
164
+ .description('Audit dependencies for known CVEs (npm, yarn, pnpm, pip-audit, bundler-audit)')
165
+ .option('--fix', 'Run the package manager fix command after auditing')
166
+ .action(depsCommand);
167
+
168
+ // -----------------------------------------------------------------------------
169
+ // SCORE COMMAND
170
+ // -----------------------------------------------------------------------------
171
+ program
172
+ .command('score [path]')
173
+ .description('Compute a 0-100 security health score for your project')
174
+ .option('--no-deps', 'Skip dependency audit')
175
+ .action(scoreCommand);
176
+
177
+ // -----------------------------------------------------------------------------
178
+ // PARSE AND RUN
179
+ // -----------------------------------------------------------------------------
180
+
181
+ // Show help if no command provided
182
+ if (process.argv.length === 2) {
183
+ console.log(banner);
184
+ console.log(chalk.yellow('\nQuick start:\n'));
185
+ console.log(chalk.white(' npx ship-safe agent . ') + chalk.gray('# AI audit: scan + classify + auto-fix'));
186
+ console.log(chalk.white(' npx ship-safe scan . ') + chalk.gray('# Scan for secrets'));
187
+ console.log(chalk.white(' npx ship-safe remediate . ') + chalk.gray('# Auto-fix: rewrite code + write .env'));
188
+ console.log(chalk.white(' npx ship-safe rotate . ') + chalk.gray('# Revoke exposed keys (provider guides)'));
189
+ console.log(chalk.white(' npx ship-safe fix ') + chalk.gray('# Generate .env.example from secrets'));
190
+ console.log(chalk.white(' npx ship-safe guard ') + chalk.gray('# Block git push if secrets found'));
191
+ console.log(chalk.white(' npx ship-safe checklist ') + chalk.gray('# Run security checklist'));
192
+ console.log(chalk.white(' npx ship-safe deps . ') + chalk.gray('# Audit dependencies for CVEs'));
193
+ console.log(chalk.white(' npx ship-safe score . ') + chalk.gray('# Security health score (0-100)'));
194
+ console.log(chalk.white(' npx ship-safe init ') + chalk.gray('# Add security configs to your project'));
195
+ console.log(chalk.white('\n npx ship-safe --help ') + chalk.gray('# Show all options'));
196
+ console.log();
197
+ process.exit(0);
198
+ }
199
+
200
+ program.parse();