ship-safe 6.1.1 → 6.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.
- package/README.md +735 -641
- package/cli/agents/api-fuzzer.js +345 -345
- package/cli/agents/auth-bypass-agent.js +348 -348
- package/cli/agents/base-agent.js +272 -272
- package/cli/agents/cicd-scanner.js +236 -201
- package/cli/agents/config-auditor.js +521 -521
- package/cli/agents/deep-analyzer.js +6 -2
- package/cli/agents/git-history-scanner.js +170 -170
- package/cli/agents/html-reporter.js +568 -568
- package/cli/agents/index.js +84 -84
- package/cli/agents/injection-tester.js +500 -500
- package/cli/agents/llm-redteam.js +251 -251
- package/cli/agents/mobile-scanner.js +231 -231
- package/cli/agents/orchestrator.js +322 -322
- package/cli/agents/pii-compliance-agent.js +301 -301
- package/cli/agents/scoring-engine.js +248 -248
- package/cli/agents/supabase-rls-agent.js +154 -154
- package/cli/agents/supply-chain-agent.js +650 -507
- package/cli/bin/ship-safe.js +452 -426
- package/cli/commands/agent.js +608 -608
- package/cli/commands/audit.js +986 -980
- package/cli/commands/baseline.js +193 -193
- package/cli/commands/ci.js +342 -342
- package/cli/commands/deps.js +516 -516
- package/cli/commands/doctor.js +159 -159
- package/cli/commands/fix.js +218 -218
- package/cli/commands/hooks.js +268 -0
- package/cli/commands/init.js +407 -407
- package/cli/commands/mcp.js +304 -304
- package/cli/commands/red-team.js +7 -1
- package/cli/commands/remediate.js +798 -798
- package/cli/commands/rotate.js +571 -571
- package/cli/commands/scan.js +569 -569
- package/cli/commands/score.js +449 -449
- package/cli/commands/watch.js +281 -281
- package/cli/hooks/patterns.js +313 -0
- package/cli/hooks/post-tool-use.js +140 -0
- package/cli/hooks/pre-tool-use.js +186 -0
- package/cli/index.js +73 -69
- package/cli/providers/llm-provider.js +397 -287
- package/cli/utils/autofix-rules.js +74 -74
- package/cli/utils/cache-manager.js +311 -311
- package/cli/utils/output.js +230 -230
- package/cli/utils/patterns.js +1121 -1121
- package/cli/utils/pdf-generator.js +94 -94
- package/package.json +69 -69
- package/configs/supabase/rls-templates.sql +0 -242
package/cli/bin/ship-safe.js
CHANGED
|
@@ -1,426 +1,452 @@
|
|
|
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
|
-
import { redTeamCommand } from '../commands/red-team.js';
|
|
35
|
-
import { watchCommand } from '../commands/watch.js';
|
|
36
|
-
import { auditCommand } from '../commands/audit.js';
|
|
37
|
-
import { doctorCommand } from '../commands/doctor.js';
|
|
38
|
-
import { baselineCommand } from '../commands/baseline.js';
|
|
39
|
-
import { ciCommand } from '../commands/ci.js';
|
|
40
|
-
import { diffCommand } from '../commands/diff.js';
|
|
41
|
-
import { vibeCheckCommand } from '../commands/vibe-check.js';
|
|
42
|
-
import { benchmarkCommand } from '../commands/benchmark.js';
|
|
43
|
-
import { openclawCommand } from '../commands/openclaw.js';
|
|
44
|
-
import { scanSkillCommand } from '../commands/scan-skill.js';
|
|
45
|
-
import { abomCommand } from '../commands/abom.js';
|
|
46
|
-
import { updateIntelCommand } from '../commands/update-intel.js';
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
${chalk.cyan('
|
|
67
|
-
${chalk.cyan('
|
|
68
|
-
${chalk.cyan('
|
|
69
|
-
${chalk.cyan('
|
|
70
|
-
${chalk.cyan('
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
.
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
.
|
|
92
|
-
.option('--
|
|
93
|
-
.option('--
|
|
94
|
-
.option('--
|
|
95
|
-
.option('--
|
|
96
|
-
.option('--
|
|
97
|
-
.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
.
|
|
105
|
-
.
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.
|
|
114
|
-
.
|
|
115
|
-
.option('--
|
|
116
|
-
.option('--
|
|
117
|
-
.option('--
|
|
118
|
-
.option('--
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
.
|
|
127
|
-
.
|
|
128
|
-
.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
.
|
|
136
|
-
.
|
|
137
|
-
.option('--
|
|
138
|
-
.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.
|
|
146
|
-
.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
.
|
|
154
|
-
.
|
|
155
|
-
.option('--
|
|
156
|
-
.option('--
|
|
157
|
-
.option('--
|
|
158
|
-
.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
.
|
|
166
|
-
.
|
|
167
|
-
.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
.
|
|
175
|
-
.
|
|
176
|
-
.option('--
|
|
177
|
-
.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
.
|
|
185
|
-
.
|
|
186
|
-
.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
.
|
|
194
|
-
.
|
|
195
|
-
.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
.
|
|
203
|
-
.
|
|
204
|
-
.option('--
|
|
205
|
-
.option('--
|
|
206
|
-
.option('--
|
|
207
|
-
.option('--
|
|
208
|
-
.option('--
|
|
209
|
-
.option('--
|
|
210
|
-
.option('--
|
|
211
|
-
.option('--no-
|
|
212
|
-
.option('--no-
|
|
213
|
-
.option('--
|
|
214
|
-
.option('--
|
|
215
|
-
.option('--
|
|
216
|
-
.option('--
|
|
217
|
-
.option('--
|
|
218
|
-
.option('--
|
|
219
|
-
.option('--
|
|
220
|
-
.option('-
|
|
221
|
-
.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
.
|
|
231
|
-
.
|
|
232
|
-
.option('--
|
|
233
|
-
.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
.
|
|
243
|
-
.
|
|
244
|
-
.option('--
|
|
245
|
-
.option('--
|
|
246
|
-
.option('--
|
|
247
|
-
.option('--
|
|
248
|
-
.option('--
|
|
249
|
-
.option('--
|
|
250
|
-
.option('--
|
|
251
|
-
.option('--
|
|
252
|
-
.option('
|
|
253
|
-
.
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
.
|
|
315
|
-
.
|
|
316
|
-
.option('--
|
|
317
|
-
.option('--
|
|
318
|
-
.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
.
|
|
348
|
-
.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
console.log(
|
|
419
|
-
console.log(chalk.
|
|
420
|
-
console.log(chalk.
|
|
421
|
-
console.log(chalk.white('
|
|
422
|
-
console.log();
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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
|
+
import { redTeamCommand } from '../commands/red-team.js';
|
|
35
|
+
import { watchCommand } from '../commands/watch.js';
|
|
36
|
+
import { auditCommand } from '../commands/audit.js';
|
|
37
|
+
import { doctorCommand } from '../commands/doctor.js';
|
|
38
|
+
import { baselineCommand } from '../commands/baseline.js';
|
|
39
|
+
import { ciCommand } from '../commands/ci.js';
|
|
40
|
+
import { diffCommand } from '../commands/diff.js';
|
|
41
|
+
import { vibeCheckCommand } from '../commands/vibe-check.js';
|
|
42
|
+
import { benchmarkCommand } from '../commands/benchmark.js';
|
|
43
|
+
import { openclawCommand } from '../commands/openclaw.js';
|
|
44
|
+
import { scanSkillCommand } from '../commands/scan-skill.js';
|
|
45
|
+
import { abomCommand } from '../commands/abom.js';
|
|
46
|
+
import { updateIntelCommand } from '../commands/update-intel.js';
|
|
47
|
+
import { hooksCommand } from '../commands/hooks.js';
|
|
48
|
+
import { ABOMGenerator } from '../agents/abom-generator.js';
|
|
49
|
+
import { PolicyEngine } from '../agents/policy-engine.js';
|
|
50
|
+
import { SBOMGenerator } from '../agents/sbom-generator.js';
|
|
51
|
+
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// CLI CONFIGURATION
|
|
54
|
+
// =============================================================================
|
|
55
|
+
|
|
56
|
+
const DEFAULT_MODEL = 'claude-haiku-4-5-20251001';
|
|
57
|
+
|
|
58
|
+
// Read version from package.json
|
|
59
|
+
const __filename = fileURLToPath(import.meta.url); // ship-safe-ignore — module's own path via import.meta.url, not user input
|
|
60
|
+
const __dirname = dirname(__filename);
|
|
61
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
|
|
62
|
+
const VERSION = packageJson.version;
|
|
63
|
+
|
|
64
|
+
// Banner shown on help
|
|
65
|
+
const banner = `
|
|
66
|
+
${chalk.cyan('███████╗██╗ ██╗██╗██████╗ ███████╗ █████╗ ███████╗███████╗')}
|
|
67
|
+
${chalk.cyan('██╔════╝██║ ██║██║██╔══██╗ ██╔════╝██╔══██╗██╔════╝██╔════╝')}
|
|
68
|
+
${chalk.cyan('███████╗███████║██║██████╔╝ ███████╗███████║█████╗ █████╗ ')}
|
|
69
|
+
${chalk.cyan('╚════██║██╔══██║██║██╔═══╝ ╚════██║██╔══██║██╔══╝ ██╔══╝ ')}
|
|
70
|
+
${chalk.cyan('███████║██║ ██║██║██║ ███████║██║ ██║██║ ███████╗')}
|
|
71
|
+
${chalk.cyan('╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝')}
|
|
72
|
+
|
|
73
|
+
${chalk.gray('Security toolkit for vibe coders. Secure your MVP in 5 minutes.')}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// PROGRAM SETUP
|
|
78
|
+
// =============================================================================
|
|
79
|
+
|
|
80
|
+
program
|
|
81
|
+
.name('ship-safe')
|
|
82
|
+
.description('Security toolkit for vibe coders and indie hackers')
|
|
83
|
+
.version(VERSION)
|
|
84
|
+
.addHelpText('before', banner);
|
|
85
|
+
|
|
86
|
+
// -----------------------------------------------------------------------------
|
|
87
|
+
// SCAN COMMAND
|
|
88
|
+
// -----------------------------------------------------------------------------
|
|
89
|
+
program
|
|
90
|
+
.command('scan [path]')
|
|
91
|
+
.description('Scan your codebase for leaked secrets (API keys, passwords, etc.)')
|
|
92
|
+
.option('-v, --verbose', 'Show all files being scanned')
|
|
93
|
+
.option('--no-color', 'Disable colored output')
|
|
94
|
+
.option('--json', 'Output results as JSON (useful for CI)')
|
|
95
|
+
.option('--sarif', 'Output results in SARIF format (for GitHub Code Scanning)')
|
|
96
|
+
.option('--include-tests', 'Also scan test files (excluded by default to reduce false positives)')
|
|
97
|
+
.option('--no-cache', 'Force full rescan (ignore cached results)')
|
|
98
|
+
.action(scanCommand);
|
|
99
|
+
|
|
100
|
+
// -----------------------------------------------------------------------------
|
|
101
|
+
// CHECKLIST COMMAND
|
|
102
|
+
// -----------------------------------------------------------------------------
|
|
103
|
+
program
|
|
104
|
+
.command('checklist')
|
|
105
|
+
.description('Run through the launch-day security checklist interactively')
|
|
106
|
+
.option('--no-interactive', 'Print checklist without prompts')
|
|
107
|
+
.action(checklistCommand);
|
|
108
|
+
|
|
109
|
+
// -----------------------------------------------------------------------------
|
|
110
|
+
// INIT COMMAND
|
|
111
|
+
// -----------------------------------------------------------------------------
|
|
112
|
+
program
|
|
113
|
+
.command('init')
|
|
114
|
+
.description('Initialize security configs in your project')
|
|
115
|
+
.option('-f, --force', 'Overwrite existing files')
|
|
116
|
+
.option('--gitignore', 'Only copy .gitignore')
|
|
117
|
+
.option('--headers', 'Only copy security headers config')
|
|
118
|
+
.option('--agents', 'Only add security rules to AI agent instruction files (CLAUDE.md, .cursor/rules/, .windsurfrules, copilot-instructions.md)')
|
|
119
|
+
.option('--openclaw', 'Generate a hardened openclaw.json template')
|
|
120
|
+
.action(initCommand);
|
|
121
|
+
|
|
122
|
+
// -----------------------------------------------------------------------------
|
|
123
|
+
// FIX COMMAND
|
|
124
|
+
// -----------------------------------------------------------------------------
|
|
125
|
+
program
|
|
126
|
+
.command('fix')
|
|
127
|
+
.description('Scan for secrets and generate a .env.example with placeholder values')
|
|
128
|
+
.option('--dry-run', 'Preview generated .env.example without writing it')
|
|
129
|
+
.action(fixCommand);
|
|
130
|
+
|
|
131
|
+
// -----------------------------------------------------------------------------
|
|
132
|
+
// GUARD COMMAND
|
|
133
|
+
// -----------------------------------------------------------------------------
|
|
134
|
+
program
|
|
135
|
+
.command('guard [action]')
|
|
136
|
+
.description('Install a git hook to block pushes if secrets are found')
|
|
137
|
+
.option('--pre-commit', 'Install as pre-commit hook instead of pre-push')
|
|
138
|
+
.option('--generate-hooks', 'Generate defensive Claude Code hooks (.claude/settings.json)')
|
|
139
|
+
.action(guardCommand);
|
|
140
|
+
|
|
141
|
+
// -----------------------------------------------------------------------------
|
|
142
|
+
// MCP SERVER COMMAND
|
|
143
|
+
// -----------------------------------------------------------------------------
|
|
144
|
+
program
|
|
145
|
+
.command('mcp')
|
|
146
|
+
.description('Start ship-safe as an MCP server (for Claude Desktop, Cursor, Windsurf, etc.)')
|
|
147
|
+
.action(mcpCommand);
|
|
148
|
+
|
|
149
|
+
// -----------------------------------------------------------------------------
|
|
150
|
+
// REMEDIATE COMMAND
|
|
151
|
+
// -----------------------------------------------------------------------------
|
|
152
|
+
program
|
|
153
|
+
.command('remediate [path]')
|
|
154
|
+
.description('Auto-fix hardcoded secrets: rewrite source code + write .env + update .gitignore')
|
|
155
|
+
.option('--dry-run', 'Preview changes without writing any files')
|
|
156
|
+
.option('--yes', 'Apply all fixes without prompting (for CI)')
|
|
157
|
+
.option('--stage', 'Also run git add on modified files after fixing')
|
|
158
|
+
.option('--all', 'Also fix common agent findings (debug mode, TLS bypass, shell injection)')
|
|
159
|
+
.action(remediateCommand);
|
|
160
|
+
|
|
161
|
+
// -----------------------------------------------------------------------------
|
|
162
|
+
// ROTATE COMMAND
|
|
163
|
+
// -----------------------------------------------------------------------------
|
|
164
|
+
program
|
|
165
|
+
.command('rotate [path]')
|
|
166
|
+
.description('Revoke and rotate exposed secrets — opens provider dashboards with step-by-step guide')
|
|
167
|
+
.option('--provider <name>', 'Only rotate secrets for a specific provider (e.g. github, stripe, openai)')
|
|
168
|
+
.action(rotateCommand);
|
|
169
|
+
|
|
170
|
+
// -----------------------------------------------------------------------------
|
|
171
|
+
// AGENT COMMAND
|
|
172
|
+
// -----------------------------------------------------------------------------
|
|
173
|
+
program
|
|
174
|
+
.command('agent [path]')
|
|
175
|
+
.description('AI-powered security audit: scan, classify with Claude, auto-remediate confirmed secrets')
|
|
176
|
+
.option('--dry-run', 'Show classification and plan without writing any files')
|
|
177
|
+
.option('--model <model>', `Claude model to use (default: ${DEFAULT_MODEL})`)
|
|
178
|
+
.action(agentCommand);
|
|
179
|
+
|
|
180
|
+
// -----------------------------------------------------------------------------
|
|
181
|
+
// DEPS COMMAND
|
|
182
|
+
// -----------------------------------------------------------------------------
|
|
183
|
+
program
|
|
184
|
+
.command('deps [path]')
|
|
185
|
+
.description('Audit dependencies for known CVEs (npm, yarn, pnpm, pip-audit, bundler-audit)')
|
|
186
|
+
.option('--fix', 'Run the package manager fix command after auditing')
|
|
187
|
+
.action(depsCommand);
|
|
188
|
+
|
|
189
|
+
// -----------------------------------------------------------------------------
|
|
190
|
+
// SCORE COMMAND
|
|
191
|
+
// -----------------------------------------------------------------------------
|
|
192
|
+
program
|
|
193
|
+
.command('score [path]')
|
|
194
|
+
.description('Compute a 0-100 security health score for your project')
|
|
195
|
+
.option('--no-deps', 'Skip dependency audit')
|
|
196
|
+
.action(scoreCommand);
|
|
197
|
+
|
|
198
|
+
// -----------------------------------------------------------------------------
|
|
199
|
+
// AUDIT COMMAND (v4.0 — Full Security Audit)
|
|
200
|
+
// -----------------------------------------------------------------------------
|
|
201
|
+
program
|
|
202
|
+
.command('audit [path]')
|
|
203
|
+
.description('Full security audit: secrets + 18 agents + deps + score + deep analysis + remediation plan')
|
|
204
|
+
.option('--json', 'Output results as JSON')
|
|
205
|
+
.option('--sarif', 'Output results in SARIF format')
|
|
206
|
+
.option('--csv', 'Output results as CSV')
|
|
207
|
+
.option('--md', 'Output results as Markdown')
|
|
208
|
+
.option('--html [file]', 'HTML report path (default: ship-safe-report.html)')
|
|
209
|
+
.option('--compare', 'Show detailed comparison with last scan')
|
|
210
|
+
.option('--timeout <ms>', 'Per-agent timeout in milliseconds (default: 30000)', parseInt)
|
|
211
|
+
.option('--no-deps', 'Skip dependency audit')
|
|
212
|
+
.option('--no-ai', 'Skip AI classification')
|
|
213
|
+
.option('--no-cache', 'Force full rescan (ignore cached results)')
|
|
214
|
+
.option('--baseline', 'Only show findings not in the baseline')
|
|
215
|
+
.option('--pdf [file]', 'Generate PDF report (requires Chrome/Chromium)')
|
|
216
|
+
.option('--deep', 'LLM-powered taint analysis for critical/high findings')
|
|
217
|
+
.option('--local', 'Use local Ollama model for deep analysis (default: llama3.2)')
|
|
218
|
+
.option('--model <model>', 'LLM model to use for deep/AI analysis')
|
|
219
|
+
.option('--provider <name>', 'LLM provider: anthropic, openai, google, ollama, groq, together, mistral, cohere, deepseek, xai, lmstudio')
|
|
220
|
+
.option('--base-url <url>', 'Custom OpenAI-compatible endpoint (e.g. http://localhost:1234/v1/chat/completions)')
|
|
221
|
+
.option('--budget <cents>', 'Max spend in cents for deep analysis (default: 50)', parseInt)
|
|
222
|
+
.option('--verify', 'Check if leaked secrets are still active (probes provider APIs)')
|
|
223
|
+
.option('-v, --verbose', 'Verbose output')
|
|
224
|
+
.action(auditCommand);
|
|
225
|
+
|
|
226
|
+
// -----------------------------------------------------------------------------
|
|
227
|
+
// DIFF COMMAND (v6.0 — Scan only changed files)
|
|
228
|
+
// -----------------------------------------------------------------------------
|
|
229
|
+
program
|
|
230
|
+
.command('diff [ref]')
|
|
231
|
+
.description('Scan only changed files (git diff) — fast pre-commit & PR scanning')
|
|
232
|
+
.option('--staged', 'Scan only staged changes')
|
|
233
|
+
.option('--json', 'Output results as JSON')
|
|
234
|
+
.option('-p, --path <path>', 'Project path (default: cwd)')
|
|
235
|
+
.option('--timeout <ms>', 'Per-agent timeout in milliseconds (default: 30000)', parseInt)
|
|
236
|
+
.action(diffCommand);
|
|
237
|
+
|
|
238
|
+
// -----------------------------------------------------------------------------
|
|
239
|
+
// RED TEAM COMMAND (v4.0 — Multi-Agent Security Audit)
|
|
240
|
+
// -----------------------------------------------------------------------------
|
|
241
|
+
program
|
|
242
|
+
.command('red-team [path]')
|
|
243
|
+
.description('Multi-agent security audit: 18 agents scan for 80+ attack classes')
|
|
244
|
+
.option('--agents <list>', 'Comma-separated list of agents to run')
|
|
245
|
+
.option('--json', 'Output results as JSON')
|
|
246
|
+
.option('--sarif', 'Output results in SARIF format')
|
|
247
|
+
.option('--html [file]', 'Generate HTML security report')
|
|
248
|
+
.option('--sbom [file]', 'Generate CycloneDX SBOM')
|
|
249
|
+
.option('--no-deps', 'Skip dependency audit')
|
|
250
|
+
.option('--no-ai', 'Skip AI classification')
|
|
251
|
+
.option('--deep', 'LLM-powered taint analysis for critical/high findings')
|
|
252
|
+
.option('--local', 'Use local Ollama model for deep analysis (default: llama3.2)')
|
|
253
|
+
.option('--model <model>', 'LLM model for deep analysis')
|
|
254
|
+
.option('--provider <name>', 'LLM provider: anthropic, openai, google, ollama, groq, together, mistral, cohere, deepseek, xai, lmstudio')
|
|
255
|
+
.option('--base-url <url>', 'Custom OpenAI-compatible endpoint (e.g. http://localhost:1234/v1/chat/completions)')
|
|
256
|
+
.option('--budget <cents>', 'Max spend in cents for deep analysis (default: 50)', parseInt)
|
|
257
|
+
.option('-v, --verbose', 'Verbose output')
|
|
258
|
+
.action(redTeamCommand);
|
|
259
|
+
|
|
260
|
+
// -----------------------------------------------------------------------------
|
|
261
|
+
// WATCH COMMAND
|
|
262
|
+
// -----------------------------------------------------------------------------
|
|
263
|
+
program
|
|
264
|
+
.command('watch [path]')
|
|
265
|
+
.description('Continuous monitoring: watch files for security issues in real-time')
|
|
266
|
+
.option('--poll', 'Use polling mode (for network drives)')
|
|
267
|
+
.option('--configs', 'Watch only agent config files (openclaw.json, .cursorrules, mcp.json, etc.)')
|
|
268
|
+
.action(watchCommand);
|
|
269
|
+
|
|
270
|
+
// -----------------------------------------------------------------------------
|
|
271
|
+
// SBOM COMMAND
|
|
272
|
+
// -----------------------------------------------------------------------------
|
|
273
|
+
program
|
|
274
|
+
.command('sbom [path]')
|
|
275
|
+
.description('Generate Software Bill of Materials (CycloneDX SBOM)')
|
|
276
|
+
.option('-o, --output <file>', 'Output file path', 'sbom.json')
|
|
277
|
+
.action((targetPath = '.', options) => {
|
|
278
|
+
const absolutePath = join(process.cwd(), targetPath);
|
|
279
|
+
const sbom = new SBOMGenerator();
|
|
280
|
+
sbom.generateToFile(absolutePath, options.output);
|
|
281
|
+
console.log(chalk.green(`✔ SBOM saved to ${options.output}`));
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// -----------------------------------------------------------------------------
|
|
285
|
+
// POLICY COMMAND
|
|
286
|
+
// -----------------------------------------------------------------------------
|
|
287
|
+
program
|
|
288
|
+
.command('policy <action>')
|
|
289
|
+
.description('Manage security policies (init: create policy template)')
|
|
290
|
+
.action((action) => {
|
|
291
|
+
if (action === 'init') {
|
|
292
|
+
const policyPath = PolicyEngine.generateTemplate(process.cwd());
|
|
293
|
+
console.log(chalk.green(`✔ Policy template created: ${policyPath}`));
|
|
294
|
+
console.log(chalk.gray(' Edit .ship-safe.policy.json to configure your security policy.'));
|
|
295
|
+
} else {
|
|
296
|
+
console.log(chalk.yellow(`Unknown policy action: ${action}. Use: policy init`));
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// -----------------------------------------------------------------------------
|
|
301
|
+
// BASELINE COMMAND (v4.3)
|
|
302
|
+
// -----------------------------------------------------------------------------
|
|
303
|
+
program
|
|
304
|
+
.command('baseline [path]')
|
|
305
|
+
.description('Create/manage a findings baseline — only report new findings on subsequent scans')
|
|
306
|
+
.option('--diff', 'Show what changed since baseline')
|
|
307
|
+
.option('--clear', 'Remove the baseline')
|
|
308
|
+
.action(baselineCommand);
|
|
309
|
+
|
|
310
|
+
// -----------------------------------------------------------------------------
|
|
311
|
+
// CI COMMAND (v5.0 — CI/CD Pipeline Integration)
|
|
312
|
+
// -----------------------------------------------------------------------------
|
|
313
|
+
program
|
|
314
|
+
.command('ci [path]')
|
|
315
|
+
.description('CI/CD pipeline mode: scan, score, exit 1 on failure — optimized for automation')
|
|
316
|
+
.option('--threshold <score>', 'Minimum passing score (default: 75)', parseInt)
|
|
317
|
+
.option('--fail-on <severity>', 'Fail on findings at this severity or above (critical, high, medium)')
|
|
318
|
+
.option('--sarif <file>', 'Write SARIF output for GitHub Code Scanning')
|
|
319
|
+
.option('--json', 'JSON output')
|
|
320
|
+
.option('--no-deps', 'Skip dependency audit')
|
|
321
|
+
.option('--baseline', 'Only check new findings (not in baseline)')
|
|
322
|
+
.option('--github-pr', 'Post findings as a GitHub PR comment (requires gh CLI)')
|
|
323
|
+
.action(ciCommand);
|
|
324
|
+
|
|
325
|
+
// -----------------------------------------------------------------------------
|
|
326
|
+
// VIBE CHECK COMMAND
|
|
327
|
+
// -----------------------------------------------------------------------------
|
|
328
|
+
program
|
|
329
|
+
.command('vibe-check [path]')
|
|
330
|
+
.description('Fun security check with emoji output, shareable score, and badge generator')
|
|
331
|
+
.option('--badge', 'Generate a shields.io markdown badge for your README')
|
|
332
|
+
.action(vibeCheckCommand);
|
|
333
|
+
|
|
334
|
+
// -----------------------------------------------------------------------------
|
|
335
|
+
// BENCHMARK COMMAND
|
|
336
|
+
// -----------------------------------------------------------------------------
|
|
337
|
+
program
|
|
338
|
+
.command('benchmark [path]')
|
|
339
|
+
.description('Compare your security score against industry averages')
|
|
340
|
+
.option('--json', 'Output results as JSON')
|
|
341
|
+
.action(benchmarkCommand);
|
|
342
|
+
|
|
343
|
+
// -----------------------------------------------------------------------------
|
|
344
|
+
// OPENCLAW COMMAND
|
|
345
|
+
// -----------------------------------------------------------------------------
|
|
346
|
+
program
|
|
347
|
+
.command('openclaw [path]')
|
|
348
|
+
.description('OpenClaw security scan: agent configs, MCP servers, skills, hooks')
|
|
349
|
+
.option('--fix', 'Auto-harden OpenClaw and agent configurations')
|
|
350
|
+
.option('--preflight', 'Exit non-zero on critical findings (for CI)')
|
|
351
|
+
.option('--red-team', 'Simulate adversarial attacks against agent configs')
|
|
352
|
+
.option('--json', 'Output results as JSON')
|
|
353
|
+
.action(openclawCommand);
|
|
354
|
+
|
|
355
|
+
// -----------------------------------------------------------------------------
|
|
356
|
+
// SCAN-SKILL COMMAND
|
|
357
|
+
// -----------------------------------------------------------------------------
|
|
358
|
+
program
|
|
359
|
+
.command('scan-skill [target]')
|
|
360
|
+
.description('Analyze an AI agent skill for security issues before installing it')
|
|
361
|
+
.option('--all', 'Scan all skills defined in openclaw.json')
|
|
362
|
+
.option('--json', 'Output results as JSON')
|
|
363
|
+
.action(scanSkillCommand);
|
|
364
|
+
|
|
365
|
+
// -----------------------------------------------------------------------------
|
|
366
|
+
// ABOM COMMAND
|
|
367
|
+
// -----------------------------------------------------------------------------
|
|
368
|
+
program
|
|
369
|
+
.command('abom [path]')
|
|
370
|
+
.description('Generate Agent Bill of Materials (CycloneDX ABOM) — MCP servers, skills, configs, LLM providers')
|
|
371
|
+
.option('-o, --output <file>', 'Output file path', 'abom.json')
|
|
372
|
+
.option('--json', 'Output to stdout as JSON')
|
|
373
|
+
.action(abomCommand);
|
|
374
|
+
|
|
375
|
+
// -----------------------------------------------------------------------------
|
|
376
|
+
// HOOKS COMMAND (Claude Code PreToolUse / PostToolUse integration)
|
|
377
|
+
// -----------------------------------------------------------------------------
|
|
378
|
+
program
|
|
379
|
+
.command('hooks [action]')
|
|
380
|
+
.description('Manage Claude Code hooks — real-time security gate on every Write, Edit, and Bash call')
|
|
381
|
+
.addHelpText('after', `
|
|
382
|
+
Actions:
|
|
383
|
+
install Register ship-safe as PreToolUse + PostToolUse hooks in ~/.claude/settings.json
|
|
384
|
+
remove Unregister ship-safe hooks
|
|
385
|
+
status Show whether hooks are installed
|
|
386
|
+
|
|
387
|
+
How it works:
|
|
388
|
+
PreToolUse — blocks Write/Edit if critical secrets are in the new content;
|
|
389
|
+
blocks dangerous Bash patterns (curl|bash, credential exfiltration)
|
|
390
|
+
PostToolUse — scans the file after it is written; injects advisory findings
|
|
391
|
+
into Claude's context so issues are caught immediately
|
|
392
|
+
`)
|
|
393
|
+
.action(hooksCommand);
|
|
394
|
+
|
|
395
|
+
// -----------------------------------------------------------------------------
|
|
396
|
+
// UPDATE-INTEL COMMAND
|
|
397
|
+
// -----------------------------------------------------------------------------
|
|
398
|
+
program
|
|
399
|
+
.command('update-intel')
|
|
400
|
+
.description('Update threat intelligence feed (malicious skill hashes, compromised MCP servers)')
|
|
401
|
+
.option('--url <url>', 'Custom feed URL')
|
|
402
|
+
.action(updateIntelCommand);
|
|
403
|
+
|
|
404
|
+
// -----------------------------------------------------------------------------
|
|
405
|
+
// DOCTOR COMMAND
|
|
406
|
+
// -----------------------------------------------------------------------------
|
|
407
|
+
program
|
|
408
|
+
.command('doctor')
|
|
409
|
+
.description('Diagnose environment: check Node.js, git, API keys, cache, and dependencies')
|
|
410
|
+
.action(doctorCommand);
|
|
411
|
+
|
|
412
|
+
// -----------------------------------------------------------------------------
|
|
413
|
+
// PARSE AND RUN
|
|
414
|
+
// -----------------------------------------------------------------------------
|
|
415
|
+
|
|
416
|
+
// Show help if no command provided
|
|
417
|
+
if (process.argv.length === 2) {
|
|
418
|
+
console.log(banner);
|
|
419
|
+
console.log(chalk.yellow('\nQuick start:\n'));
|
|
420
|
+
console.log(chalk.cyan.bold(' v6.0 — Full Security Audit'));
|
|
421
|
+
console.log(chalk.white(' npx ship-safe audit . ') + chalk.gray('# Full audit: secrets + 18 agents + deps + remediation'));
|
|
422
|
+
console.log(chalk.white(' npx ship-safe audit . --deep') + chalk.gray('# LLM-powered taint analysis (Anthropic/Ollama)'));
|
|
423
|
+
console.log(chalk.white(' npx ship-safe red-team . ') + chalk.gray('# 18-agent red team scan (80+ attack classes)'));
|
|
424
|
+
console.log(chalk.white(' npx ship-safe vibe-check . ') + chalk.gray('# Fun security check with emoji & shareable badge'));
|
|
425
|
+
console.log(chalk.white(' npx ship-safe benchmark . ') + chalk.gray('# Compare score against industry averages'));
|
|
426
|
+
console.log(chalk.white(' npx ship-safe ci . ') + chalk.gray('# CI/CD mode: scan, score, exit code'));
|
|
427
|
+
console.log(chalk.white(' npx ship-safe diff ') + chalk.gray('# Scan only changed files (fast pre-commit)'));
|
|
428
|
+
console.log(chalk.white(' npx ship-safe watch . ') + chalk.gray('# Continuous monitoring mode'));
|
|
429
|
+
console.log(chalk.white(' npx ship-safe openclaw . ') + chalk.gray('# OpenClaw & agent config security scan'));
|
|
430
|
+
console.log(chalk.white(' npx ship-safe scan-skill <u>') + chalk.gray('# Vet a skill before installing'));
|
|
431
|
+
console.log(chalk.white(' npx ship-safe abom . ') + chalk.gray('# Agent Bill of Materials (CycloneDX)'));
|
|
432
|
+
console.log(chalk.white(' npx ship-safe sbom . ') + chalk.gray('# Generate CycloneDX SBOM (CRA-ready)'));
|
|
433
|
+
console.log(chalk.white(' npx ship-safe update-intel ') + chalk.gray('# Update threat intelligence feed'));
|
|
434
|
+
console.log(chalk.white(' npx ship-safe policy init ') + chalk.gray('# Create security policy template'));
|
|
435
|
+
console.log(chalk.white(' npx ship-safe doctor ') + chalk.gray('# Check environment and configuration'));
|
|
436
|
+
console.log();
|
|
437
|
+
console.log(chalk.gray(' Core commands:'));
|
|
438
|
+
console.log(chalk.white(' npx ship-safe agent . ') + chalk.gray('# AI audit: scan + classify + auto-fix'));
|
|
439
|
+
console.log(chalk.white(' npx ship-safe scan . ') + chalk.gray('# Scan for secrets'));
|
|
440
|
+
console.log(chalk.white(' npx ship-safe remediate . ') + chalk.gray('# Auto-fix: rewrite code + write .env'));
|
|
441
|
+
console.log(chalk.white(' npx ship-safe rotate . ') + chalk.gray('# Revoke exposed keys (provider guides)'));
|
|
442
|
+
console.log(chalk.white(' npx ship-safe deps . ') + chalk.gray('# Audit dependencies for CVEs'));
|
|
443
|
+
console.log(chalk.white(' npx ship-safe score . ') + chalk.gray('# Security health score (0-100)'));
|
|
444
|
+
console.log(chalk.white(' npx ship-safe hooks install ') + chalk.gray('# Real-time security gate inside Claude Code (PreToolUse/PostToolUse)'));
|
|
445
|
+
console.log(chalk.white(' npx ship-safe guard ') + chalk.gray('# Block git push if secrets found'));
|
|
446
|
+
console.log(chalk.white(' npx ship-safe init ') + chalk.gray('# Add security configs to your project'));
|
|
447
|
+
console.log(chalk.white('\n npx ship-safe --help ') + chalk.gray('# Show all options'));
|
|
448
|
+
console.log();
|
|
449
|
+
process.exit(0);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
program.parse();
|