npx-ray 1.0.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/LICENSE +201 -0
- package/README.md +365 -0
- package/data/popular-packages.json +619 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +261 -0
- package/dist/cli.js.map +1 -0
- package/dist/diff.d.ts +21 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +301 -0
- package/dist/diff.js.map +1 -0
- package/dist/extract.d.ts +18 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +80 -0
- package/dist/extract.js.map +1 -0
- package/dist/github.d.ts +38 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +132 -0
- package/dist/github.js.map +1 -0
- package/dist/mcp.d.ts +19 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +219 -0
- package/dist/mcp.js.map +1 -0
- package/dist/registry.d.ts +19 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +229 -0
- package/dist/registry.js.map +1 -0
- package/dist/reporter.d.ts +23 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +208 -0
- package/dist/reporter.js.map +1 -0
- package/dist/scanners/binaries.d.ts +12 -0
- package/dist/scanners/binaries.d.ts.map +1 -0
- package/dist/scanners/binaries.js +80 -0
- package/dist/scanners/binaries.js.map +1 -0
- package/dist/scanners/dependencies.d.ts +14 -0
- package/dist/scanners/dependencies.d.ts.map +1 -0
- package/dist/scanners/dependencies.js +114 -0
- package/dist/scanners/dependencies.js.map +1 -0
- package/dist/scanners/hooks.d.ts +12 -0
- package/dist/scanners/hooks.d.ts.map +1 -0
- package/dist/scanners/hooks.js +126 -0
- package/dist/scanners/hooks.js.map +1 -0
- package/dist/scanners/ioc.d.ts +17 -0
- package/dist/scanners/ioc.d.ts.map +1 -0
- package/dist/scanners/ioc.js +414 -0
- package/dist/scanners/ioc.js.map +1 -0
- package/dist/scanners/obfuscation.d.ts +12 -0
- package/dist/scanners/obfuscation.d.ts.map +1 -0
- package/dist/scanners/obfuscation.js +227 -0
- package/dist/scanners/obfuscation.js.map +1 -0
- package/dist/scanners/secrets.d.ts +12 -0
- package/dist/scanners/secrets.d.ts.map +1 -0
- package/dist/scanners/secrets.js +173 -0
- package/dist/scanners/secrets.js.map +1 -0
- package/dist/scanners/static.d.ts +13 -0
- package/dist/scanners/static.d.ts.map +1 -0
- package/dist/scanners/static.js +138 -0
- package/dist/scanners/static.js.map +1 -0
- package/dist/scanners/typosquatting.d.ts +13 -0
- package/dist/scanners/typosquatting.d.ts.map +1 -0
- package/dist/scanners/typosquatting.js +102 -0
- package/dist/scanners/typosquatting.js.map +1 -0
- package/dist/scorer.d.ts +28 -0
- package/dist/scorer.d.ts.map +1 -0
- package/dist/scorer.js +139 -0
- package/dist/scorer.js.map +1 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
package/dist/registry.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm registry API client for npx-ray.
|
|
3
|
+
*
|
|
4
|
+
* Fetches package metadata from the npm registry, supporting:
|
|
5
|
+
* - Unscoped packages: `chalk`
|
|
6
|
+
* - Scoped packages: `@anthropic-ai/sdk`
|
|
7
|
+
* - Pinned versions: `chalk@5.4.0`
|
|
8
|
+
* - Local tarballs: `./my-package-1.0.0.tgz`
|
|
9
|
+
*/
|
|
10
|
+
import { createReadStream } from 'node:fs';
|
|
11
|
+
import { resolve } from 'node:path';
|
|
12
|
+
import { createGunzip } from 'node:zlib';
|
|
13
|
+
import { pipeline } from 'node:stream/promises';
|
|
14
|
+
const NPM_REGISTRY = 'https://registry.npmjs.org';
|
|
15
|
+
/**
|
|
16
|
+
* Parse a target string into a package name and optional version.
|
|
17
|
+
*
|
|
18
|
+
* Handles scoped packages correctly:
|
|
19
|
+
* `@scope/name` -> { name: '@scope/name', version: undefined }
|
|
20
|
+
* `@scope/name@1.2.3` -> { name: '@scope/name', version: '1.2.3' }
|
|
21
|
+
* `lodash` -> { name: 'lodash', version: undefined }
|
|
22
|
+
* `lodash@4.17.21` -> { name: 'lodash', version: '4.17.21' }
|
|
23
|
+
*/
|
|
24
|
+
function parseTarget(target) {
|
|
25
|
+
// Local tarball detection
|
|
26
|
+
if (target.startsWith('./') ||
|
|
27
|
+
target.startsWith('/') ||
|
|
28
|
+
target.startsWith('../') ||
|
|
29
|
+
target.endsWith('.tgz') ||
|
|
30
|
+
target.endsWith('.tar.gz')) {
|
|
31
|
+
return { name: target, isLocal: true };
|
|
32
|
+
}
|
|
33
|
+
// Scoped package: @scope/name or @scope/name@version
|
|
34
|
+
if (target.startsWith('@')) {
|
|
35
|
+
const lastAt = target.lastIndexOf('@');
|
|
36
|
+
// If the only '@' is at position 0, there's no version specifier
|
|
37
|
+
if (lastAt === 0) {
|
|
38
|
+
return { name: target, version: undefined, isLocal: false };
|
|
39
|
+
}
|
|
40
|
+
// '@scope/name@version' — lastAt points to the version separator
|
|
41
|
+
const name = target.slice(0, lastAt);
|
|
42
|
+
const version = target.slice(lastAt + 1);
|
|
43
|
+
return { name, version, isLocal: false };
|
|
44
|
+
}
|
|
45
|
+
// Unscoped package: name or name@version
|
|
46
|
+
const atIndex = target.indexOf('@');
|
|
47
|
+
if (atIndex === -1) {
|
|
48
|
+
return { name: target, version: undefined, isLocal: false };
|
|
49
|
+
}
|
|
50
|
+
const name = target.slice(0, atIndex);
|
|
51
|
+
const version = target.slice(atIndex + 1);
|
|
52
|
+
return { name, version, isLocal: false };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract a package.json from a local .tgz tarball and build minimal metadata.
|
|
56
|
+
*
|
|
57
|
+
* npm tarballs contain files under a `package/` prefix, so the package.json
|
|
58
|
+
* is at `package/package.json`.
|
|
59
|
+
*/
|
|
60
|
+
async function metadataFromLocalTarball(filePath) {
|
|
61
|
+
const absPath = resolve(filePath);
|
|
62
|
+
const chunks = [];
|
|
63
|
+
let foundPackageJson = false;
|
|
64
|
+
// We'll manually parse the tar stream to find package/package.json.
|
|
65
|
+
// tar v7 uses a stream-based API. We read the gzipped tarball and look for
|
|
66
|
+
// the package.json entry.
|
|
67
|
+
const { Parser } = await import('tar');
|
|
68
|
+
const parser = new Parser({
|
|
69
|
+
filter: (path) => {
|
|
70
|
+
// npm tarballs have package/package.json
|
|
71
|
+
return path === 'package/package.json' || path === './package/package.json';
|
|
72
|
+
},
|
|
73
|
+
onReadEntry: (entry) => {
|
|
74
|
+
foundPackageJson = true;
|
|
75
|
+
entry.on('data', (chunk) => {
|
|
76
|
+
chunks.push(chunk);
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
const gunzip = createGunzip();
|
|
81
|
+
const fileStream = createReadStream(absPath);
|
|
82
|
+
await pipeline(fileStream, gunzip, parser);
|
|
83
|
+
if (!foundPackageJson || chunks.length === 0) {
|
|
84
|
+
throw new Error(`No package.json found in tarball: ${filePath}`);
|
|
85
|
+
}
|
|
86
|
+
const pkgJson = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
87
|
+
// Extract repository URL from package.json repository field
|
|
88
|
+
let repositoryUrl = '';
|
|
89
|
+
if (typeof pkgJson.repository === 'string') {
|
|
90
|
+
repositoryUrl = pkgJson.repository;
|
|
91
|
+
}
|
|
92
|
+
else if (pkgJson.repository?.url) {
|
|
93
|
+
repositoryUrl = pkgJson.repository.url
|
|
94
|
+
.replace(/^git\+/, '')
|
|
95
|
+
.replace(/\.git$/, '');
|
|
96
|
+
}
|
|
97
|
+
// Extract license
|
|
98
|
+
let license = '';
|
|
99
|
+
if (typeof pkgJson.license === 'string') {
|
|
100
|
+
license = pkgJson.license;
|
|
101
|
+
}
|
|
102
|
+
else if (pkgJson.license?.type) {
|
|
103
|
+
license = pkgJson.license.type;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
name: pkgJson.name || 'unknown',
|
|
107
|
+
version: pkgJson.version || '0.0.0',
|
|
108
|
+
description: pkgJson.description || '',
|
|
109
|
+
license,
|
|
110
|
+
publisher: pkgJson.author
|
|
111
|
+
? typeof pkgJson.author === 'string'
|
|
112
|
+
? pkgJson.author
|
|
113
|
+
: pkgJson.author.name || ''
|
|
114
|
+
: '',
|
|
115
|
+
publishedAt: '',
|
|
116
|
+
tarballUrl: `file://${absPath}`,
|
|
117
|
+
repositoryUrl,
|
|
118
|
+
homepage: pkgJson.homepage || '',
|
|
119
|
+
fileCount: 0,
|
|
120
|
+
unpackedSize: 0,
|
|
121
|
+
dependencies: pkgJson.dependencies || {},
|
|
122
|
+
optionalDependencies: pkgJson.optionalDependencies || {},
|
|
123
|
+
scripts: pkgJson.scripts || {},
|
|
124
|
+
maintainers: pkgJson.maintainers || [],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Fetch full package metadata from the npm registry.
|
|
129
|
+
*
|
|
130
|
+
* @param target - Package specifier: `name`, `name@version`, or a local tarball path.
|
|
131
|
+
* @returns Resolved package metadata.
|
|
132
|
+
* @throws If the package is not found or the registry request fails.
|
|
133
|
+
*/
|
|
134
|
+
export async function fetchPackageMetadata(target) {
|
|
135
|
+
const { name, version, isLocal } = parseTarget(target);
|
|
136
|
+
// Handle local tarballs
|
|
137
|
+
if (isLocal) {
|
|
138
|
+
return metadataFromLocalTarball(name);
|
|
139
|
+
}
|
|
140
|
+
// Fetch the full packument from the registry.
|
|
141
|
+
// Scoped packages need the scope URL-encoded (@ -> %40, / -> %2f),
|
|
142
|
+
// but npm registry also accepts the raw form for scoped packages.
|
|
143
|
+
const url = `${NPM_REGISTRY}/${encodeURIComponent(name).replace('%40', '@')}`;
|
|
144
|
+
const response = await fetch(url, {
|
|
145
|
+
headers: {
|
|
146
|
+
Accept: 'application/json',
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
if (response.status === 404) {
|
|
151
|
+
throw new Error(`Package not found: ${name}`);
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`npm registry error: ${response.status} ${response.statusText} for ${name}`);
|
|
154
|
+
}
|
|
155
|
+
const packument = (await response.json());
|
|
156
|
+
// Resolve the version
|
|
157
|
+
const distTags = packument['dist-tags'];
|
|
158
|
+
const resolvedVersion = version || distTags?.latest;
|
|
159
|
+
if (!resolvedVersion) {
|
|
160
|
+
throw new Error(`Cannot determine version for ${name}: no dist-tags.latest found`);
|
|
161
|
+
}
|
|
162
|
+
const versions = packument.versions;
|
|
163
|
+
if (!versions) {
|
|
164
|
+
throw new Error(`No versions found in packument for ${name}`);
|
|
165
|
+
}
|
|
166
|
+
const manifest = versions[resolvedVersion];
|
|
167
|
+
if (!manifest) {
|
|
168
|
+
const available = Object.keys(versions).slice(-5).join(', ');
|
|
169
|
+
throw new Error(`Version ${resolvedVersion} not found for ${name}. Recent versions: ${available}`);
|
|
170
|
+
}
|
|
171
|
+
// Extract dist info
|
|
172
|
+
const dist = manifest.dist;
|
|
173
|
+
const tarballUrl = dist?.tarball || '';
|
|
174
|
+
const fileCount = dist?.fileCount || 0;
|
|
175
|
+
const unpackedSize = dist?.unpackedSize || 0;
|
|
176
|
+
// Extract repository URL
|
|
177
|
+
let repositoryUrl = '';
|
|
178
|
+
const repo = manifest.repository;
|
|
179
|
+
if (typeof repo === 'string') {
|
|
180
|
+
repositoryUrl = repo;
|
|
181
|
+
}
|
|
182
|
+
else if (repo && typeof repo === 'object') {
|
|
183
|
+
const repoObj = repo;
|
|
184
|
+
const rawUrl = repoObj.url || '';
|
|
185
|
+
repositoryUrl = rawUrl
|
|
186
|
+
.replace(/^git\+/, '')
|
|
187
|
+
.replace(/\.git$/, '');
|
|
188
|
+
}
|
|
189
|
+
// Extract license
|
|
190
|
+
let license = '';
|
|
191
|
+
const lic = manifest.license;
|
|
192
|
+
if (typeof lic === 'string') {
|
|
193
|
+
license = lic;
|
|
194
|
+
}
|
|
195
|
+
else if (lic && typeof lic === 'object') {
|
|
196
|
+
license = lic.type || '';
|
|
197
|
+
}
|
|
198
|
+
// Extract publisher info
|
|
199
|
+
let publisher = '';
|
|
200
|
+
const npmUser = manifest._npmUser;
|
|
201
|
+
if (npmUser?.name) {
|
|
202
|
+
publisher = npmUser.name;
|
|
203
|
+
}
|
|
204
|
+
// Extract publish date from the time field
|
|
205
|
+
const timeMap = packument.time;
|
|
206
|
+
const publishedAt = timeMap?.[resolvedVersion] || '';
|
|
207
|
+
// Extract maintainers — fall back to packument-level maintainers
|
|
208
|
+
const maintainers = manifest.maintainers ||
|
|
209
|
+
packument.maintainers ||
|
|
210
|
+
[];
|
|
211
|
+
return {
|
|
212
|
+
name: manifest.name || name,
|
|
213
|
+
version: manifest.version || resolvedVersion,
|
|
214
|
+
description: manifest.description || '',
|
|
215
|
+
license,
|
|
216
|
+
publisher,
|
|
217
|
+
publishedAt,
|
|
218
|
+
tarballUrl,
|
|
219
|
+
repositoryUrl,
|
|
220
|
+
homepage: manifest.homepage || '',
|
|
221
|
+
fileCount,
|
|
222
|
+
unpackedSize,
|
|
223
|
+
dependencies: manifest.dependencies || {},
|
|
224
|
+
optionalDependencies: manifest.optionalDependencies || {},
|
|
225
|
+
scripts: manifest.scripts || {},
|
|
226
|
+
maintainers,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting for npx-ray scan results.
|
|
3
|
+
*
|
|
4
|
+
* Provides both human-readable (chalk-colored) and machine-readable (JSON)
|
|
5
|
+
* output formats for scan reports.
|
|
6
|
+
*/
|
|
7
|
+
import type { ScanReport } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generate a human-readable, chalk-colored report.
|
|
10
|
+
*
|
|
11
|
+
* @param report - The complete scan report.
|
|
12
|
+
* @param verbose - Whether to show individual findings.
|
|
13
|
+
* @returns Formatted string ready for console output.
|
|
14
|
+
*/
|
|
15
|
+
export declare function reportPretty(report: ScanReport, verbose: boolean): string;
|
|
16
|
+
/**
|
|
17
|
+
* Generate a machine-readable JSON report.
|
|
18
|
+
*
|
|
19
|
+
* @param report - The complete scan report.
|
|
20
|
+
* @returns Pretty-printed JSON string.
|
|
21
|
+
*/
|
|
22
|
+
export declare function reportJson(report: ScanReport): string;
|
|
23
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAA0B,MAAM,YAAY,CAAC;AAqGrE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAmGzE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAErD"}
|
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting for npx-ray scan results.
|
|
3
|
+
*
|
|
4
|
+
* Provides both human-readable (chalk-colored) and machine-readable (JSON)
|
|
5
|
+
* output formats for scan reports.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
/** Format bytes into a human-readable string. */
|
|
9
|
+
function formatBytes(bytes) {
|
|
10
|
+
if (bytes === 0)
|
|
11
|
+
return '0 B';
|
|
12
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
13
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
14
|
+
const value = bytes / Math.pow(1024, i);
|
|
15
|
+
return `${value.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
|
|
16
|
+
}
|
|
17
|
+
/** Format milliseconds into a human-readable duration. */
|
|
18
|
+
function formatDuration(ms) {
|
|
19
|
+
if (ms < 1000)
|
|
20
|
+
return `${ms}ms`;
|
|
21
|
+
const seconds = (ms / 1000).toFixed(1);
|
|
22
|
+
return `${seconds}s`;
|
|
23
|
+
}
|
|
24
|
+
/** Get the status icon for a scanner result. */
|
|
25
|
+
function statusIcon(result) {
|
|
26
|
+
const hasCritical = result.findings.some(f => f.severity === 'critical');
|
|
27
|
+
const hasWarning = result.findings.some(f => f.severity === 'warning');
|
|
28
|
+
if (hasCritical)
|
|
29
|
+
return chalk.red('\u274c');
|
|
30
|
+
if (hasWarning)
|
|
31
|
+
return chalk.yellow('\u26a0\ufe0f');
|
|
32
|
+
return chalk.green('\u2705');
|
|
33
|
+
}
|
|
34
|
+
/** Get the colored label for a severity level. */
|
|
35
|
+
function severityLabel(severity) {
|
|
36
|
+
switch (severity) {
|
|
37
|
+
case 'critical':
|
|
38
|
+
return chalk.red.bold('CRITICAL');
|
|
39
|
+
case 'warning':
|
|
40
|
+
return chalk.yellow('WARNING');
|
|
41
|
+
case 'info':
|
|
42
|
+
return chalk.blue('INFO');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Color a score based on its grade. */
|
|
46
|
+
function colorScore(score, grade) {
|
|
47
|
+
const label = `${score}/100 (${grade})`;
|
|
48
|
+
switch (grade) {
|
|
49
|
+
case 'A':
|
|
50
|
+
case 'B':
|
|
51
|
+
return chalk.green.bold(label);
|
|
52
|
+
case 'C':
|
|
53
|
+
return chalk.yellow.bold(label);
|
|
54
|
+
case 'D':
|
|
55
|
+
case 'F':
|
|
56
|
+
return chalk.red.bold(label);
|
|
57
|
+
default:
|
|
58
|
+
return label;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Color a verdict string based on its prefix. */
|
|
62
|
+
function colorVerdict(verdict) {
|
|
63
|
+
if (verdict.startsWith('CLEAN'))
|
|
64
|
+
return chalk.green.bold(verdict);
|
|
65
|
+
if (verdict.startsWith('CAUTION'))
|
|
66
|
+
return chalk.yellow.bold(verdict);
|
|
67
|
+
if (verdict.startsWith('DANGER'))
|
|
68
|
+
return chalk.red.bold(verdict);
|
|
69
|
+
return chalk.bold(verdict);
|
|
70
|
+
}
|
|
71
|
+
/** Capitalize the first letter of a scanner name for display. */
|
|
72
|
+
function scannerDisplayName(name) {
|
|
73
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Render a finding as a single line for verbose output.
|
|
77
|
+
*/
|
|
78
|
+
function renderFinding(finding) {
|
|
79
|
+
const location = finding.file
|
|
80
|
+
? finding.line
|
|
81
|
+
? chalk.dim(` ${finding.file}:${finding.line}`)
|
|
82
|
+
: chalk.dim(` ${finding.file}`)
|
|
83
|
+
: '';
|
|
84
|
+
return ` ${severityLabel(finding.severity)} ${finding.message}${location}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Render a scanner section in the pretty report.
|
|
88
|
+
*/
|
|
89
|
+
function renderScannerSection(result, verbose) {
|
|
90
|
+
const lines = [];
|
|
91
|
+
const icon = statusIcon(result);
|
|
92
|
+
const name = scannerDisplayName(result.name);
|
|
93
|
+
lines.push(` ${icon} ${chalk.bold(name)}: ${result.summary}`);
|
|
94
|
+
if (verbose && result.findings.length > 0) {
|
|
95
|
+
for (const finding of result.findings) {
|
|
96
|
+
lines.push(renderFinding(finding));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return lines.join('\n');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Generate a human-readable, chalk-colored report.
|
|
103
|
+
*
|
|
104
|
+
* @param report - The complete scan report.
|
|
105
|
+
* @param verbose - Whether to show individual findings.
|
|
106
|
+
* @returns Formatted string ready for console output.
|
|
107
|
+
*/
|
|
108
|
+
export function reportPretty(report, verbose) {
|
|
109
|
+
const lines = [];
|
|
110
|
+
// Header
|
|
111
|
+
lines.push('');
|
|
112
|
+
lines.push(chalk.cyan.bold('npx-ray v1.0.0 \u2014 X-ray vision for npm packages'));
|
|
113
|
+
lines.push(chalk.dim('\u2500'.repeat(55)));
|
|
114
|
+
// Package info block
|
|
115
|
+
const pkg = report.package;
|
|
116
|
+
lines.push('');
|
|
117
|
+
lines.push(chalk.bold('Package: ') + `${pkg.name}@${pkg.version}`);
|
|
118
|
+
lines.push(chalk.bold('Publisher: ') + (pkg.publisher || chalk.dim('unknown')));
|
|
119
|
+
lines.push(chalk.bold('Published: ') + (pkg.publishedAt || chalk.dim('unknown')));
|
|
120
|
+
lines.push(chalk.bold('License: ') + (pkg.license || chalk.dim('none')));
|
|
121
|
+
lines.push(chalk.bold('Files: ') + pkg.fileCount.toString());
|
|
122
|
+
lines.push(chalk.bold('Size: ') + formatBytes(pkg.unpackedSize));
|
|
123
|
+
// Risk score
|
|
124
|
+
lines.push('');
|
|
125
|
+
lines.push(chalk.dim('\u2500'.repeat(55)));
|
|
126
|
+
lines.push(` Risk Score: ${colorScore(report.score, report.grade)}`);
|
|
127
|
+
lines.push(chalk.dim('\u2500'.repeat(55)));
|
|
128
|
+
// Scanner sections
|
|
129
|
+
lines.push('');
|
|
130
|
+
lines.push(chalk.bold.underline('Scan Results'));
|
|
131
|
+
lines.push('');
|
|
132
|
+
for (const result of report.scanners) {
|
|
133
|
+
lines.push(renderScannerSection(result, verbose));
|
|
134
|
+
}
|
|
135
|
+
// GitHub section
|
|
136
|
+
if (report.github) {
|
|
137
|
+
lines.push('');
|
|
138
|
+
lines.push(chalk.bold.underline('GitHub'));
|
|
139
|
+
lines.push('');
|
|
140
|
+
const gh = report.github;
|
|
141
|
+
if (!gh.found) {
|
|
142
|
+
lines.push(` ${chalk.yellow('\u26a0\ufe0f')} No GitHub repository found`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
const repoIcon = gh.archived ? chalk.yellow('\u26a0\ufe0f') : chalk.green('\u2705');
|
|
146
|
+
lines.push(` ${repoIcon} ${chalk.bold('Repository:')} ${gh.fullName}`);
|
|
147
|
+
lines.push(` Stars: ${gh.stars} | Forks: ${gh.forks} | Open Issues: ${gh.openIssues}`);
|
|
148
|
+
lines.push(` Created: ${gh.createdAt} | Last Push: ${gh.lastPush}`);
|
|
149
|
+
if (gh.archived) {
|
|
150
|
+
lines.push(` ${chalk.yellow('Repository is archived')}`);
|
|
151
|
+
}
|
|
152
|
+
if (!gh.publisherMatchesOwner) {
|
|
153
|
+
lines.push(` ${chalk.yellow('npm publisher does not match GitHub owner')}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Diff section
|
|
158
|
+
if (report.diff) {
|
|
159
|
+
lines.push('');
|
|
160
|
+
lines.push(chalk.bold.underline('Source Diff'));
|
|
161
|
+
lines.push('');
|
|
162
|
+
const diff = report.diff;
|
|
163
|
+
if (!diff.performed) {
|
|
164
|
+
lines.push(` ${chalk.dim('\u2014')} Diff not performed${diff.error ? `: ${diff.error}` : ''}`);
|
|
165
|
+
}
|
|
166
|
+
else if (diff.unexpectedFiles.length === 0 && diff.modifiedFiles.length === 0) {
|
|
167
|
+
lines.push(` ${chalk.green('\u2705')} Source matches published package`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
if (diff.unexpectedFiles.length > 0) {
|
|
171
|
+
lines.push(` ${chalk.red('\u274c')} ${diff.unexpectedFiles.length} unexpected file(s) in npm package:`);
|
|
172
|
+
if (verbose) {
|
|
173
|
+
for (const file of diff.unexpectedFiles) {
|
|
174
|
+
lines.push(` ${chalk.red('\u2022')} ${file}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (diff.modifiedFiles.length > 0) {
|
|
179
|
+
lines.push(` ${chalk.yellow('\u26a0\ufe0f')} ${diff.modifiedFiles.length} modified file(s):`);
|
|
180
|
+
if (verbose) {
|
|
181
|
+
for (const file of diff.modifiedFiles) {
|
|
182
|
+
lines.push(` ${chalk.yellow('\u2022')} ${file}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Final verdict
|
|
189
|
+
lines.push('');
|
|
190
|
+
lines.push(chalk.dim('\u2500'.repeat(55)));
|
|
191
|
+
lines.push(` Verdict: ${colorVerdict(report.verdict)}`);
|
|
192
|
+
lines.push(chalk.dim('\u2500'.repeat(55)));
|
|
193
|
+
// Duration
|
|
194
|
+
lines.push('');
|
|
195
|
+
lines.push(chalk.dim(`Scan completed in ${formatDuration(report.duration)}`));
|
|
196
|
+
lines.push('');
|
|
197
|
+
return lines.join('\n');
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Generate a machine-readable JSON report.
|
|
201
|
+
*
|
|
202
|
+
* @param report - The complete scan report.
|
|
203
|
+
* @returns Pretty-printed JSON string.
|
|
204
|
+
*/
|
|
205
|
+
export function reportJson(report) {
|
|
206
|
+
return JSON.stringify(report, null, 2);
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary file scanner.
|
|
3
|
+
*
|
|
4
|
+
* Detects binary and native addon files that cannot be source-reviewed:
|
|
5
|
+
* .node, .so, .dll, .dylib, .exe, .bin, .wasm
|
|
6
|
+
*/
|
|
7
|
+
import type { ScannerResult } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Scan for binary and native addon files.
|
|
10
|
+
*/
|
|
11
|
+
export declare function scanBinaries(pkgDir: string): Promise<ScannerResult>;
|
|
12
|
+
//# sourceMappingURL=binaries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binaries.d.ts","sourceRoot":"","sources":["../../src/scanners/binaries.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,aAAa,CAAC;AAe1D;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA4DzE"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary file scanner.
|
|
3
|
+
*
|
|
4
|
+
* Detects binary and native addon files that cannot be source-reviewed:
|
|
5
|
+
* .node, .so, .dll, .dylib, .exe, .bin, .wasm
|
|
6
|
+
*/
|
|
7
|
+
import { promises as fs } from 'node:fs';
|
|
8
|
+
import { join, relative, extname } from 'node:path';
|
|
9
|
+
const SCANNER_NAME = 'binaries';
|
|
10
|
+
/** Binary/native addon extensions to flag. */
|
|
11
|
+
const BINARY_EXTENSIONS = new Set([
|
|
12
|
+
'.node',
|
|
13
|
+
'.so',
|
|
14
|
+
'.dll',
|
|
15
|
+
'.dylib',
|
|
16
|
+
'.exe',
|
|
17
|
+
'.bin',
|
|
18
|
+
'.wasm',
|
|
19
|
+
]);
|
|
20
|
+
/**
|
|
21
|
+
* Scan for binary and native addon files.
|
|
22
|
+
*/
|
|
23
|
+
export async function scanBinaries(pkgDir) {
|
|
24
|
+
const findings = [];
|
|
25
|
+
let entries;
|
|
26
|
+
try {
|
|
27
|
+
entries = await fs.readdir(pkgDir, { withFileTypes: true, recursive: true });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return {
|
|
31
|
+
name: SCANNER_NAME,
|
|
32
|
+
passed: true,
|
|
33
|
+
findings: [],
|
|
34
|
+
summary: 'Unable to read package directory',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
if (!entry.isFile())
|
|
39
|
+
continue;
|
|
40
|
+
const ext = extname(entry.name).toLowerCase();
|
|
41
|
+
if (!BINARY_EXTENSIONS.has(ext))
|
|
42
|
+
continue;
|
|
43
|
+
const parentPath = entry.parentPath ?? entry.path ?? pkgDir;
|
|
44
|
+
const fullPath = join(parentPath, entry.name);
|
|
45
|
+
const relPath = relative(pkgDir, fullPath);
|
|
46
|
+
// Skip node_modules
|
|
47
|
+
if (relPath.includes('node_modules'))
|
|
48
|
+
continue;
|
|
49
|
+
findings.push({
|
|
50
|
+
scanner: SCANNER_NAME,
|
|
51
|
+
severity: 'warning',
|
|
52
|
+
message: `Binary file found: ${ext} (cannot be source-reviewed)`,
|
|
53
|
+
file: relPath,
|
|
54
|
+
evidence: entry.name,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const passed = findings.length === 0;
|
|
58
|
+
let summary;
|
|
59
|
+
if (findings.length === 0) {
|
|
60
|
+
summary = 'No binary files found';
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const extCounts = new Map();
|
|
64
|
+
for (const f of findings) {
|
|
65
|
+
const ext = extname(f.file || '').toLowerCase();
|
|
66
|
+
extCounts.set(ext, (extCounts.get(ext) || 0) + 1);
|
|
67
|
+
}
|
|
68
|
+
const extSummary = [...extCounts.entries()]
|
|
69
|
+
.map(([ext, count]) => `${count} ${ext}`)
|
|
70
|
+
.join(', ');
|
|
71
|
+
summary = `${findings.length} binary file(s): ${extSummary}`;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
name: SCANNER_NAME,
|
|
75
|
+
passed,
|
|
76
|
+
findings,
|
|
77
|
+
summary,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=binaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binaries.js","sourceRoot":"","sources":["../../src/scanners/binaries.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpD,MAAM,YAAY,GAAG,UAAU,CAAC;AAEhC,8CAA8C;AAC9C,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,OAAO;IACP,KAAK;IACL,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,OAAO;CACR,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc;IAC/C,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,IAAI,OAAmC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAA0C,CAAC;IACxH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,kCAAkC;SAC5C,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,SAAS;QAE9B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9C,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAE1C,MAAM,UAAU,GAAI,KAAa,CAAC,UAAU,IAAK,KAAa,CAAC,IAAI,IAAI,MAAM,CAAC;QAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE3C,oBAAoB;QACpB,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;YAAE,SAAS;QAE/C,QAAQ,CAAC,IAAI,CAAC;YACZ,OAAO,EAAE,YAAY;YACrB,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,sBAAsB,GAAG,8BAA8B;YAChE,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,KAAK,CAAC,IAAI;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;IAErC,IAAI,OAAe,CAAC;IACpB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,uBAAuB,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC5C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YAChD,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,UAAU,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,GAAG,EAAE,CAAC;aACxC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,oBAAoB,UAAU,EAAE,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,MAAM;QACN,QAAQ;QACR,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency analysis scanner.
|
|
3
|
+
*
|
|
4
|
+
* Analyzes package.json dependencies for:
|
|
5
|
+
* - Dependency count (bloat detection)
|
|
6
|
+
* - Git URL dependencies (not pinned to registry)
|
|
7
|
+
* - Wildcard/unpinned version ranges
|
|
8
|
+
*/
|
|
9
|
+
import type { ScannerResult } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Scan package.json dependencies.
|
|
12
|
+
*/
|
|
13
|
+
export declare function scanDependencies(pkgDir: string): Promise<ScannerResult>;
|
|
14
|
+
//# sourceMappingURL=dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/scanners/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,aAAa,CAAC;AAkB1D;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA4F7E"}
|