depguard-cli 1.3.0 → 1.4.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 +116 -2
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +14 -6
- package/dist/audit.js.map +1 -1
- package/dist/cli.js +75 -2
- package/dist/cli.js.map +1 -1
- package/dist/guard.d.ts +29 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +233 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +54 -1
- package/dist/license.js.map +1 -1
- package/dist/mcp.js +65 -1
- package/dist/mcp.js.map +1 -1
- package/dist/native-alternatives.js +1 -1
- package/dist/native-alternatives.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +7 -2
- package/dist/registry.js.map +1 -1
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +55 -14
- package/dist/scorer.js.map +1 -1
- package/dist/script-analysis.d.ts +5 -0
- package/dist/script-analysis.d.ts.map +1 -1
- package/dist/script-analysis.js +19 -6
- package/dist/script-analysis.js.map +1 -1
- package/dist/semver.d.ts +3 -1
- package/dist/semver.d.ts.map +1 -1
- package/dist/semver.js +24 -5
- package/dist/semver.js.map +1 -1
- package/dist/sweep.d.ts +53 -0
- package/dist/sweep.d.ts.map +1 -0
- package/dist/sweep.js +639 -0
- package/dist/sweep.js.map +1 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +31 -0
- package/dist/tokens.js.map +1 -1
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -30,6 +30,12 @@ depguard-cli score <package> [--target-license MIT] [--json]
|
|
|
30
30
|
|
|
31
31
|
# Get install/write recommendation
|
|
32
32
|
depguard-cli should-use <intent...> [--threshold 60] [--json]
|
|
33
|
+
|
|
34
|
+
# Pre-install guardian (verify + audit + allow/warn/block)
|
|
35
|
+
depguard-cli guard <package> [--threshold 60] [--block] [--json]
|
|
36
|
+
|
|
37
|
+
# Detect unused dependencies
|
|
38
|
+
depguard-cli sweep [path] [--include-dev] [--json]
|
|
33
39
|
```
|
|
34
40
|
|
|
35
41
|
### Examples
|
|
@@ -46,12 +52,20 @@ depguard-cli score lodash --json
|
|
|
46
52
|
|
|
47
53
|
# Should I install or write my own?
|
|
48
54
|
depguard-cli should-use "http client" --threshold 70
|
|
55
|
+
|
|
56
|
+
# Check before installing — blocks nonexistent/typosquat packages
|
|
57
|
+
depguard-cli guard expresss
|
|
58
|
+
# [WARN] expresss
|
|
59
|
+
# Possible typosquat of: express
|
|
60
|
+
|
|
61
|
+
# Find unused dependencies in your project
|
|
62
|
+
depguard-cli sweep . --include-dev
|
|
49
63
|
```
|
|
50
64
|
|
|
51
65
|
## API
|
|
52
66
|
|
|
53
67
|
```typescript
|
|
54
|
-
import { audit, search, score, shouldUse } from 'depguard-cli'
|
|
68
|
+
import { audit, search, score, shouldUse, guard, verify, sweep } from 'depguard-cli'
|
|
55
69
|
|
|
56
70
|
// Full audit report
|
|
57
71
|
const report = await audit('express', 'MIT')
|
|
@@ -73,6 +87,22 @@ const rec = await shouldUse('http client')
|
|
|
73
87
|
console.log(rec.action) // "install"
|
|
74
88
|
console.log(rec.package) // "axios"
|
|
75
89
|
console.log(rec.reasoning) // "axios scores 85/100 (≥60) — safe to install"
|
|
90
|
+
|
|
91
|
+
// Pre-install guardian — verify + audit + decision
|
|
92
|
+
const check = await guard('expresss')
|
|
93
|
+
console.log(check.exists) // true (but suspicious)
|
|
94
|
+
console.log(check.possibleTyposquat) // true
|
|
95
|
+
console.log(check.similarTo) // ["express"]
|
|
96
|
+
console.log(check.decision) // "warn"
|
|
97
|
+
|
|
98
|
+
// AI hallucination guard — does this package even exist?
|
|
99
|
+
const exists = await verify('ai-hallucinated-pkg')
|
|
100
|
+
console.log(exists.exists) // false
|
|
101
|
+
|
|
102
|
+
// Dead dependency detection
|
|
103
|
+
const sweepResult = await sweep('.', { includeDevDependencies: true })
|
|
104
|
+
console.log(sweepResult.unused) // [{ name: 'lodash', status: 'unused', ... }]
|
|
105
|
+
console.log(sweepResult.estimatedSavingsKB) // 1400
|
|
76
106
|
```
|
|
77
107
|
|
|
78
108
|
## Scoring
|
|
@@ -181,6 +211,9 @@ claude mcp add --transport stdio depguard -- npx -y depguard-cli --mcp
|
|
|
181
211
|
| `depguard_search` | Search npm for packages by keywords |
|
|
182
212
|
| `depguard_score` | Score a package 0-100 |
|
|
183
213
|
| `depguard_should_use` | Recommend install, use native Node.js, or write from scratch |
|
|
214
|
+
| `depguard_guard` | Pre-install guardian: verify, audit, allow/warn/block decision |
|
|
215
|
+
| `depguard_verify` | AI hallucination guard: check if a package exists + typosquatting |
|
|
216
|
+
| `depguard_sweep` | Dead dependency detection: find unused packages in a project |
|
|
184
217
|
|
|
185
218
|
### Bulk audit
|
|
186
219
|
|
|
@@ -212,6 +245,87 @@ const report = await auditProject('./package.json', {
|
|
|
212
245
|
|
|
213
246
|
Via MCP, the agent just passes the file path — depguard reads it, detects the project license, and audits everything.
|
|
214
247
|
|
|
248
|
+
## Pre-Install Guardian
|
|
249
|
+
|
|
250
|
+
The `guard` command is the recommended entry point for AI agents. Before installing any package, it runs three checks in sequence:
|
|
251
|
+
|
|
252
|
+
1. **Existence check** — Does the package exist on npm? (blocks AI hallucinations)
|
|
253
|
+
2. **Typosquatting detection** — Is the name suspiciously similar to a popular package? (Levenshtein distance against 100+ top packages)
|
|
254
|
+
3. **Security audit** — Score, vulnerabilities, deprecated status, install script analysis
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Safe package
|
|
258
|
+
depguard-cli guard express
|
|
259
|
+
# [ALLOW] express
|
|
260
|
+
# Score: 82/100 — safe to install
|
|
261
|
+
|
|
262
|
+
# Typosquat attempt
|
|
263
|
+
depguard-cli guard expresss
|
|
264
|
+
# [WARN] expresss
|
|
265
|
+
# Possible typosquat of: express
|
|
266
|
+
# Score: 45/100 is below threshold 60
|
|
267
|
+
|
|
268
|
+
# Nonexistent package (AI hallucination)
|
|
269
|
+
depguard-cli guard ai-made-up-package
|
|
270
|
+
# [BLOCK] ai-made-up-package
|
|
271
|
+
# Package does NOT exist on npm!
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Use `--block` to escalate all warnings to blocks (useful in CI):
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
depguard-cli guard sketchy-lib --block
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### AI Hallucination Guard
|
|
281
|
+
|
|
282
|
+
The `verify` tool is a lightweight version of `guard` — it only checks if a package exists and whether the name is a possible typosquat. No audit, no scoring. Fast enough to run on every `npm install` suggestion from an AI agent.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { verify } from 'depguard-cli'
|
|
286
|
+
|
|
287
|
+
const result = await verify('expresss')
|
|
288
|
+
console.log(result.exists) // true
|
|
289
|
+
console.log(result.possibleTyposquat) // true
|
|
290
|
+
console.log(result.similarTo) // ["express"]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Dead Dependency Detection
|
|
294
|
+
|
|
295
|
+
The `sweep` command scans your project to find npm packages listed in `package.json` but not actually imported or used in source code.
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
depguard-cli sweep . --include-dev
|
|
299
|
+
|
|
300
|
+
# Scanned 42 files, 15 dependencies
|
|
301
|
+
#
|
|
302
|
+
# Unused (3):
|
|
303
|
+
# - lodash@^4.17.21 (~1400 KB)
|
|
304
|
+
# - moment@^2.29.4 (~800 KB)
|
|
305
|
+
# - request@^2.88.2 (~250 KB)
|
|
306
|
+
#
|
|
307
|
+
# Maybe unused (1):
|
|
308
|
+
# ? some-dev-tool@^1.0.0
|
|
309
|
+
#
|
|
310
|
+
# Estimated savings: ~2450 KB
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Smart detection:**
|
|
314
|
+
- Scans all `.js`, `.ts`, `.mjs`, `.cjs`, `.jsx`, `.tsx` files for `import`/`require`/`export from`
|
|
315
|
+
- Recognizes config-only dependencies (eslint, prettier, typescript, jest, vitest, babel, tailwind, etc.)
|
|
316
|
+
- Detects binaries used in npm scripts
|
|
317
|
+
- Handles `@types/*` packages paired with runtime dependencies
|
|
318
|
+
- Marks untraced devDependencies as "maybe-unused" instead of "unused"
|
|
319
|
+
- Estimates disk size savings
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
import { sweep } from 'depguard-cli'
|
|
323
|
+
|
|
324
|
+
const result = await sweep('.', { includeDevDependencies: true })
|
|
325
|
+
console.log(result.unused) // [{ name: 'lodash', estimatedSizeKB: 1400, ... }]
|
|
326
|
+
console.log(result.estimatedSavingsKB) // 2450
|
|
327
|
+
```
|
|
328
|
+
|
|
215
329
|
## Smart Advisor
|
|
216
330
|
|
|
217
331
|
The `should_use` tool now checks for native Node.js alternatives before recommending npm packages:
|
|
@@ -313,7 +427,7 @@ A dependency is compatible if its license is equally or more permissive than you
|
|
|
313
427
|
```bash
|
|
314
428
|
npm run build # compile TypeScript
|
|
315
429
|
npm run lint # ESLint (strict)
|
|
316
|
-
npm test #
|
|
430
|
+
npm test # 147 tests (all offline)
|
|
317
431
|
npm run check # build + lint + test + audit
|
|
318
432
|
```
|
|
319
433
|
|
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAoD,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAoD,MAAM,YAAY,CAAA;AA+ExG;;;;GAIG;AACH,wBAAsB,KAAK,CACzB,IAAI,EAAE,MAAM,EACZ,aAAa,SAAQ,EACrB,OAAO,GAAE,OAA0B,GAClC,OAAO,CAAC,WAAW,CAAC,CAqHtB"}
|
package/dist/audit.js
CHANGED
|
@@ -3,14 +3,14 @@ import { checkLicenseCompatibility } from './license.js';
|
|
|
3
3
|
import { analyzeScripts } from './script-analysis.js';
|
|
4
4
|
import { satisfiesRange } from './semver.js';
|
|
5
5
|
const INSTALL_SCRIPT_NAMES = ['preinstall', 'install', 'postinstall'];
|
|
6
|
-
/** Map GitHub severity to npm severity */
|
|
6
|
+
/** Map GitHub severity to npm severity — unknown defaults to moderate (not low) for safety */
|
|
7
7
|
function mapGitHubSeverity(severity) {
|
|
8
8
|
switch (severity) {
|
|
9
9
|
case 'critical': return 'critical';
|
|
10
10
|
case 'high': return 'high';
|
|
11
11
|
case 'medium': return 'moderate';
|
|
12
12
|
case 'low': return 'low';
|
|
13
|
-
default: return '
|
|
13
|
+
default: return 'moderate'; // Unknown severity → err on side of caution
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
@@ -18,11 +18,12 @@ function mapGitHubSeverity(severity) {
|
|
|
18
18
|
* GitHub advisories are converted to NpmAdvisory format.
|
|
19
19
|
*/
|
|
20
20
|
function mergeAdvisories(npmAdvisories, ghAdvisories, currentVersion) {
|
|
21
|
-
const
|
|
21
|
+
const seenUrls = new Set();
|
|
22
|
+
const seenCves = new Set();
|
|
22
23
|
const merged = [];
|
|
23
24
|
// Add npm advisories first (npm bulk endpoint already filters by version)
|
|
24
25
|
for (const adv of npmAdvisories) {
|
|
25
|
-
|
|
26
|
+
seenUrls.add(adv.url);
|
|
26
27
|
merged.push({ ...adv, source: 'npm' });
|
|
27
28
|
}
|
|
28
29
|
// Guard against non-array responses
|
|
@@ -30,12 +31,19 @@ function mergeAdvisories(npmAdvisories, ghAdvisories, currentVersion) {
|
|
|
30
31
|
return merged;
|
|
31
32
|
// Add GitHub advisories that aren't already covered
|
|
32
33
|
for (const gh of ghAdvisories) {
|
|
33
|
-
|
|
34
|
+
// Dedup by URL
|
|
35
|
+
if (seenUrls.has(gh.html_url))
|
|
34
36
|
continue;
|
|
35
|
-
//
|
|
37
|
+
// Dedup by GHSA ID in npm URLs
|
|
36
38
|
const ghsaInNpm = npmAdvisories.some(a => a.url.includes(gh.ghsa_id));
|
|
37
39
|
if (ghsaInNpm)
|
|
38
40
|
continue;
|
|
41
|
+
// Dedup by CVE ID — same vulnerability reported under different GHSA entries
|
|
42
|
+
if (gh.cve_id) {
|
|
43
|
+
if (seenCves.has(gh.cve_id))
|
|
44
|
+
continue;
|
|
45
|
+
seenCves.add(gh.cve_id);
|
|
46
|
+
}
|
|
39
47
|
// Filter: only include if current version is actually affected
|
|
40
48
|
const vuln = gh.vulnerabilities?.[0];
|
|
41
49
|
const range = vuln?.vulnerable_version_range;
|
package/dist/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AACpG,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;AAErE,
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,8 @@ import { audit } from './audit.js';
|
|
|
4
4
|
import { search } from './search.js';
|
|
5
5
|
import { score } from './scorer.js';
|
|
6
6
|
import { shouldUse } from './advisor.js';
|
|
7
|
+
import { guard } from './guard.js';
|
|
8
|
+
import { sweep } from './sweep.js';
|
|
7
9
|
const { values, positionals } = parseArgs({
|
|
8
10
|
allowPositionals: true,
|
|
9
11
|
options: {
|
|
@@ -12,6 +14,8 @@ const { values, positionals } = parseArgs({
|
|
|
12
14
|
'limit': { type: 'string', default: '10' },
|
|
13
15
|
'json': { type: 'boolean', default: false },
|
|
14
16
|
'mcp': { type: 'boolean', default: false },
|
|
17
|
+
'block': { type: 'boolean', default: false },
|
|
18
|
+
'include-dev': { type: 'boolean', default: false },
|
|
15
19
|
'help': { type: 'boolean', short: 'h', default: false },
|
|
16
20
|
},
|
|
17
21
|
});
|
|
@@ -33,13 +37,17 @@ Commands:
|
|
|
33
37
|
search <keywords...> Search npm for packages by keywords
|
|
34
38
|
score <package> Score a package 0-100
|
|
35
39
|
should-use <intent...> Recommend install vs write-from-scratch
|
|
40
|
+
guard <package> Pre-install check: verify, audit, allow/warn/block
|
|
41
|
+
sweep [path] Detect unused dependencies in a project
|
|
36
42
|
|
|
37
43
|
Options:
|
|
38
44
|
--target-license <id> Target project license (default: MIT)
|
|
39
|
-
--threshold <n> Score threshold for should-use (default: 60)
|
|
45
|
+
--threshold <n> Score threshold for should-use/guard (default: 60)
|
|
40
46
|
--limit <n> Max results for search (default: 10)
|
|
41
47
|
--json Output as JSON
|
|
42
48
|
--mcp Start MCP server (JSON-RPC over stdio)
|
|
49
|
+
--block Guard: escalate warnings to blocks
|
|
50
|
+
--include-dev Sweep: include devDependencies
|
|
43
51
|
-h, --help Show this help
|
|
44
52
|
`);
|
|
45
53
|
process.exit(0);
|
|
@@ -135,8 +143,73 @@ Options:
|
|
|
135
143
|
output(rec, json);
|
|
136
144
|
break;
|
|
137
145
|
}
|
|
146
|
+
case 'guard': {
|
|
147
|
+
const name = positionals[1];
|
|
148
|
+
if (!name) {
|
|
149
|
+
console.error('Usage: depguard-cli guard <package>');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
const result = await guard(name, {
|
|
153
|
+
threshold,
|
|
154
|
+
targetLicense,
|
|
155
|
+
block: values.block ?? false,
|
|
156
|
+
});
|
|
157
|
+
if (json) {
|
|
158
|
+
output(result, true);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const icon = result.decision === 'allow' ? 'ALLOW' : result.decision === 'warn' ? 'WARN' : 'BLOCK';
|
|
162
|
+
console.log(`\n[${icon}] ${result.package}`);
|
|
163
|
+
if (!result.exists)
|
|
164
|
+
console.log(' Package does NOT exist on npm!');
|
|
165
|
+
if (result.possibleTyposquat)
|
|
166
|
+
console.log(` Possible typosquat of: ${result.similarTo.join(', ')}`);
|
|
167
|
+
if (result.score !== null)
|
|
168
|
+
console.log(` Score: ${result.score}/100`);
|
|
169
|
+
for (const reason of result.reasons)
|
|
170
|
+
console.log(` - ${reason}`);
|
|
171
|
+
console.log();
|
|
172
|
+
}
|
|
173
|
+
if (result.decision === 'block')
|
|
174
|
+
process.exit(1);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case 'sweep': {
|
|
178
|
+
const projectPath = positionals[1] ?? process.cwd();
|
|
179
|
+
const result = await sweep(projectPath, {
|
|
180
|
+
includeDevDependencies: values['include-dev'] ?? false,
|
|
181
|
+
});
|
|
182
|
+
if (json) {
|
|
183
|
+
output(result, true);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
console.log(`\nScanned ${result.scannedFiles} files, ${result.totalDependencies} dependencies\n`);
|
|
187
|
+
if (result.unused.length > 0) {
|
|
188
|
+
console.log(`Unused (${result.unused.length}):`);
|
|
189
|
+
for (const dep of result.unused) {
|
|
190
|
+
const size = dep.estimatedSizeKB ? ` (~${dep.estimatedSizeKB} KB)` : '';
|
|
191
|
+
console.log(` - ${dep.name}@${dep.version}${size}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (result.maybeUnused.length > 0) {
|
|
195
|
+
console.log(`\nMaybe unused (${result.maybeUnused.length}):`);
|
|
196
|
+
for (const dep of result.maybeUnused) {
|
|
197
|
+
console.log(` ? ${dep.name}@${dep.version}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (result.unused.length === 0 && result.maybeUnused.length === 0) {
|
|
201
|
+
console.log('All dependencies appear to be in use.');
|
|
202
|
+
}
|
|
203
|
+
if (result.estimatedSavingsKB > 0) {
|
|
204
|
+
console.log(`\nEstimated savings: ~${result.estimatedSavingsKB} KB`);
|
|
205
|
+
}
|
|
206
|
+
console.log(`\nNote: ${result.note}`);
|
|
207
|
+
console.log();
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
138
211
|
default:
|
|
139
|
-
console.error(`Unknown command: ${command}. Use: audit, search, score, should-use`);
|
|
212
|
+
console.error(`Unknown command: ${command}. Use: audit, search, score, should-use, guard, sweep`);
|
|
140
213
|
process.exit(1);
|
|
141
214
|
}
|
|
142
215
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-install guardian and AI hallucination guard.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that npm packages exist, checks for typosquatting against popular
|
|
5
|
+
* packages, and runs a quick audit to produce an allow/warn/block decision.
|
|
6
|
+
*
|
|
7
|
+
* Zero dependencies — uses only depguard internals.
|
|
8
|
+
*/
|
|
9
|
+
import type { GuardResult, GuardOptions, VerifyResult, VerifyOptions } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Compute Levenshtein edit distance between two strings.
|
|
12
|
+
*/
|
|
13
|
+
export declare function levenshtein(a: string, b: string): number;
|
|
14
|
+
/**
|
|
15
|
+
* Find popular packages within edit distance of the given name.
|
|
16
|
+
* Returns empty array if the name is itself in the popular list.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findSimilarPackages(name: string, maxDistance?: number): string[];
|
|
19
|
+
/**
|
|
20
|
+
* Verify if an npm package exists and check for typosquatting.
|
|
21
|
+
* Lightweight — no audit, just existence + name similarity check.
|
|
22
|
+
*/
|
|
23
|
+
export declare function verify(packageName: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Pre-install guardian: verify existence, check typosquatting, run audit,
|
|
26
|
+
* and return allow/warn/block decision.
|
|
27
|
+
*/
|
|
28
|
+
export declare function guard(packageName: string, options?: GuardOptions): Promise<GuardResult>;
|
|
29
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAyDxF;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAcxD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,MAAM,EAAE,CAkB3E;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAC1B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA0BvB;AAED;;;GAGG;AACH,wBAAsB,KAAK,CACzB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAwGtB"}
|
package/dist/guard.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-install guardian and AI hallucination guard.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that npm packages exist, checks for typosquatting against popular
|
|
5
|
+
* packages, and runs a quick audit to produce an allow/warn/block decision.
|
|
6
|
+
*
|
|
7
|
+
* Zero dependencies — uses only depguard internals.
|
|
8
|
+
*/
|
|
9
|
+
import { fetchPackage } from './registry.js';
|
|
10
|
+
import { audit } from './audit.js';
|
|
11
|
+
import { score } from './scorer.js';
|
|
12
|
+
/**
|
|
13
|
+
* Top ~100 popular npm packages for typosquatting detection.
|
|
14
|
+
* Curated from npm weekly download rankings.
|
|
15
|
+
*/
|
|
16
|
+
const POPULAR_PACKAGES = [
|
|
17
|
+
// Web frameworks
|
|
18
|
+
'express', 'fastify', 'koa', 'next', 'nuxt', 'hapi',
|
|
19
|
+
// Frontend
|
|
20
|
+
'react', 'vue', 'angular', 'svelte', 'solid-js', 'preact',
|
|
21
|
+
'react-dom', 'react-router', 'react-query',
|
|
22
|
+
// Utilities
|
|
23
|
+
'lodash', 'underscore', 'ramda', 'immer', 'date-fns', 'dayjs', 'moment',
|
|
24
|
+
'uuid', 'nanoid', 'debug', 'dotenv',
|
|
25
|
+
// HTTP
|
|
26
|
+
'axios', 'node-fetch', 'got', 'superagent', 'request',
|
|
27
|
+
// CLI
|
|
28
|
+
'commander', 'yargs', 'inquirer', 'ora', 'chalk', 'minimist', 'meow',
|
|
29
|
+
// Build tools
|
|
30
|
+
'webpack', 'rollup', 'esbuild', 'vite', 'parcel', 'turbo',
|
|
31
|
+
'typescript', 'babel', 'swc', 'tsup', 'unbuild', 'tsx', 'ts-node',
|
|
32
|
+
// Testing
|
|
33
|
+
'jest', 'mocha', 'vitest', 'ava', 'tap', 'cypress', 'playwright',
|
|
34
|
+
'puppeteer', 'supertest', 'nock', 'sinon', 'chai', 'nyc', 'c8',
|
|
35
|
+
// Linting / formatting
|
|
36
|
+
'eslint', 'prettier', 'stylelint',
|
|
37
|
+
// Database
|
|
38
|
+
'mongoose', 'sequelize', 'prisma', 'knex', 'pg', 'mysql', 'mysql2',
|
|
39
|
+
'redis', 'ioredis', 'sqlite3', 'better-sqlite3', 'typeorm',
|
|
40
|
+
// Validation
|
|
41
|
+
'zod', 'joi', 'ajv', 'yup',
|
|
42
|
+
// Auth / security
|
|
43
|
+
'passport', 'jsonwebtoken', 'bcrypt', 'bcryptjs', 'helmet', 'cors',
|
|
44
|
+
// Logging
|
|
45
|
+
'winston', 'pino', 'bunyan', 'morgan',
|
|
46
|
+
// File / process
|
|
47
|
+
'rimraf', 'glob', 'globby', 'fs-extra', 'chokidar', 'sharp', 'jimp',
|
|
48
|
+
'nodemon', 'pm2', 'concurrently',
|
|
49
|
+
// Middleware
|
|
50
|
+
'body-parser', 'cookie-parser', 'compression', 'multer',
|
|
51
|
+
// Email / network
|
|
52
|
+
'nodemailer', 'socket.io', 'ws',
|
|
53
|
+
// State management
|
|
54
|
+
'redux', 'mobx', 'zustand', 'jotai', 'recoil', 'rxjs',
|
|
55
|
+
// CSS
|
|
56
|
+
'tailwindcss', 'postcss', 'sass', 'less', 'autoprefixer',
|
|
57
|
+
// GraphQL
|
|
58
|
+
'graphql', 'apollo-server',
|
|
59
|
+
// Misc
|
|
60
|
+
'cheerio', 'marked', 'highlight.js', 'storybook', 'lerna', 'nx',
|
|
61
|
+
'formik', 'swr',
|
|
62
|
+
];
|
|
63
|
+
/**
|
|
64
|
+
* Compute Levenshtein edit distance between two strings.
|
|
65
|
+
*/
|
|
66
|
+
export function levenshtein(a, b) {
|
|
67
|
+
const m = a.length;
|
|
68
|
+
const n = b.length;
|
|
69
|
+
const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
|
|
70
|
+
for (let i = 1; i <= m; i++) {
|
|
71
|
+
for (let j = 1; j <= n; j++) {
|
|
72
|
+
dp[i][j] = a[i - 1] === b[j - 1]
|
|
73
|
+
? dp[i - 1][j - 1]
|
|
74
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return dp[m][n];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Find popular packages within edit distance of the given name.
|
|
81
|
+
* Returns empty array if the name is itself in the popular list.
|
|
82
|
+
*/
|
|
83
|
+
export function findSimilarPackages(name, maxDistance = 2) {
|
|
84
|
+
const lower = name.toLowerCase();
|
|
85
|
+
// If it's an exact match to a popular package, no typosquatting
|
|
86
|
+
if (POPULAR_PACKAGES.includes(lower))
|
|
87
|
+
return [];
|
|
88
|
+
const similar = [];
|
|
89
|
+
for (const pkg of POPULAR_PACKAGES) {
|
|
90
|
+
// Skip if length difference is too large (quick filter)
|
|
91
|
+
if (Math.abs(pkg.length - lower.length) > maxDistance)
|
|
92
|
+
continue;
|
|
93
|
+
const dist = levenshtein(lower, pkg);
|
|
94
|
+
if (dist > 0 && dist <= maxDistance) {
|
|
95
|
+
similar.push({ name: pkg, distance: dist });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Sort by distance (closest first)
|
|
99
|
+
similar.sort((a, b) => a.distance - b.distance);
|
|
100
|
+
return similar.map(s => s.name);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Verify if an npm package exists and check for typosquatting.
|
|
104
|
+
* Lightweight — no audit, just existence + name similarity check.
|
|
105
|
+
*/
|
|
106
|
+
export async function verify(packageName, options = {}) {
|
|
107
|
+
const fetcher = options.fetcher ?? globalThis.fetch;
|
|
108
|
+
const similarTo = findSimilarPackages(packageName);
|
|
109
|
+
const possibleTyposquat = similarTo.length > 0;
|
|
110
|
+
const pkg = await fetchPackage(packageName, fetcher);
|
|
111
|
+
if (!pkg) {
|
|
112
|
+
return {
|
|
113
|
+
package: packageName,
|
|
114
|
+
exists: false,
|
|
115
|
+
possibleTyposquat,
|
|
116
|
+
similarTo,
|
|
117
|
+
description: null,
|
|
118
|
+
version: null,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
package: packageName,
|
|
123
|
+
exists: true,
|
|
124
|
+
possibleTyposquat,
|
|
125
|
+
similarTo,
|
|
126
|
+
description: pkg.description ?? null,
|
|
127
|
+
version: pkg['dist-tags']?.latest ?? null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Pre-install guardian: verify existence, check typosquatting, run audit,
|
|
132
|
+
* and return allow/warn/block decision.
|
|
133
|
+
*/
|
|
134
|
+
export async function guard(packageName, options = {}) {
|
|
135
|
+
const threshold = options.threshold ?? 60;
|
|
136
|
+
const targetLicense = options.targetLicense ?? 'MIT';
|
|
137
|
+
const blockMode = options.block ?? false;
|
|
138
|
+
const fetcher = options.fetcher ?? globalThis.fetch;
|
|
139
|
+
const reasons = [];
|
|
140
|
+
let decision = 'allow';
|
|
141
|
+
// Step 1: Verify existence (hallucination guard)
|
|
142
|
+
const verifyResult = await verify(packageName, { fetcher });
|
|
143
|
+
if (!verifyResult.exists) {
|
|
144
|
+
reasons.push('Package does not exist on npm — possible AI hallucination');
|
|
145
|
+
if (verifyResult.possibleTyposquat) {
|
|
146
|
+
reasons.push(`Possible typosquat of: ${verifyResult.similarTo.join(', ')}`);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
package: packageName,
|
|
150
|
+
decision: 'block',
|
|
151
|
+
exists: false,
|
|
152
|
+
possibleTyposquat: verifyResult.possibleTyposquat,
|
|
153
|
+
similarTo: verifyResult.similarTo,
|
|
154
|
+
score: null,
|
|
155
|
+
reasons,
|
|
156
|
+
auditSummary: null,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Step 2: Typosquatting warning (package exists but name is suspiciously similar)
|
|
160
|
+
if (verifyResult.possibleTyposquat) {
|
|
161
|
+
reasons.push(`Possible typosquat of: ${verifyResult.similarTo.join(', ')}`);
|
|
162
|
+
decision = 'warn';
|
|
163
|
+
}
|
|
164
|
+
// Step 3: Quick audit + score
|
|
165
|
+
let scoreResult = null;
|
|
166
|
+
let auditSummary = null;
|
|
167
|
+
try {
|
|
168
|
+
const [auditReport, scoreReport] = await Promise.all([
|
|
169
|
+
audit(packageName, targetLicense, fetcher),
|
|
170
|
+
score(packageName, { targetLicense, fetcher }),
|
|
171
|
+
]);
|
|
172
|
+
scoreResult = scoreReport.total;
|
|
173
|
+
auditSummary = {
|
|
174
|
+
vulnerabilities: auditReport.vulnerabilities.total,
|
|
175
|
+
critical: auditReport.vulnerabilities.critical,
|
|
176
|
+
high: auditReport.vulnerabilities.high,
|
|
177
|
+
deprecated: auditReport.deprecated,
|
|
178
|
+
hasInstallScripts: auditReport.hasInstallScripts,
|
|
179
|
+
scriptAnalysisSuspicious: auditReport.scriptAnalysis.suspicious,
|
|
180
|
+
license: auditReport.license,
|
|
181
|
+
};
|
|
182
|
+
// Decision logic based on audit results
|
|
183
|
+
if (auditReport.vulnerabilities.critical > 0) {
|
|
184
|
+
reasons.push(`${auditReport.vulnerabilities.critical} critical vulnerabilities`);
|
|
185
|
+
decision = 'warn';
|
|
186
|
+
}
|
|
187
|
+
if (auditReport.vulnerabilities.high > 0) {
|
|
188
|
+
reasons.push(`${auditReport.vulnerabilities.high} high severity vulnerabilities`);
|
|
189
|
+
decision = 'warn';
|
|
190
|
+
}
|
|
191
|
+
if (auditReport.deprecated) {
|
|
192
|
+
reasons.push('Package is deprecated');
|
|
193
|
+
decision = 'warn';
|
|
194
|
+
}
|
|
195
|
+
if (auditReport.scriptAnalysis.suspicious) {
|
|
196
|
+
reasons.push('Suspicious install scripts detected');
|
|
197
|
+
decision = 'warn';
|
|
198
|
+
}
|
|
199
|
+
// Score-based decision (can escalate to block)
|
|
200
|
+
if (scoreResult < threshold - 20) {
|
|
201
|
+
reasons.push(`Score ${scoreResult}/100 is critically below threshold ${threshold}`);
|
|
202
|
+
decision = 'block';
|
|
203
|
+
}
|
|
204
|
+
else if (scoreResult < threshold) {
|
|
205
|
+
reasons.push(`Score ${scoreResult}/100 is below threshold ${threshold}`);
|
|
206
|
+
if (decision === 'allow')
|
|
207
|
+
decision = 'warn';
|
|
208
|
+
}
|
|
209
|
+
else if (reasons.length === 0) {
|
|
210
|
+
reasons.push(`Score ${scoreResult}/100 — safe to install`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
reasons.push('Could not complete audit — proceeding with caution');
|
|
215
|
+
if (decision === 'allow')
|
|
216
|
+
decision = 'warn';
|
|
217
|
+
}
|
|
218
|
+
// Escalate warn to block if --block mode is active
|
|
219
|
+
if (blockMode && decision === 'warn') {
|
|
220
|
+
decision = 'block';
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
package: packageName,
|
|
224
|
+
decision,
|
|
225
|
+
exists: true,
|
|
226
|
+
possibleTyposquat: verifyResult.possibleTyposquat,
|
|
227
|
+
similarTo: verifyResult.similarTo,
|
|
228
|
+
score: scoreResult,
|
|
229
|
+
reasons,
|
|
230
|
+
auditSummary,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=guard.js.map
|