@nodesecure/scanner
Advanced tools
Comparing version 3.4.1 to 3.5.0
{ | ||
"name": "@nodesecure/scanner", | ||
"version": "3.4.1", | ||
"version": "3.5.0", | ||
"description": "A package API to run a static analysis of your module's dependencies.", | ||
@@ -51,16 +51,16 @@ "exports": "./index.js", | ||
"devDependencies": { | ||
"@nodesecure/eslint-config": "^1.3.1", | ||
"@nodesecure/eslint-config": "^1.4.0", | ||
"@slimio/is": "^1.5.1", | ||
"@small-tech/esm-tape-runner": "^1.0.3", | ||
"@small-tech/tap-monkey": "^1.3.0", | ||
"@types/node": "^17.0.21", | ||
"c8": "^7.11.0", | ||
"@small-tech/esm-tape-runner": "^2.0.0", | ||
"@small-tech/tap-monkey": "^1.4.0", | ||
"@types/node": "^17.0.39", | ||
"c8": "^7.11.3", | ||
"cross-env": "^7.0.3", | ||
"dotenv": "^16.0.0", | ||
"eslint": "^8.11.0", | ||
"dotenv": "^16.0.1", | ||
"eslint": "^8.17.0", | ||
"get-folder-size": "^3.1.0", | ||
"pkg-ok": "^2.3.1", | ||
"sinon": "^13.0.1", | ||
"pkg-ok": "^3.0.0", | ||
"sinon": "^14.0.0", | ||
"snap-shot-core": "^10.2.4", | ||
"tape": "^5.5.2" | ||
"tape": "^5.5.3" | ||
}, | ||
@@ -70,19 +70,19 @@ "dependencies": { | ||
"@nodesecure/fs-walk": "^1.0.0", | ||
"@nodesecure/i18n": "^1.2.1", | ||
"@nodesecure/js-x-ray": "^4.2.1", | ||
"@nodesecure/i18n": "^1.3.0", | ||
"@nodesecure/js-x-ray": "^4.4.0", | ||
"@nodesecure/npm-registry-sdk": "^1.3.0", | ||
"@nodesecure/ntlp": "^2.1.0", | ||
"@nodesecure/utils": "^1.0.0", | ||
"@nodesecure/vuln": "^1.6.0", | ||
"@npm/types": "^1.0.1", | ||
"@npmcli/arborist": "^5.0.3", | ||
"@nodesecure/vuln": "^1.7.0", | ||
"@npm/types": "^1.0.2", | ||
"@npmcli/arborist": "^5.2.1", | ||
"@slimio/lock": "^1.0.0", | ||
"builtins": "^4.0.0", | ||
"builtins": "^5.0.1", | ||
"combine-async-iterators": "^2.0.1", | ||
"itertools": "^1.7.1", | ||
"lodash.difference": "^4.5.0", | ||
"pacote": "^13.0.5", | ||
"semver": "^7.3.4" | ||
"pacote": "^13.6.0", | ||
"semver": "^7.3.7" | ||
}, | ||
"type": "module" | ||
} |
@@ -0,0 +0,0 @@ # NodeSecure Scanner |
@@ -78,3 +78,4 @@ export default class Dependency { | ||
required_nodejs: [], | ||
required_thirdparty: [] | ||
required_thirdparty: [], | ||
required_subpath: [] | ||
}, | ||
@@ -81,0 +82,0 @@ license: "unkown license", |
@@ -36,7 +36,7 @@ // Import Node.js Dependencies | ||
// TODO: PR @npm/types to fix dependencies typo | ||
export async function readAnalyze(location) { | ||
const { | ||
description = "", author = {}, scripts = {}, | ||
dependencies = {}, devDependencies = {}, gypfile = false | ||
dependencies = {}, devDependencies = {}, gypfile = false, | ||
imports = {} | ||
} = await read(location); | ||
@@ -56,4 +56,5 @@ | ||
packageDevDeps, | ||
nodejs: { imports }, | ||
hasNativeElements: hasNativePackage || gypfile | ||
}; | ||
} |
@@ -28,3 +28,3 @@ // Import Third-party Dependencies | ||
hasReceivedUpdateInOneYear: !(oneYearFromToday > lastUpdateAt), | ||
maintainers: pkg.maintainers, | ||
maintainers: pkg.maintainers ?? [], | ||
publishers: [] | ||
@@ -39,4 +39,5 @@ }; | ||
const publishers = new Set(); | ||
let searchForMaintainersInVersions = metadata.maintainers.length === 0; | ||
for (const ver of Object.values(pkg.versions).reverse()) { | ||
const { _npmUser: npmUser, version } = ver; | ||
const { _npmUser: npmUser, version, maintainers = [] } = ver; | ||
const isNullOrUndefined = typeof npmUser === "undefined" || npmUser === null; | ||
@@ -60,2 +61,7 @@ if (isNullOrUndefined || !("name" in npmUser) || typeof npmUser.name !== "string") { | ||
} | ||
if (searchForMaintainersInVersions) { | ||
metadata.maintainers.push(...maintainers); | ||
searchForMaintainersInVersions = false; | ||
} | ||
} | ||
@@ -62,0 +68,0 @@ |
@@ -68,3 +68,5 @@ // Import Node.js Dependencies | ||
// Read the package.json at the root of the directory or archive. | ||
const { packageDeps, packageDevDeps, author, description, hasScript, hasNativeElements } = await manifest.readAnalyze(dest); | ||
const { | ||
packageDeps, packageDevDeps, author, description, hasScript, hasNativeElements, nodejs | ||
} = await manifest.readAnalyze(dest); | ||
ref.author = author; | ||
@@ -101,6 +103,7 @@ ref.description = description; | ||
const { | ||
nodeDependencies, thirdPartyDependencies, missingDependencies, unusedDependencies, flags | ||
} = analyzeDependencies(dependencies, { packageDeps, packageDevDeps, tryDependencies }); | ||
nodeDependencies, thirdPartyDependencies, subpathImportsDependencies, missingDependencies, unusedDependencies, flags | ||
} = analyzeDependencies(dependencies, { packageDeps, packageDevDeps, tryDependencies, nodeImports: nodejs.imports }); | ||
ref.composition.required_thirdparty = thirdPartyDependencies; | ||
ref.composition.required_subpath = Object.fromEntries(subpathImportsDependencies); | ||
ref.composition.unused.push(...unusedDependencies); | ||
@@ -107,0 +110,0 @@ ref.composition.missing.push(...missingDependencies); |
@@ -13,8 +13,16 @@ // Import Third-party Dependencies | ||
export function analyzeDependencies(dependencies, deps = {}) { | ||
const { packageDeps, packageDevDeps, tryDependencies } = deps; | ||
const { packageDeps, packageDevDeps, tryDependencies, nodeImports = {} } = deps; | ||
// See: https://nodejs.org/api/packages.html#subpath-imports | ||
const subpathImportsDependencies = dependencies | ||
.filter((name) => isAliasDependency(name) && name in nodeImports) | ||
.map((name) => buildSubpathDependency(name, nodeImports)); | ||
const thirdPartyDependenciesAliased = new Set( | ||
subpathImportsDependencies.flat().filter((name) => !isAliasDependency(name)) | ||
); | ||
const thirdPartyDependencies = dependencies | ||
.map((name) => (packageDeps.includes(name) ? name : getPackageName(name))) | ||
.filter((name) => !name.startsWith(".")) | ||
.filter((name) => !kNodeModules.has(name)) | ||
.filter((name) => !isNodeCoreModule(name)) | ||
.filter((name) => !packageDevDeps.includes(name)) | ||
@@ -25,6 +33,7 @@ .filter((name) => !tryDependencies.has(name)); | ||
packageDeps.filter((name) => !name.startsWith("@types")), | ||
thirdPartyDependencies | ||
[...thirdPartyDependencies, ...thirdPartyDependenciesAliased] | ||
); | ||
const missingDependencies = [...new Set(difference(thirdPartyDependencies, packageDeps))]; | ||
const nodeDependencies = dependencies.filter((name) => kNodeModules.has(name)); | ||
const missingDependencies = [...new Set(difference(thirdPartyDependencies, packageDeps))] | ||
.filter((name) => !(name in nodeImports)); | ||
const nodeDependencies = dependencies.filter((name) => isNodeCoreModule(name)); | ||
@@ -34,2 +43,3 @@ return { | ||
thirdPartyDependencies: [...new Set(thirdPartyDependencies)], | ||
subpathImportsDependencies, | ||
unusedDependencies, | ||
@@ -44,1 +54,22 @@ missingDependencies, | ||
} | ||
/** | ||
* @param {!string} moduleName | ||
* @returns {boolean} | ||
*/ | ||
function isNodeCoreModule(moduleName) { | ||
const cleanModuleName = moduleName.startsWith("node:") ? moduleName.slice(5) : moduleName; | ||
// Note: We need to also check moduleName because builtins package only return true for 'node:test'. | ||
return kNodeModules.has(cleanModuleName) || kNodeModules.has(moduleName); | ||
} | ||
function isAliasDependency(moduleName) { | ||
return moduleName.charAt(0) === "#"; | ||
} | ||
function buildSubpathDependency(alias, nodeImports) { | ||
const importedDependency = nodeImports[alias].node ?? nodeImports[alias].default; | ||
return [alias, importedDependency]; | ||
} |
@@ -0,0 +0,0 @@ // Import Third-party Dependencies |
@@ -61,2 +61,3 @@ // Import NodeSecure Dependencies | ||
required_nodejs: string[]; | ||
required_subpath: string[]; | ||
unused: string[]; | ||
@@ -63,0 +64,0 @@ missing: string[]; |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
57898
1366
9
- Removedbuiltins@4.1.0(transitive)
Updated@nodesecure/i18n@^1.3.0
Updated@nodesecure/js-x-ray@^4.4.0
Updated@nodesecure/vuln@^1.7.0
Updated@npm/types@^1.0.2
Updated@npmcli/arborist@^5.2.1
Updatedbuiltins@^5.0.1
Updatedpacote@^13.6.0
Updatedsemver@^7.3.7