ship-safe 6.1.1 → 6.3.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 +748 -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 +85 -84
- package/cli/agents/injection-tester.js +500 -500
- package/cli/agents/legal-risk-agent.js +302 -0
- 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 +464 -426
- package/cli/commands/agent.js +608 -608
- package/cli/commands/audit.js +1006 -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/legal.js +158 -0
- 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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legal Command
|
|
3
|
+
* =============
|
|
4
|
+
*
|
|
5
|
+
* Scans dependency manifests for packages that carry legal risk:
|
|
6
|
+
* active DMCA takedowns, leaked-source derivatives, IP disputes,
|
|
7
|
+
* and license violations.
|
|
8
|
+
*
|
|
9
|
+
* USAGE:
|
|
10
|
+
* ship-safe legal [path] Scan for legally risky dependencies
|
|
11
|
+
* ship-safe legal . --json JSON output
|
|
12
|
+
*
|
|
13
|
+
* EXIT CODES:
|
|
14
|
+
* 0 Clean — no legally risky packages found
|
|
15
|
+
* 1 Findings — one or more legally risky packages detected
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import chalk from 'chalk';
|
|
21
|
+
import ora from 'ora';
|
|
22
|
+
import { LegalRiskAgent } from '../agents/legal-risk-agent.js';
|
|
23
|
+
import * as output from '../utils/output.js';
|
|
24
|
+
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// RISK LABELS & COLORS
|
|
27
|
+
// =============================================================================
|
|
28
|
+
|
|
29
|
+
const RISK_COLORS = {
|
|
30
|
+
dmca: chalk.red.bold,
|
|
31
|
+
'ip-dispute': chalk.red,
|
|
32
|
+
'leaked-source': chalk.yellow.bold,
|
|
33
|
+
'license-violation': chalk.yellow,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const RISK_LABELS = {
|
|
37
|
+
dmca: 'DMCA Takedown',
|
|
38
|
+
'ip-dispute': 'IP Dispute',
|
|
39
|
+
'leaked-source': 'Leaked Source',
|
|
40
|
+
'license-violation': 'License Violation',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const SEVERITY_COLORS = {
|
|
44
|
+
critical: chalk.bgRed.white.bold,
|
|
45
|
+
high: chalk.red.bold,
|
|
46
|
+
medium: chalk.yellow,
|
|
47
|
+
low: chalk.blue,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// MAIN COMMAND
|
|
52
|
+
// =============================================================================
|
|
53
|
+
|
|
54
|
+
export async function legalCommand(targetPath = '.', options = {}) {
|
|
55
|
+
const absolutePath = path.resolve(targetPath);
|
|
56
|
+
|
|
57
|
+
if (!fs.existsSync(absolutePath)) {
|
|
58
|
+
output.error(`Path does not exist: ${absolutePath}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!options.json) {
|
|
63
|
+
console.log();
|
|
64
|
+
output.header('Legal Risk Audit');
|
|
65
|
+
console.log(chalk.gray(' Scanning for DMCA notices, leaked-source derivatives, and IP disputes'));
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── Run the agent ──────────────────────────────────────────────────────────
|
|
70
|
+
const spinner = options.json
|
|
71
|
+
? null
|
|
72
|
+
: ora({ text: 'Scanning dependency manifests…', color: 'cyan' }).start();
|
|
73
|
+
|
|
74
|
+
const agent = new LegalRiskAgent();
|
|
75
|
+
let findings = [];
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
findings = await agent.analyze({ rootPath: absolutePath, files: [] });
|
|
79
|
+
if (spinner) spinner.stop();
|
|
80
|
+
} catch (err) {
|
|
81
|
+
if (spinner) spinner.stop();
|
|
82
|
+
output.error(`Legal scan failed: ${err.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── JSON output ────────────────────────────────────────────────────────────
|
|
87
|
+
if (options.json) {
|
|
88
|
+
console.log(JSON.stringify({ findings, total: findings.length }, null, 2));
|
|
89
|
+
process.exit(findings.length > 0 ? 1 : 0);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ── Human-readable output ──────────────────────────────────────────────────
|
|
93
|
+
if (findings.length === 0) {
|
|
94
|
+
output.success('No legally risky packages found.');
|
|
95
|
+
console.log();
|
|
96
|
+
console.log(chalk.gray(' Scanned: package.json, requirements.txt, Cargo.toml, go.mod'));
|
|
97
|
+
console.log();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Group by severity
|
|
102
|
+
const bySeverity = { critical: [], high: [], medium: [], low: [] };
|
|
103
|
+
for (const f of findings) {
|
|
104
|
+
(bySeverity[f.severity] || bySeverity.medium).push(f);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const total = findings.length;
|
|
108
|
+
const critCount = bySeverity.critical.length;
|
|
109
|
+
const highCount = bySeverity.high.length;
|
|
110
|
+
|
|
111
|
+
// Summary line
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.red.bold(` ${total} legal risk finding${total === 1 ? '' : 's'}`),
|
|
114
|
+
chalk.gray('—'),
|
|
115
|
+
critCount > 0 ? chalk.red.bold(`${critCount} critical`) + chalk.gray(', ') : '',
|
|
116
|
+
highCount > 0 ? chalk.red(`${highCount} high`) : '',
|
|
117
|
+
);
|
|
118
|
+
console.log();
|
|
119
|
+
|
|
120
|
+
// Print findings
|
|
121
|
+
for (const severity of ['critical', 'high', 'medium', 'low']) {
|
|
122
|
+
const group = bySeverity[severity];
|
|
123
|
+
if (group.length === 0) continue;
|
|
124
|
+
|
|
125
|
+
for (const f of group) {
|
|
126
|
+
const sevBadge = SEVERITY_COLORS[severity]
|
|
127
|
+
? SEVERITY_COLORS[severity](` ${severity.toUpperCase()} `)
|
|
128
|
+
: chalk.gray(` ${severity.toUpperCase()} `);
|
|
129
|
+
|
|
130
|
+
// Extract risk type from rule: LEGAL_RISK_DMCA → dmca
|
|
131
|
+
const riskKey = f.rule
|
|
132
|
+
.replace('LEGAL_RISK_', '')
|
|
133
|
+
.toLowerCase()
|
|
134
|
+
.replace(/_/g, '-');
|
|
135
|
+
const riskColor = RISK_COLORS[riskKey] || chalk.white;
|
|
136
|
+
const riskLabel = RISK_LABELS[riskKey] || riskKey;
|
|
137
|
+
|
|
138
|
+
console.log(` ${sevBadge} ${chalk.white.bold(f.title)}`);
|
|
139
|
+
console.log(` ${riskColor(`[${riskLabel}]`)} ${chalk.gray(path.relative(absolutePath, f.file) || f.file)}`);
|
|
140
|
+
console.log();
|
|
141
|
+
console.log(` ${chalk.gray(f.description)}`);
|
|
142
|
+
console.log();
|
|
143
|
+
if (f.fix) {
|
|
144
|
+
console.log(` ${chalk.cyan('Fix:')} ${chalk.gray(f.fix)}`);
|
|
145
|
+
}
|
|
146
|
+
console.log();
|
|
147
|
+
console.log(chalk.gray(' ' + '─'.repeat(56)));
|
|
148
|
+
console.log();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Footer
|
|
153
|
+
console.log(chalk.yellow.bold(' ⚠ Shipping legally risky packages can expose your project to IP liability.'));
|
|
154
|
+
console.log(chalk.gray(' Review each finding and remove the affected dependency before releasing.'));
|
|
155
|
+
console.log();
|
|
156
|
+
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|