np-audit 1.0.0 → 1.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.
Files changed (2) hide show
  1. package/package.json +3 -3
  2. package/src/scanner.js +22 -9
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "np-audit",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Static obfuscation detector for npm lifecycle scripts — supply chain attack prevention",
5
5
  "bin": {
6
- "npa": "./bin/npa.js",
7
- "np-audit": "./bin/npa.js"
6
+ "npa": "bin/npa.js",
7
+ "np-audit": "bin/npa.js"
8
8
  },
9
9
  "main": "./src/cli.js",
10
10
  "files": [
package/src/scanner.js CHANGED
@@ -242,6 +242,17 @@ function verdictFromScore(score, config) {
242
242
  return 'OK';
243
243
  }
244
244
 
245
+ /**
246
+ * Extract the first clean X.Y.Z (or X.Y or X) semver from a range string.
247
+ * Returns null if no clean version can be found.
248
+ * Examples: "^5.1.0" → "5.1.0", "4.22.1 || ^5" → "4.22.1", "2" → "2", "*" → null
249
+ */
250
+ function extractSemver(range) {
251
+ const match = range.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?|\d+\.\d+|\d+)(?!\S*-)/);
252
+ if (match) return match[1];
253
+ return null;
254
+ }
255
+
245
256
  /**
246
257
  * Resolve a single package's dependency tree via the npm registry.
247
258
  * @param {string} packageSpec e.g. "express" or "express@4.18.0"
@@ -275,17 +286,19 @@ async function resolveSinglePackage(packageSpec, config) {
275
286
  for (const [depName, range] of Object.entries(deps || {})) {
276
287
  if (seen.has(depName)) continue;
277
288
  seen.add(depName);
278
- // We don't resolve ranges here just list direct deps; full tree would need more registry calls
289
+ // Extract the first clean semver from the range (e.g. "4.22.1 || ^5" "4.22.1", "^5.1.0" "5.1.0")
290
+ const exactVersion = extractSemver(range);
291
+ if (!exactVersion) continue; // skip unresolvable ranges — lockfile scan will cover them
279
292
  packages.push({
280
- name: depName,
281
- version: range.replace(/^[\^~>=<]/, ''),
282
- resolved: buildTarballUrl(depName, range.replace(/^[\^~>=<]/, ''), config.registry),
283
- integrity: '',
293
+ name: depName,
294
+ version: exactVersion,
295
+ resolved: buildTarballUrl(depName, exactVersion, config.registry),
296
+ integrity: '',
284
297
  hasInstallScript: false,
285
- dev: false,
286
- optional: false,
287
- inBundle: false,
288
- link: false,
298
+ dev: false,
299
+ optional: false,
300
+ inBundle: false,
301
+ link: false,
289
302
  });
290
303
  }
291
304
  }