@nodesecure/scanner 3.6.0 → 3.8.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 CHANGED
@@ -1,97 +1,104 @@
1
- # NodeSecure Scanner
2
- ![version](https://img.shields.io/badge/dynamic/json.svg?url=https://raw.githubusercontent.com/NodeSecure/scanner/master/package.json&query=$.version&label=Version)
3
- [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/NodeSecure/scanner/commit-activity)
4
- [![Security Responsible Disclosure](https://img.shields.io/badge/Security-Responsible%20Disclosure-yellow.svg)](https://github.com/nodejs/security-wg/blob/master/processes/responsible_disclosure_template.md
5
- )
6
- [![mit](https://img.shields.io/github/license/Naereen/StrapDown.js.svg)](https://github.com/NodeSecure/scanner/blob/master/LICENSE)
7
- ![build](https://img.shields.io/github/workflow/status/NodeSecure/scanner/Node.js%20CI)
8
-
9
- ⚡️ Run a static analysis of your module's dependencies.
10
-
11
- ## Requirements
12
-
13
- - [Node.js](https://nodejs.org/en/) version 16 or higher
14
-
15
- ## Getting Started
16
-
17
- This package is available in the Node Package Repository and can be easily installed with [npm](https://docs.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com).
18
-
19
- ```bash
20
- $ npm i @nodesecure/scanner
21
- # or
22
- $ yarn add @nodesecure/scanner
23
- ```
24
-
25
- ## Usage example
26
-
27
- ```js
28
- import * as scanner from "@nodesecure/scanner";
29
- import fs from "fs/promises";
30
-
31
- // CONSTANTS
32
- const kPackagesToAnalyze = ["mocha", "cacache", "is-wsl"];
33
-
34
- const payloads = await Promise.all(
35
- kPackagesToAnalyze.map((name) => scanner.from(name))
36
- );
37
-
38
- const promises = [];
39
- for (let i = 0; i < kPackagesToAnalyze.length; i++) {
40
- const data = JSON.stringify(payloads[i], null, 2);
41
-
42
- promises.push(fs.writeFile(`${kPackagesToAnalyze[i]}.json`, data));
43
- }
44
- await Promise.allSettled(promises);
45
- ```
46
-
47
- ## API
48
-
49
- See `types/api.d.ts` for a complete TypeScript definition.
50
-
51
- ```ts
52
- function cwd(location: string, options?: Scanner.Options): Promise<Scanner.Payload>;
53
- function from(packageName: string, options?: Omit<Scanner.Options, "includeDevDeps">): Promise<Scanner.Payload>;
54
- function verify(packageName?: string | null): Promise<Scanner.VerifyPayload>;
55
- ```
56
-
57
- `Options` is described with the following TypeScript interface:
58
-
59
- ```ts
60
- interface Options {
61
- readonly maxDepth?: number;
62
- readonly usePackageLock?: boolean;
63
- readonly includeDevDeps?: boolean;
64
- readonly vulnerabilityStrategy: Strategy.Kind;
65
- readonly forceRootAnalysis?: boolean;
66
- readonly fullLockMode?: boolean;
67
- }
68
- ```
69
-
70
- ## Contributors ✨
71
-
72
- <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
73
- [![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-)
74
- <!-- ALL-CONTRIBUTORS-BADGE:END -->
75
-
76
- Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
77
-
78
- <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
79
- <!-- prettier-ignore-start -->
80
- <!-- markdownlint-disable -->
81
- <table>
82
- <tr>
83
- <td align="center"><a href="https://www.linkedin.com/in/thomas-gentilhomme/"><img src="https://avatars.githubusercontent.com/u/4438263?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gentilhomme</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=fraxken" title="Code">💻</a> <a href="https://github.com/NodeSecure/scanner/commits?author=fraxken" title="Documentation">📖</a> <a href="https://github.com/NodeSecure/scanner/pulls?q=is%3Apr+reviewed-by%3Afraxken" title="Reviewed Pull Requests">👀</a> <a href="#security-fraxken" title="Security">🛡️</a> <a href="https://github.com/NodeSecure/scanner/issues?q=author%3Afraxken" title="Bug reports">🐛</a></td>
84
- <td align="center"><a href="http://tonygo.dev"><img src="https://avatars.githubusercontent.com/u/22824417?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tony Gorez</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=tony-go" title="Code">💻</a> <a href="https://github.com/NodeSecure/scanner/commits?author=tony-go" title="Documentation">📖</a> <a href="https://github.com/NodeSecure/scanner/pulls?q=is%3Apr+reviewed-by%3Atony-go" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/NodeSecure/scanner/issues?q=author%3Atony-go" title="Bug reports">🐛</a></td>
85
- <td align="center"><a href="https://mickaelcroquet.fr"><img src="https://avatars.githubusercontent.com/u/23740372?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Haze</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=CroquetMickael" title="Code">💻</a></td>
86
- <td align="center"><a href="https://github.com/mbalabash"><img src="https://avatars.githubusercontent.com/u/16868922?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maksim Balabash</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=mbalabash" title="Code">💻</a></td>
87
- <td align="center"><a href="https://dev.to/antoinecoulon"><img src="https://avatars.githubusercontent.com/u/43391199?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Antoine Coulon</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=antoine-coulon" title="Code">💻</a> <a href="#security-antoine-coulon" title="Security">🛡️</a></td>
88
- </tr>
89
- </table>
90
-
91
- <!-- markdownlint-restore -->
92
- <!-- prettier-ignore-end -->
93
-
94
- <!-- ALL-CONTRIBUTORS-LIST:END -->
95
-
96
- ## License
97
- MIT
1
+ # NodeSecure Scanner
2
+ ![version](https://img.shields.io/badge/dynamic/json.svg?url=https://raw.githubusercontent.com/NodeSecure/scanner/master/package.json&query=$.version&label=Version)
3
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/NodeSecure/scanner/commit-activity)
4
+ [![mit](https://img.shields.io/github/license/Naereen/StrapDown.js.svg)](https://github.com/NodeSecure/scanner/blob/master/LICENSE)
5
+ ![build](https://img.shields.io/github/workflow/status/NodeSecure/scanner/Node.js%20CI)
6
+
7
+ ⚡️ Run a static analysis of your module's dependencies.
8
+
9
+ ## Requirements
10
+
11
+ - [Node.js](https://nodejs.org/en/) version 16 or higher
12
+
13
+ ## Getting Started
14
+
15
+ This package is available in the Node Package Repository and can be easily installed with [npm](https://docs.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com).
16
+
17
+ ```bash
18
+ $ npm i @nodesecure/scanner
19
+ # or
20
+ $ yarn add @nodesecure/scanner
21
+ ```
22
+
23
+ ## Usage example
24
+
25
+ ```js
26
+ import * as scanner from "@nodesecure/scanner";
27
+ import fs from "fs/promises";
28
+
29
+ // CONSTANTS
30
+ const kPackagesToAnalyze = ["mocha", "cacache", "is-wsl"];
31
+
32
+ const payloads = await Promise.all(
33
+ kPackagesToAnalyze.map((name) => scanner.from(name))
34
+ );
35
+
36
+ const promises = [];
37
+ for (let i = 0; i < kPackagesToAnalyze.length; i++) {
38
+ const data = JSON.stringify(payloads[i], null, 2);
39
+
40
+ promises.push(fs.writeFile(`${kPackagesToAnalyze[i]}.json`, data));
41
+ }
42
+ await Promise.allSettled(promises);
43
+ ```
44
+
45
+ ## API
46
+
47
+ See `types/api.d.ts` for a complete TypeScript definition.
48
+
49
+ ```ts
50
+ function cwd(location: string, options?: Scanner.Options): Promise<Scanner.Payload>;
51
+ function from(packageName: string, options?: Omit<Scanner.Options, "includeDevDeps">): Promise<Scanner.Payload>;
52
+ function verify(packageName?: string | null): Promise<Scanner.VerifyPayload>;
53
+ ```
54
+
55
+ `Options` is described with the following TypeScript interface:
56
+
57
+ ```ts
58
+ interface Options {
59
+ readonly maxDepth?: number;
60
+ readonly registry?: string | URL;
61
+ readonly usePackageLock?: boolean;
62
+ readonly includeDevDeps?: boolean;
63
+ readonly vulnerabilityStrategy: Strategy.Kind;
64
+ readonly forceRootAnalysis?: boolean;
65
+ readonly fullLockMode?: boolean;
66
+ }
67
+ ```
68
+
69
+ ## Contributors ✨
70
+
71
+ <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
72
+ [![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors-)
73
+ <!-- ALL-CONTRIBUTORS-BADGE:END -->
74
+
75
+ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
76
+
77
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
78
+ <!-- prettier-ignore-start -->
79
+ <!-- markdownlint-disable -->
80
+ <table>
81
+ <tbody>
82
+ <tr>
83
+ <td align="center"><a href="https://www.linkedin.com/in/thomas-gentilhomme/"><img src="https://avatars.githubusercontent.com/u/4438263?v=4?s=100" width="100px;" alt="Gentilhomme"/><br /><sub><b>Gentilhomme</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=fraxken" title="Code">💻</a> <a href="https://github.com/NodeSecure/scanner/commits?author=fraxken" title="Documentation">📖</a> <a href="https://github.com/NodeSecure/scanner/pulls?q=is%3Apr+reviewed-by%3Afraxken" title="Reviewed Pull Requests">👀</a> <a href="#security-fraxken" title="Security">🛡️</a> <a href="https://github.com/NodeSecure/scanner/issues?q=author%3Afraxken" title="Bug reports">🐛</a></td>
84
+ <td align="center"><a href="http://tonygo.dev"><img src="https://avatars.githubusercontent.com/u/22824417?v=4?s=100" width="100px;" alt="Tony Gorez"/><br /><sub><b>Tony Gorez</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=tony-go" title="Code">💻</a> <a href="https://github.com/NodeSecure/scanner/commits?author=tony-go" title="Documentation">📖</a> <a href="https://github.com/NodeSecure/scanner/pulls?q=is%3Apr+reviewed-by%3Atony-go" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/NodeSecure/scanner/issues?q=author%3Atony-go" title="Bug reports">🐛</a></td>
85
+ <td align="center"><a href="https://mickaelcroquet.fr"><img src="https://avatars.githubusercontent.com/u/23740372?v=4?s=100" width="100px;" alt="Haze"/><br /><sub><b>Haze</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=CroquetMickael" title="Code">💻</a></td>
86
+ <td align="center"><a href="https://github.com/mbalabash"><img src="https://avatars.githubusercontent.com/u/16868922?v=4?s=100" width="100px;" alt="Maksim Balabash"/><br /><sub><b>Maksim Balabash</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=mbalabash" title="Code">💻</a></td>
87
+ <td align="center"><a href="https://dev.to/antoinecoulon"><img src="https://avatars.githubusercontent.com/u/43391199?v=4?s=100" width="100px;" alt="Antoine Coulon"/><br /><sub><b>Antoine Coulon</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=antoine-coulon" title="Code">💻</a> <a href="#security-antoine-coulon" title="Security">🛡️</a></td>
88
+ <td align="center"><a href="https://www.linkedin.com/in/nicolas-hallaert/"><img src="https://avatars.githubusercontent.com/u/39910164?v=4?s=100" width="100px;" alt="Nicolas Hallaert"/><br /><sub><b>Nicolas Hallaert</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=Rossb0b" title="Code">💻</a></td>
89
+ <td align="center"><a href="http://sofiand.github.io/portfolio-client/"><img src="https://avatars.githubusercontent.com/u/39944043?v=4?s=100" width="100px;" alt="Yefis"/><br /><sub><b>Yefis</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=SofianD" title="Code">💻</a></td>
90
+ </tr>
91
+ <tr>
92
+ <td align="center"><a href="https://www.linkedin.com/in/franck-hallaert/"><img src="https://avatars.githubusercontent.com/u/110826655?v=4?s=100" width="100px;" alt="Franck Hallaert"/><br /><sub><b>Franck Hallaert</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=Aekk0" title="Code">💻</a></td>
93
+ <td align="center"><a href="https://www.linkedin.com/in/ange-tekeu-a155811b4/"><img src="https://avatars.githubusercontent.com/u/35274201?v=4?s=100" width="100px;" alt="Ange TEKEU"/><br /><sub><b>Ange TEKEU</b></sub></a><br /><a href="https://github.com/NodeSecure/scanner/commits?author=tekeuange23" title="Code">💻</a></td>
94
+ </tr>
95
+ </tbody>
96
+ </table>
97
+
98
+ <!-- markdownlint-restore -->
99
+ <!-- prettier-ignore-end -->
100
+
101
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
102
+
103
+ ## License
104
+ MIT
package/index.js CHANGED
@@ -19,7 +19,16 @@ import * as tarball from "./src/tarball.js";
19
19
  const kDefaultCwdOptions = { forceRootAnalysis: true, usePackageLock: true, includeDevDeps: false };
20
20
 
21
21
  export async function cwd(location = process.cwd(), options = {}, logger = new Logger()) {
22
- const finalizedOptions = Object.assign({ location }, kDefaultCwdOptions, options);
22
+ const registry = options.registry ? new URL(options.registry).toString() : getLocalRegistryURL();
23
+
24
+ const finalizedOptions = Object.assign(
25
+ { location },
26
+ kDefaultCwdOptions,
27
+ {
28
+ ...options,
29
+ registry
30
+ }
31
+ );
23
32
 
24
33
  logger.start(ScannerLoggerEvents.manifest.read);
25
34
  const packagePath = path.join(location, "package.json");
@@ -30,13 +39,15 @@ export async function cwd(location = process.cwd(), options = {}, logger = new L
30
39
  }
31
40
 
32
41
  export async function from(packageName, options, logger = new Logger()) {
42
+ const registry = options.registry ? new URL(options.registry).toString() : getLocalRegistryURL();
43
+
33
44
  logger.start(ScannerLoggerEvents.manifest.fetch);
34
45
  const manifest = await pacote.manifest(packageName, {
35
- ...NPM_TOKEN, registry: getLocalRegistryURL(), cache: `${os.homedir()}/.npm`
46
+ ...NPM_TOKEN, registry, cache: `${os.homedir()}/.npm`
36
47
  });
37
48
  logger.end(ScannerLoggerEvents.manifest.fetch);
38
49
 
39
- return depWalker(manifest, options, logger);
50
+ return depWalker(manifest, Object.assign(options, { registry }), logger);
40
51
  }
41
52
 
42
53
  export async function verify(packageName = null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodesecure/scanner",
3
- "version": "3.6.0",
3
+ "version": "3.8.0",
4
4
  "description": "A package API to run a static analysis of your module's dependencies.",
5
5
  "exports": "./index.js",
6
6
  "engines": {
@@ -48,39 +48,39 @@
48
48
  },
49
49
  "homepage": "https://github.com/NodeSecure/scanner#readme",
50
50
  "devDependencies": {
51
- "@nodesecure/eslint-config": "^1.4.0",
51
+ "@nodesecure/eslint-config": "^1.5.0",
52
52
  "@slimio/is": "^1.5.1",
53
53
  "@small-tech/esm-tape-runner": "^2.0.0",
54
54
  "@small-tech/tap-monkey": "^1.4.0",
55
- "@types/node": "^17.0.39",
56
- "c8": "^7.11.3",
55
+ "@types/node": "^18.11.9",
56
+ "c8": "^7.12.0",
57
57
  "cross-env": "^7.0.3",
58
- "dotenv": "^16.0.1",
59
- "eslint": "^8.17.0",
60
- "get-folder-size": "^3.1.0",
58
+ "dotenv": "^16.0.3",
59
+ "eslint": "^8.27.0",
60
+ "get-folder-size": "^4.0.0",
61
61
  "pkg-ok": "^3.0.0",
62
- "sinon": "^14.0.0",
62
+ "sinon": "^14.0.1",
63
63
  "snap-shot-core": "^10.2.4",
64
- "tape": "^5.5.3"
64
+ "tape": "^5.6.1"
65
65
  },
66
66
  "dependencies": {
67
- "@nodesecure/flags": "^2.3.0",
67
+ "@nodesecure/flags": "^2.4.0",
68
68
  "@nodesecure/fs-walk": "^1.0.0",
69
- "@nodesecure/i18n": "^1.3.0",
70
- "@nodesecure/js-x-ray": "^4.5.0",
71
- "@nodesecure/npm-registry-sdk": "^1.3.0",
69
+ "@nodesecure/i18n": "^2.0.0",
70
+ "@nodesecure/js-x-ray": "^5.1.0",
71
+ "@nodesecure/npm-registry-sdk": "^1.4.1",
72
72
  "@nodesecure/ntlp": "^2.1.0",
73
73
  "@nodesecure/utils": "^1.0.0",
74
74
  "@nodesecure/vuln": "^1.7.0",
75
75
  "@npm/types": "^1.0.2",
76
- "@npmcli/arborist": "^5.2.1",
76
+ "@npmcli/arborist": "^6.1.1",
77
77
  "@slimio/lock": "^1.0.0",
78
78
  "builtins": "^5.0.1",
79
79
  "combine-async-iterators": "^2.0.1",
80
80
  "itertools": "^1.7.1",
81
81
  "lodash.difference": "^4.5.0",
82
- "pacote": "^13.6.0",
83
- "semver": "^7.3.7"
82
+ "pacote": "^15.0.6",
83
+ "semver": "^7.3.8"
84
84
  },
85
85
  "type": "module"
86
86
  }
@@ -9,6 +9,8 @@ export default class Dependency {
9
9
  this.name = name;
10
10
  this.version = version;
11
11
  this.dev = false;
12
+ this.existOnRemoteRegistry = true;
13
+ this.alias = {};
12
14
 
13
15
  if (parent !== null) {
14
16
  parent.dependencyCount++;
@@ -62,6 +64,7 @@ export default class Dependency {
62
64
  id: typeof customId === "number" ? customId : Dependency.currentId++,
63
65
  usedBy: this.parent,
64
66
  isDevDependency: this.dev,
67
+ existOnRemoteRegistry: this.existOnRemoteRegistry,
65
68
  flags: this.flags,
66
69
  description: "",
67
70
  size: 0,
@@ -76,6 +79,7 @@ export default class Dependency {
76
79
  minified: [],
77
80
  unused: [],
78
81
  missing: [],
82
+ alias: this.alias,
79
83
  required_files: [],
80
84
  required_nodejs: [],
81
85
  required_thirdparty: [],
package/src/depWalker.js CHANGED
@@ -11,7 +11,6 @@ import pacote from "pacote";
11
11
  import Arborist from "@npmcli/arborist";
12
12
  import Lock from "@slimio/lock";
13
13
  import * as vuln from "@nodesecure/vuln";
14
- import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk";
15
14
  import { ScannerLoggerEvents } from "./constants.js";
16
15
 
17
16
  // Import Internal Dependencies
@@ -31,24 +30,38 @@ const { version: packageVersion } = JSON.parse(
31
30
  );
32
31
 
33
32
  export async function* searchDeepDependencies(packageName, gitURL, options) {
34
- const { exclude, currDepth = 0, parent, maxDepth } = options;
33
+ const { exclude, currDepth = 0, parent, maxDepth, registry } = options;
35
34
 
36
35
  const { name, version, deprecated, ...pkg } = await pacote.manifest(gitURL ?? packageName, {
37
36
  ...NPM_TOKEN,
38
- registry: getLocalRegistryURL(),
37
+ registry,
39
38
  cache: `${os.homedir()}/.npm`
40
39
  });
41
- const { dependencies, customResolvers } = mergeDependencies(pkg);
40
+ const { dependencies, customResolvers, alias } = mergeDependencies(pkg);
42
41
 
43
42
  const current = new Dependency(name, version, parent);
44
- gitURL !== null && current.isGit(gitURL);
43
+ current.alias = Object.fromEntries(alias);
44
+
45
+ if (gitURL !== null) {
46
+ current.isGit(gitURL);
47
+ try {
48
+ await pacote.manifest(`${name}@${version}`, {
49
+ ...NPM_TOKEN,
50
+ registry,
51
+ cache: `${os.homedir()}/.npm`
52
+ });
53
+ }
54
+ catch {
55
+ current.existOnRemoteRegistry = false;
56
+ }
57
+ }
45
58
  current.addFlag("isDeprecated", deprecated === true);
46
59
  current.addFlag("hasCustomResolver", customResolvers.size > 0);
47
60
  current.addFlag("hasDependencies", dependencies.size > 0);
48
61
 
49
62
  if (currDepth !== maxDepth) {
50
63
  const config = {
51
- exclude, currDepth: currDepth + 1, parent: current, maxDepth
64
+ exclude, currDepth: currDepth + 1, parent: current, maxDepth, registry
52
65
  };
53
66
 
54
67
  const gitDependencies = iter.filter(customResolvers.entries(), ([, valueStr]) => isGitDependency(valueStr));
@@ -76,7 +89,7 @@ export async function* searchDeepDependencies(packageName, gitURL, options) {
76
89
  }
77
90
 
78
91
  export async function* deepReadEdges(currentPackageName, options) {
79
- const { to, parent, exclude, fullLockMode, includeDevDeps } = options;
92
+ const { to, parent, exclude, fullLockMode, includeDevDeps, registry } = options;
80
93
  const { version, integrity = to.integrity } = to.package;
81
94
 
82
95
  const updatedVersion = version === "*" || typeof version === "undefined" ? "latest" : version;
@@ -86,14 +99,19 @@ export async function* deepReadEdges(currentPackageName, options) {
86
99
  if (fullLockMode && !includeDevDeps) {
87
100
  const { deprecated, _integrity, ...pkg } = await pacote.manifest(`${currentPackageName}@${updatedVersion}`, {
88
101
  ...NPM_TOKEN,
89
- registry: getLocalRegistryURL(),
102
+ registry,
90
103
  cache: `${os.homedir()}/.npm`
91
104
  });
92
- const { customResolvers } = mergeDependencies(pkg);
105
+ const { customResolvers, alias } = mergeDependencies(pkg);
93
106
 
107
+ current.alias = Object.fromEntries(alias);
94
108
  current.addFlag("hasValidIntegrity", _integrity === integrity);
95
109
  current.addFlag("isDeprecated");
96
110
  current.addFlag("hasCustomResolver", customResolvers.size > 0);
111
+
112
+ if (isGitDependency(to.resolved)) {
113
+ current.isGit(to.resolved);
114
+ }
97
115
  }
98
116
  current.addFlag("hasDependencies", to.edgesOut.size > 0);
99
117
 
@@ -108,7 +126,7 @@ export async function* deepReadEdges(currentPackageName, options) {
108
126
  }
109
127
  else {
110
128
  exclude.set(cleanName, new Set([current.fullName]));
111
- yield* deepReadEdges(packageName, { parent: current, to: toNode, exclude });
129
+ yield* deepReadEdges(packageName, { parent: current, to: toNode, exclude, registry });
112
130
  }
113
131
  }
114
132
  yield current;
@@ -118,11 +136,24 @@ export async function* getRootDependencies(manifest, options) {
118
136
  const {
119
137
  maxDepth = 4, exclude,
120
138
  usePackageLock, fullLockMode, includeDevDeps,
121
- location
139
+ location,
140
+ registry
122
141
  } = options;
123
142
 
124
- const { dependencies, customResolvers } = mergeDependencies(manifest, void 0);
143
+ const { dependencies, customResolvers, alias } = mergeDependencies(manifest, void 0);
125
144
  const parent = new Dependency(manifest.name, manifest.version);
145
+ parent.alias = Object.fromEntries(alias);
146
+
147
+ try {
148
+ await pacote.manifest(`${manifest.name}@${manifest.version}`, {
149
+ ...NPM_TOKEN,
150
+ registry,
151
+ cache: `${os.homedir()}/.npm`
152
+ });
153
+ }
154
+ catch {
155
+ parent.existOnRemoteRegistry = false;
156
+ }
126
157
  parent.addFlag("hasCustomResolver", customResolvers.size > 0);
127
158
  parent.addFlag("hasDependencies", dependencies.size > 0);
128
159
 
@@ -131,7 +162,7 @@ export async function* getRootDependencies(manifest, options) {
131
162
  const arb = new Arborist({
132
163
  ...NPM_TOKEN,
133
164
  path: location,
134
- registry: getLocalRegistryURL()
165
+ registry
135
166
  });
136
167
  let tree;
137
168
  try {
@@ -146,11 +177,18 @@ export async function* getRootDependencies(manifest, options) {
146
177
  ...iter
147
178
  .filter(tree.edgesOut.entries(), ([, { to }]) => to !== null && (includeDevDeps ? true : (!to.dev || to.isWorkspace)))
148
179
  .map(([packageName, { to }]) => [packageName, to.isWorkspace ? to.target : to])
149
- .map(([packageName, to]) => deepReadEdges(packageName, { to, parent, fullLockMode, includeDevDeps, exclude }))
180
+ .map(([packageName, to]) => deepReadEdges(packageName, {
181
+ to,
182
+ parent,
183
+ fullLockMode,
184
+ includeDevDeps,
185
+ exclude,
186
+ registry
187
+ }))
150
188
  ];
151
189
  }
152
190
  else {
153
- const configRef = { exclude, maxDepth, parent };
191
+ const configRef = { exclude, maxDepth, parent, registry };
154
192
  iterators = [
155
193
  ...iter.filter(customResolvers.entries(), ([, valueStr]) => isGitDependency(valueStr))
156
194
  .map(([depName, valueStr]) => searchDeepDependencies(depName, valueStr, configRef)),
@@ -189,7 +227,8 @@ export async function depWalker(manifest, options = {}, logger = new Logger()) {
189
227
  fullLockMode = false,
190
228
  maxDepth,
191
229
  location,
192
- vulnerabilityStrategy = vuln.strategies.NONE
230
+ vulnerabilityStrategy = vuln.strategies.NONE,
231
+ registry
193
232
  } = options;
194
233
 
195
234
  // Create TMP directory
@@ -218,7 +257,7 @@ export async function depWalker(manifest, options = {}, logger = new Logger()) {
218
257
  const tarballLocker = new Lock({ maxConcurrent: 5 });
219
258
  tarballLocker.on("freeOne", () => logger.tick(ScannerLoggerEvents.analysis.tarball));
220
259
 
221
- const rootDepsOptions = { maxDepth, exclude, usePackageLock, fullLockMode, includeDevDeps, location };
260
+ const rootDepsOptions = { maxDepth, exclude, usePackageLock, fullLockMode, includeDevDeps, location, registry };
222
261
  for await (const currentDep of getRootDependencies(manifest, rootDepsOptions)) {
223
262
  const { name, version, dev } = currentDep;
224
263
  const current = currentDep.exportAsPlainObject(name === manifest.name ? 0 : void 0);
@@ -267,7 +306,8 @@ export async function depWalker(manifest, options = {}, logger = new Logger()) {
267
306
  location,
268
307
  tmpLocation: forceRootAnalysis && name === manifest.name ? null : tmpLocation,
269
308
  locker: tarballLocker,
270
- logger
309
+ logger,
310
+ registry
271
311
  }));
272
312
  }
273
313
  }
package/src/tarball.js CHANGED
@@ -14,7 +14,6 @@ import {
14
14
  NPM_TOKEN
15
15
  } from "./utils/index.js";
16
16
  import * as manifest from "./manifest.js";
17
- import { getLocalRegistryURL } from "@nodesecure/npm-registry-sdk";
18
17
 
19
18
  // CONSTANTS
20
19
  const kNativeCodeExtensions = new Set([".gyp", ".c", ".cpp", ".node", ".so", ".h"]);
@@ -47,7 +46,7 @@ export async function scanJavascriptFile(dest, file, packageName) {
47
46
  }
48
47
 
49
48
  export async function scanDirOrArchive(name, version, options) {
50
- const { ref, location = process.cwd(), tmpLocation, locker } = options;
49
+ const { ref, location = process.cwd(), tmpLocation, locker, registry } = options;
51
50
 
52
51
  const isNpmTarball = !(tmpLocation === null);
53
52
  const dest = isNpmTarball ? path.join(tmpLocation, `${name}@${version}`) : location;
@@ -58,7 +57,7 @@ export async function scanDirOrArchive(name, version, options) {
58
57
  if (isNpmTarball) {
59
58
  await pacote.extract(ref.flags.includes("isGit") ? ref.gitUrl : `${name}@${version}`, dest, {
60
59
  ...NPM_TOKEN,
61
- registry: getLocalRegistryURL(),
60
+ registry,
62
61
  cache: `${os.homedir()}/.npm`
63
62
  });
64
63
  await timers.setImmediate();
@@ -1,5 +1,3 @@
1
- const kGitVersionVariants = ["git:", "git+", "github:"];
2
-
3
1
  /**
4
2
  * @example isGitDependency("github:NodeSecure/scanner") // => true
5
3
  * @example isGitDependency("git+ssh://git@github.com:npm/cli#semver:^5.0") // => true
@@ -9,12 +7,5 @@ const kGitVersionVariants = ["git:", "git+", "github:"];
9
7
  * @returns {boolean}
10
8
  */
11
9
  export function isGitDependency(version) {
12
- for (const variant of kGitVersionVariants) {
13
- if (version.startsWith(variant)) {
14
- return true;
15
- }
16
- }
17
-
18
- return false;
10
+ return /^git(:|\+|hub:)/.test(version);
19
11
  }
20
-
@@ -1,6 +1,7 @@
1
1
  export function mergeDependencies(manifest, types = ["dependencies"]) {
2
2
  const dependencies = new Map();
3
3
  const customResolvers = new Map();
4
+ const alias = new Map();
4
5
 
5
6
  for (const fieldName of types) {
6
7
  if (!Reflect.has(manifest, fieldName)) {
@@ -15,12 +16,15 @@ export function mergeDependencies(manifest, types = ["dependencies"]) {
15
16
  */
16
17
  if (/^([a-zA-Z]+:|git\+|\.\\)/.test(version)) {
17
18
  customResolvers.set(name, version);
18
- continue;
19
+ if (!version.startsWith("npm:")) {
20
+ continue;
21
+ }
22
+ alias.set(name, version.slice(4));
19
23
  }
20
24
 
21
25
  dependencies.set(name, version);
22
26
  }
23
27
  }
24
28
 
25
- return { dependencies, customResolvers };
29
+ return { dependencies, customResolvers, alias };
26
30
  }
@@ -34,6 +34,11 @@ declare namespace Scanner {
34
34
  /** Id of the package (useful for usedBy relation) */
35
35
  id: number;
36
36
  isDevDependency: boolean;
37
+ /**
38
+ * Tell if the given package exist on the configured remote registry (npm by default)
39
+ * @default true
40
+ */
41
+ existOnRemoteRegistry: boolean;
37
42
  /** By whom (id) is used the package */
38
43
  usedBy: Record<string, string>;
39
44
  /** Size on disk of the extracted tarball (in bytes) */
@@ -56,7 +61,7 @@ declare namespace Scanner {
56
61
  *
57
62
  * @see https://github.com/NodeSecure/js-x-ray/blob/master/WARNINGS.md
58
63
  */
59
- warnings: JSXRay.Warning<JSXRay.BaseWarning>[];
64
+ warnings: JSXRay.Warning<JSXRay.WarningDefault>[];
60
65
  /** Tarball composition (files and dependencies) */
61
66
  composition: {
62
67
  /** Files extensions (.js, .md, .exe etc..) */
@@ -64,6 +69,7 @@ declare namespace Scanner {
64
69
  files: string[];
65
70
  /** Minified files (foo.min.js etc..) */
66
71
  minified: string[];
72
+ alias: Record<string, string>;
67
73
  required_files: string[];
68
74
  required_thirdparty: string[];
69
75
  required_nodejs: string[];
@@ -155,7 +161,7 @@ declare namespace Scanner {
155
161
  licenses: License[];
156
162
  ast: {
157
163
  dependencies: Record<string, JSXRay.Dependency>;
158
- warnings: JSXRay.Warning<JSXRay.BaseWarning>[];
164
+ warnings: JSXRay.Warning<JSXRay.WarningDefault>[];
159
165
  };
160
166
  }
161
167
 
@@ -166,6 +172,7 @@ declare namespace Scanner {
166
172
  * @default 4
167
173
  */
168
174
  readonly maxDepth?: number;
175
+ readonly registry?: string | URL;
169
176
  /**
170
177
  * Use root package-lock.json. This will have the effect of triggering the Arborist package.
171
178
  *
@@ -1,63 +1,63 @@
1
- import ntlp from "@nodesecure/ntlp";
2
- import Locker from "@slimio/lock";
3
- import Logger from "../src/logger.class";
4
-
5
- export = tarball;
6
-
7
- declare namespace tarball {
8
- export interface ManifestData {
9
- /** Dependencies in package.json */
10
- packageDeps: string[];
11
- /** DevDependencies in package.json */
12
- packageDevDeps: string[];
13
- /** Does package.json contain a 'gypfile' property ? */
14
- packageGyp: boolean;
15
- }
16
-
17
- export interface ScannedFileResult {
18
- /** Dependencies in try/catch block (probably optional dependencies) */
19
- inTryDeps: string[];
20
- /** Dependencies required or imported */
21
- dependencies: string[];
22
- /** Required or imported javascript files */
23
- filesDependencies: string[];
24
- }
25
-
26
- export interface ScannedPackageResult {
27
- files: {
28
- /** Complete list of files for the given package */
29
- list: string[];
30
- /** Complete list of extensions (.js, .md etc.) */
31
- extensions: string[];
32
- /** List of minified javascript files */
33
- minified: string[];
34
- };
35
- /** Size of the directory in bytes */
36
- directorySize: number;
37
- /** Unique license contained in the tarball (MIT, ISC ..) */
38
- uniqueLicenseIds: string[];
39
- /** All licenses with their SPDX */
40
- licenses: ntlp.license[];
41
- ast: {
42
- dependencies: any;
43
- warnings: any[];
44
- };
45
- }
46
-
47
- export interface ScanDirOrArchiveOptions {
48
- ref: any;
49
- locker: Locker;
50
- tmpLocation: string;
51
- logger: Logger;
52
- }
53
-
54
- export interface ScanFileOptions {
55
- name: string;
56
- ref: any;
57
- }
58
-
59
- export function readManifest(dest: string, ref: any): Promise<ManifestData>;
60
- export function scanFile(dest: string, file: string, options: ScanFileOptions): Promise<ScannedFileResult | null>;
61
- export function scanPackage(dest: string, packageName: string): Promise<ScannedPackageResult>;
62
- export function scanDirOrArchive(name: string, version: string, options: ScanDirOrArchiveOptions): Promise<void>;
63
- }
1
+ import ntlp from "@nodesecure/ntlp";
2
+ import Locker from "@slimio/lock";
3
+ import Logger from "../src/logger.class";
4
+
5
+ export = tarball;
6
+
7
+ declare namespace tarball {
8
+ export interface ManifestData {
9
+ /** Dependencies in package.json */
10
+ packageDeps: string[];
11
+ /** DevDependencies in package.json */
12
+ packageDevDeps: string[];
13
+ /** Does package.json contain a 'gypfile' property ? */
14
+ packageGyp: boolean;
15
+ }
16
+
17
+ export interface ScannedFileResult {
18
+ /** Dependencies in try/catch block (probably optional dependencies) */
19
+ inTryDeps: string[];
20
+ /** Dependencies required or imported */
21
+ dependencies: string[];
22
+ /** Required or imported javascript files */
23
+ filesDependencies: string[];
24
+ }
25
+
26
+ export interface ScannedPackageResult {
27
+ files: {
28
+ /** Complete list of files for the given package */
29
+ list: string[];
30
+ /** Complete list of extensions (.js, .md etc.) */
31
+ extensions: string[];
32
+ /** List of minified javascript files */
33
+ minified: string[];
34
+ };
35
+ /** Size of the directory in bytes */
36
+ directorySize: number;
37
+ /** Unique license contained in the tarball (MIT, ISC ..) */
38
+ uniqueLicenseIds: string[];
39
+ /** All licenses with their SPDX */
40
+ licenses: ntlp.license[];
41
+ ast: {
42
+ dependencies: any;
43
+ warnings: any[];
44
+ };
45
+ }
46
+
47
+ export interface ScanDirOrArchiveOptions {
48
+ ref: any;
49
+ locker: Locker;
50
+ tmpLocation: string;
51
+ logger: Logger;
52
+ }
53
+
54
+ export interface ScanFileOptions {
55
+ name: string;
56
+ ref: any;
57
+ }
58
+
59
+ export function readManifest(dest: string, ref: any): Promise<ManifestData>;
60
+ export function scanFile(dest: string, file: string, options: ScanFileOptions): Promise<ScannedFileResult | null>;
61
+ export function scanPackage(dest: string, packageName?: string): Promise<ScannedPackageResult>;
62
+ export function scanDirOrArchive(name: string, version: string, options: ScanDirOrArchiveOptions): Promise<void>;
63
+ }