@cdxgen/cdxgen 13.3.0 → 13.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 +9 -6
- package/bin/cdxgen.js +90 -26
- package/bin/evinse.js +18 -1
- package/bin/repl.js +86 -0
- package/bin/sign.js +45 -15
- package/bin/tracebom.js +5 -1
- package/bin/validate.js +84 -18
- package/bin/verify.js +155 -86
- package/data/helpers/init.gradle +46 -21
- package/data/remediations.json +61 -0
- package/data/rules/dependency-sources.yaml +67 -0
- package/data/rules/scala-evidence.yaml +115 -0
- package/lib/audit/index.js +38 -6
- package/lib/cli/index.js +113 -54
- package/lib/cli/jsBom.js +50 -29
- package/lib/cli/jvmBom.js +665 -138
- package/lib/cli/managedBom.js +320 -200
- package/lib/cli/nativeBom.js +139 -30
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +17 -9
- package/lib/core/fs.js +3 -2
- package/lib/core/httpClient.js +159 -24
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/runState.js +39 -0
- package/lib/core/toml.js +72 -0
- package/lib/ecosystems/asarutils.js +4 -2
- package/lib/ecosystems/bunutils.js +5 -7
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/cmakeResolver.js +10 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +337 -22
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1967 -788
- package/lib/ecosystems/golem.js +28 -12
- package/lib/ecosystems/gradleutils.js +314 -30
- package/lib/ecosystems/jsEvidence.js +85 -24
- package/lib/ecosystems/kosi.js +21 -4
- package/lib/ecosystems/npmutils.js +64 -0
- package/lib/ecosystems/parsers-dotnet.js +567 -151
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +324 -61
- package/lib/ecosystems/parsers-js.js +92 -26
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +204 -12
- package/lib/ecosystems/parsers-misc.js +182 -55
- package/lib/ecosystems/parsers-python.js +141 -10
- package/lib/ecosystems/parsers-rust.js +4 -4
- package/lib/ecosystems/parsers-terraform.js +1573 -19
- package/lib/ecosystems/pythonutils.js +102 -6
- package/lib/ecosystems/remote/huggingface.js +3 -0
- package/lib/ecosystems/rubyutils.js +67 -17
- package/lib/ecosystems/rusi.js +22 -9
- package/lib/ecosystems/sbtutils.js +243 -187
- package/lib/ecosystems/scalacliutils.js +342 -0
- package/lib/ecosystems/scalasem.js +2618 -0
- package/lib/ecosystems/terraformRegistry.js +288 -0
- package/lib/ecosystems/utils.js +2 -0
- package/lib/ecosystems/vendoredCode.js +156 -0
- package/lib/evinser/evinser.js +578 -69
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +576 -128
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/atomUtils.js +171 -48
- package/lib/inventory/auditCategories.js +7 -0
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/deps.js +501 -124
- package/lib/inventory/dosai.js +248 -44
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +52 -6
- package/lib/inventory/evidenceUtils.js +154 -109
- package/lib/inventory/fetchBatch.js +574 -38
- package/lib/inventory/fetchDiskCache.js +597 -0
- package/lib/inventory/forgeEnricher.js +14 -5
- package/lib/inventory/jvmLocalRepos.js +917 -0
- package/lib/inventory/mcpConfigParser.js +2 -3
- package/lib/inventory/parentSelection.js +146 -0
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +8 -8
- package/lib/inventory/spdx.js +101 -0
- package/lib/inventory/traceRunner.js +88 -7
- package/lib/inventory/tracedCrypto.js +294 -0
- package/lib/managers/docker.js +33 -32
- package/lib/managers/oci.js +24 -2
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +16 -2
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/strictJson.js +322 -0
- package/lib/parsers/terraformConfig.js +1073 -0
- package/lib/parsers/terraformSource.js +652 -0
- package/lib/server/server.js +23 -0
- package/lib/stages/postgen/introspection/markers.js +1 -1
- package/lib/stages/postgen/postgen.js +15 -1
- package/lib/stages/postgen/specVersionCompat.js +32 -0
- package/lib/validator/index.js +25 -10
- package/lib/validator/reporters/json.js +1 -0
- package/package.json +21 -21
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +24 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +7 -4
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +3 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +9 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/httpClient.d.ts +13 -8
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/pluginRun.d.ts +97 -0
- package/types/lib/core/pluginRun.d.ts.map +1 -0
- package/types/lib/core/processTree.d.ts +36 -0
- package/types/lib/core/processTree.d.ts.map +1 -0
- package/types/lib/core/runState.d.ts +29 -0
- package/types/lib/core/runState.d.ts.map +1 -0
- package/types/lib/core/toml.d.ts +20 -0
- package/types/lib/core/toml.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +12 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
- package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +18 -2
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +9 -3
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +62 -13
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +50 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmutils.d.ts +15 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +44 -2
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +6 -1
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +3 -1
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +53 -3
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +27 -2
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +21 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/ecosystems/sbtutils.d.ts +88 -2
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
- package/types/lib/ecosystems/scalasem.d.ts +311 -0
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +2 -2
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +75 -8
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +80 -4
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/atomUtils.d.ts +82 -10
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +3 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
- package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +2 -1
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
- package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +59 -1
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +57 -8
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts +53 -7
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +10 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +19 -4
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +83 -14
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
- package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/parentSelection.d.ts +34 -0
- package/types/lib/inventory/parentSelection.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts +80 -0
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +9 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +12 -0
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +42 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +3 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeCache.d.ts +16 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +2 -1
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
- package/types/lib/parsers/cmakePresets.d.ts +78 -0
- package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
- package/types/lib/parsers/compileCommands.d.ts +115 -0
- package/types/lib/parsers/compileCommands.d.ts.map +1 -0
- package/types/lib/parsers/strictJson.d.ts +46 -0
- package/types/lib/parsers/strictJson.d.ts.map +1 -0
- package/types/lib/parsers/terraformConfig.d.ts +70 -0
- package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
- package/types/lib/parsers/terraformSource.d.ts +66 -0
- package/types/lib/parsers/terraformSource.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +8 -0
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
readEnvironmentVariable,
|
|
19
19
|
} from "../core/activity.js";
|
|
20
20
|
import { PYTHON_CMD, PYTHON_EXCLUDED_COMPONENTS } from "../core/env.js";
|
|
21
|
-
import { safeExistsSync, safeSpawnSync } from "../core/fs.js";
|
|
21
|
+
import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
|
|
22
22
|
import { thoughtLog } from "../core/logger.js";
|
|
23
23
|
import { isWin } from "../core/paths.js";
|
|
24
24
|
import {
|
|
@@ -331,6 +331,70 @@ export function get_python_command_from_env(env) {
|
|
|
331
331
|
return fallbackCmd;
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
/** Directories that hold installed packages, not the project's own code. */
|
|
335
|
+
const INSTALLED_PACKAGE_DIRS = [
|
|
336
|
+
"**/site-packages/**",
|
|
337
|
+
"**/dist-packages/**",
|
|
338
|
+
"**/.venv/**",
|
|
339
|
+
"**/venv/**",
|
|
340
|
+
"**/.tox/**",
|
|
341
|
+
"**/.nox/**",
|
|
342
|
+
"**/__pypackages__/**",
|
|
343
|
+
"**/node_modules/**",
|
|
344
|
+
];
|
|
345
|
+
|
|
346
|
+
const projectModuleNamesCache = new Map();
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* The top-level packages and modules a project provides, wherever they sit
|
|
350
|
+
* in its tree: each outermost package directory (one with an `__init__.py`
|
|
351
|
+
* whose parent has none), and the module files beside such packages, since
|
|
352
|
+
* their directory is a source root. Directories of installed packages
|
|
353
|
+
* (virtual environments, `site-packages`) are not the project's.
|
|
354
|
+
*
|
|
355
|
+
* @param {string} src Path to the project being analysed
|
|
356
|
+
* @returns {Set<string>} Module names
|
|
357
|
+
*/
|
|
358
|
+
export function projectModuleNames(src) {
|
|
359
|
+
const root = resolve(src);
|
|
360
|
+
if (projectModuleNamesCache.has(root)) {
|
|
361
|
+
return projectModuleNamesCache.get(root);
|
|
362
|
+
}
|
|
363
|
+
const names = new Set();
|
|
364
|
+
const sourceRoots = new Set();
|
|
365
|
+
const inits = getAllFiles(root, "**/__init__.py", {
|
|
366
|
+
exclude: INSTALLED_PACKAGE_DIRS,
|
|
367
|
+
});
|
|
368
|
+
for (const init of inits) {
|
|
369
|
+
let pkgDir = dirname(resolve(init));
|
|
370
|
+
while (
|
|
371
|
+
dirname(pkgDir) !== root &&
|
|
372
|
+
dirname(pkgDir).startsWith(root) &&
|
|
373
|
+
safeExistsSync(join(dirname(pkgDir), "__init__.py"))
|
|
374
|
+
) {
|
|
375
|
+
pkgDir = dirname(pkgDir);
|
|
376
|
+
}
|
|
377
|
+
if (pkgDir === root) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
names.add(basename(pkgDir));
|
|
381
|
+
sourceRoots.add(dirname(pkgDir));
|
|
382
|
+
}
|
|
383
|
+
for (const dir of sourceRoots) {
|
|
384
|
+
try {
|
|
385
|
+
for (const f of readdirSync(dir)) {
|
|
386
|
+
if (f.endsWith(".py") && f !== "__init__.py") {
|
|
387
|
+
names.add(f.slice(0, -3));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
} catch {
|
|
391
|
+
// an unreadable directory provides nothing
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
projectModuleNamesCache.set(root, names);
|
|
395
|
+
return names;
|
|
396
|
+
}
|
|
397
|
+
|
|
334
398
|
/**
|
|
335
399
|
* Is this import satisfied by a module that lives in the project itself?
|
|
336
400
|
*
|
|
@@ -344,7 +408,9 @@ export function get_python_command_from_env(env) {
|
|
|
344
408
|
* filesystem whether the module is ours answers it exactly.
|
|
345
409
|
*
|
|
346
410
|
* Checks the project root and a `src/` layout for a module file, a package directory,
|
|
347
|
-
* and a PEP 420 namespace package directory
|
|
411
|
+
* and a PEP 420 namespace package directory, then the top-level packages found
|
|
412
|
+
* anywhere in the project and the modules beside them (tool-heavy repositories
|
|
413
|
+
* keep their Python libraries in places such as `dev_tools/pylibs/`).
|
|
348
414
|
*
|
|
349
415
|
* @param {string} src Path to the project being analysed
|
|
350
416
|
* @param {string} name Imported top-level module name
|
|
@@ -354,6 +420,9 @@ export function isFirstPartyModule(src, name) {
|
|
|
354
420
|
if (!src || !name || name.includes("/") || name.includes("\\")) {
|
|
355
421
|
return false;
|
|
356
422
|
}
|
|
423
|
+
if (projectModuleNames(src).has(name)) {
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
357
426
|
for (const root of [src, join(src, "src")]) {
|
|
358
427
|
if (
|
|
359
428
|
safeExistsSync(join(root, `${name}.py`)) ||
|
|
@@ -378,6 +447,21 @@ export function isFirstPartyModule(src, name) {
|
|
|
378
447
|
return false;
|
|
379
448
|
}
|
|
380
449
|
|
|
450
|
+
/**
|
|
451
|
+
* Whether a directory holds Python sources for atom to parse.
|
|
452
|
+
*
|
|
453
|
+
* The search skips the directories the manifest searches skip, such as
|
|
454
|
+
* node_modules and dot directories, and honours the exclude patterns, so a
|
|
455
|
+
* Python file shipped inside an npm package does not count.
|
|
456
|
+
*
|
|
457
|
+
* @param {string} src directory
|
|
458
|
+
* @param {Object} options CLI options
|
|
459
|
+
* @returns {boolean} true when the directory holds at least one Python file
|
|
460
|
+
*/
|
|
461
|
+
export function hasPythonSources(src, options = {}) {
|
|
462
|
+
return getAllFiles(src, "**/*.py", options).length > 0;
|
|
463
|
+
}
|
|
464
|
+
|
|
381
465
|
/**
|
|
382
466
|
* Method to find python modules by parsing the imports and then checking with PyPI to obtain the latest version
|
|
383
467
|
*
|
|
@@ -390,9 +474,11 @@ export async function getPyModules(src, epkgList, options) {
|
|
|
390
474
|
const allImports = {};
|
|
391
475
|
const dependenciesList = [];
|
|
392
476
|
let modList = [];
|
|
393
|
-
const
|
|
394
|
-
options.depsSlicesFile || options.usagesSlicesFile
|
|
395
|
-
|
|
477
|
+
const requestedSlicesFile =
|
|
478
|
+
options.depsSlicesFile || options.usagesSlicesFile;
|
|
479
|
+
let slicesFile = requestedSlicesFile
|
|
480
|
+
? resolve(requestedSlicesFile)
|
|
481
|
+
: undefined;
|
|
396
482
|
// Issue: 615 fix. Reuse existing slices file
|
|
397
483
|
if (slicesFile && safeExistsSync(slicesFile)) {
|
|
398
484
|
const slicesData = JSON.parse(readFileSync(slicesFile, "utf-8"));
|
|
@@ -401,8 +487,18 @@ export async function getPyModules(src, epkgList, options) {
|
|
|
401
487
|
} else {
|
|
402
488
|
modList = slicesData;
|
|
403
489
|
}
|
|
404
|
-
} else {
|
|
490
|
+
} else if (hasPythonSources(src, options)) {
|
|
491
|
+
// A new slices file is kept where it was asked for only when the evidence
|
|
492
|
+
// step will read it again; otherwise atom writes it to a temporary
|
|
493
|
+
// directory instead of the working directory.
|
|
494
|
+
if (!options.evidence) {
|
|
495
|
+
slicesFile = undefined;
|
|
496
|
+
}
|
|
405
497
|
modList = findAppModules(src, "python", "parsedeps", slicesFile, options);
|
|
498
|
+
} else {
|
|
499
|
+
thoughtLog(
|
|
500
|
+
`There are no Python sources at '${src}', so atom parsedeps has nothing to read.`,
|
|
501
|
+
);
|
|
406
502
|
}
|
|
407
503
|
const pyDefaultModules = new Set(PYTHON_STD_MODULES);
|
|
408
504
|
modList = modList.filter(
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
recordActivity,
|
|
6
6
|
} from "../../core/activity.js";
|
|
7
7
|
import { sanitizeStructuredValueForBom } from "../../core/propertySanitizer.js";
|
|
8
|
+
import { registerRunReset } from "../../core/runState.js";
|
|
8
9
|
import {
|
|
9
10
|
detectAiModelVariants,
|
|
10
11
|
normalizeDetectedVariants,
|
|
@@ -167,6 +168,8 @@ export function resetHuggingFaceRemoteCaches() {
|
|
|
167
168
|
payloadCache.clear();
|
|
168
169
|
}
|
|
169
170
|
|
|
171
|
+
registerRunReset("huggingface:responses", resetHuggingFaceRemoteCaches);
|
|
172
|
+
|
|
170
173
|
const normalizeLicenseFilePath = (licensePath) =>
|
|
171
174
|
String(licensePath || "")
|
|
172
175
|
.trim()
|
|
@@ -15,17 +15,14 @@ import { build, Purl } from "@cdxgen/cdx-purl";
|
|
|
15
15
|
|
|
16
16
|
// utils.js does not import rubyutils.js, so importing from it here is safe and
|
|
17
17
|
// does not introduce a cyclic dependency.
|
|
18
|
-
import {
|
|
19
|
-
cdxgenAgent,
|
|
20
|
-
DEBUG_MODE,
|
|
21
|
-
readEnvironmentVariable,
|
|
22
|
-
} from "../core/activity.js";
|
|
18
|
+
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
23
19
|
import { shouldFetchLicense } from "../core/env.js";
|
|
24
20
|
import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
|
|
25
21
|
import { thoughtLog } from "../core/logger.js";
|
|
26
22
|
import { dirNameStr, isWin } from "../core/paths.js";
|
|
27
23
|
import { mergeDependencies } from "../inventory/depsUtils.js";
|
|
28
24
|
import {
|
|
25
|
+
gatedGet,
|
|
29
26
|
prefetchEnabled,
|
|
30
27
|
prefetchedResponse,
|
|
31
28
|
prefetchJson,
|
|
@@ -913,6 +910,9 @@ export async function enrichGemsFromLocalCache(pkgList, options = {}) {
|
|
|
913
910
|
installedPkgs = await parseGemspecData(
|
|
914
911
|
readFileSync(gemspecFile, { encoding: "utf-8" }),
|
|
915
912
|
gemspecFile,
|
|
913
|
+
// The gemspec is read only for the fields it holds; the registry
|
|
914
|
+
// round the caller is about to make answers the rest.
|
|
915
|
+
{ noFetch: true },
|
|
916
916
|
);
|
|
917
917
|
} catch (_err) {
|
|
918
918
|
// pass
|
|
@@ -983,16 +983,21 @@ function applyGemMetadata(p, body) {
|
|
|
983
983
|
p.properties.push({ name, value: `${value}` });
|
|
984
984
|
}
|
|
985
985
|
};
|
|
986
|
-
|
|
987
|
-
|
|
986
|
+
// The registry fills only what the lockfile, the gemspec and the caches on
|
|
987
|
+
// this machine left open, so a local answer survives the round.
|
|
988
|
+
if (!p.description?.length && (body.description || body.summary)) {
|
|
989
|
+
p.description = body.description || body.summary;
|
|
990
|
+
}
|
|
991
|
+
if (body.licenses && !p.license) {
|
|
988
992
|
p.license = body.licenses;
|
|
989
993
|
}
|
|
990
994
|
if (body.metadata) {
|
|
991
|
-
if (body.metadata.source_code_uri) {
|
|
995
|
+
if (body.metadata.source_code_uri && !p.repository) {
|
|
992
996
|
p.repository = { url: body.metadata.source_code_uri };
|
|
993
997
|
if (
|
|
994
998
|
body.homepage_uri &&
|
|
995
|
-
body.homepage_uri !== body.metadata.source_code_uri
|
|
999
|
+
body.homepage_uri !== body.metadata.source_code_uri &&
|
|
1000
|
+
!p.homepage
|
|
996
1001
|
) {
|
|
997
1002
|
p.homepage = { url: body.homepage_uri };
|
|
998
1003
|
}
|
|
@@ -1033,7 +1038,7 @@ function applyGemMetadata(p, body) {
|
|
|
1033
1038
|
if (!p.externalReferences.length) {
|
|
1034
1039
|
p.externalReferences = undefined;
|
|
1035
1040
|
}
|
|
1036
|
-
if (body.sha) {
|
|
1041
|
+
if (body.sha && !p._integrity && !p.hashes?.length) {
|
|
1037
1042
|
p._integrity = `sha256-${body.sha}`;
|
|
1038
1043
|
}
|
|
1039
1044
|
// RubyGems reports the authors as a comma separated string. It is split into
|
|
@@ -1173,7 +1178,17 @@ export async function getRubyGemsMetadata(pkgList) {
|
|
|
1173
1178
|
for (const [name, pkgs] of Object.entries(pkgsByName)) {
|
|
1174
1179
|
const versionedPkgs = pkgs.filter((p) => p.version);
|
|
1175
1180
|
if (versionedPkgs.length > 1) {
|
|
1181
|
+
// The listing answers every versioned variant of this gem in one
|
|
1182
|
+
// request. A direct URL is asked for only an entry the listing does
|
|
1183
|
+
// not answer, so it is not prefetched here: the serial path below
|
|
1184
|
+
// requests one when the listing misses.
|
|
1176
1185
|
addBatchUrl(`${RUBYGEMS_V1_VERSIONS_URL}${name}.json`);
|
|
1186
|
+
for (const p of pkgs) {
|
|
1187
|
+
if (!p.version) {
|
|
1188
|
+
addBatchUrl(gemDirectUrl(p, RUBYGEMS_V2_URL, RUBYGEMS_V1_URL));
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
continue;
|
|
1177
1192
|
}
|
|
1178
1193
|
for (const p of pkgs) {
|
|
1179
1194
|
addBatchUrl(gemDirectUrl(p, RUBYGEMS_V2_URL, RUBYGEMS_V1_URL));
|
|
@@ -1201,7 +1216,7 @@ export async function getRubyGemsMetadata(pkgList) {
|
|
|
1201
1216
|
}
|
|
1202
1217
|
const res =
|
|
1203
1218
|
prefetchedResponse(prefetched, versionsUrl) ||
|
|
1204
|
-
(await
|
|
1219
|
+
(await gatedGet(versionsUrl, apiOptions));
|
|
1205
1220
|
versions = res.body;
|
|
1206
1221
|
}
|
|
1207
1222
|
if (Array.isArray(versions) && versions.length) {
|
|
@@ -1280,7 +1295,7 @@ async function enrichGemFromVersionEndpoint(
|
|
|
1280
1295
|
}
|
|
1281
1296
|
const res =
|
|
1282
1297
|
prefetchedResponse(prefetched, fullUrl) ||
|
|
1283
|
-
(await
|
|
1298
|
+
(await gatedGet(fullUrl, apiOptions));
|
|
1284
1299
|
let body = res.body;
|
|
1285
1300
|
if (body?.length) {
|
|
1286
1301
|
body = body[0];
|
|
@@ -1565,6 +1580,12 @@ function listGemBindirFiles(gemspecFile, bindir = "bin") {
|
|
|
1565
1580
|
* @param {Object} [options] Parse options
|
|
1566
1581
|
* @param {Object<string, string>} [options.lockedVersions] Locked versions of
|
|
1567
1582
|
* the gems the project directory serves, by gem name
|
|
1583
|
+
* @param {boolean} [options.projectGemspec] The gemspec describes the project
|
|
1584
|
+
* being scanned. No registry holds the project, so its gem is never looked
|
|
1585
|
+
* up and keeps what the gemspec says.
|
|
1586
|
+
* @param {boolean} [options.noFetch] Read the gemspec for the fields it holds
|
|
1587
|
+
* without asking the registry about the gem. The local cache enricher uses
|
|
1588
|
+
* this, since the caller is responsible for the registry round.
|
|
1568
1589
|
*/
|
|
1569
1590
|
export async function parseGemspecData(gemspecData, gemspecFile, options = {}) {
|
|
1570
1591
|
let pkgList = [];
|
|
@@ -1983,7 +2004,7 @@ export async function parseGemspecData(gemspecData, gemspecFile, options = {}) {
|
|
|
1983
2004
|
} else {
|
|
1984
2005
|
console.log("Unable to parse", gemspecData, gemspecFile);
|
|
1985
2006
|
}
|
|
1986
|
-
if (shouldFetchLicense()) {
|
|
2007
|
+
if (shouldFetchLicense() && !options.projectGemspec && !options.noFetch) {
|
|
1987
2008
|
return await getRubyGemsMetadata(pkgList);
|
|
1988
2009
|
}
|
|
1989
2010
|
return pkgList;
|
|
@@ -1997,11 +2018,24 @@ export async function parseGemspecData(gemspecData, gemspecFile, options = {}) {
|
|
|
1997
2018
|
* directory (`PATH` with `remote: .`), which is how Bundler records the gem a
|
|
1998
2019
|
* project builds when its Gemfile uses the `gemspec` directive.
|
|
1999
2020
|
*
|
|
2021
|
+
* Gems the lockfile serves from a git remote or from a path outside the
|
|
2022
|
+
* project are never sent to rubygems.org: no public registry holds the release
|
|
2023
|
+
* they pinned. Before the registry round, the caches on this machine are read
|
|
2024
|
+
* first, so a gem whose installed gemspec or compact index entry is present
|
|
2025
|
+
* keeps those answers.
|
|
2026
|
+
*
|
|
2000
2027
|
* @param {object} gemLockData Gemfile.lock data
|
|
2001
2028
|
* @param {string} lockFile Lock file
|
|
2029
|
+
* @param {object} [options] Options
|
|
2030
|
+
* @param {string} [options.gemHome] GEM_HOME to read installed gemspecs from
|
|
2031
|
+
* @param {string} [options.compactIndexCacheDir] Bundler compact index cache
|
|
2002
2032
|
*/
|
|
2003
|
-
export async function parseGemfileLockData(
|
|
2004
|
-
|
|
2033
|
+
export async function parseGemfileLockData(
|
|
2034
|
+
gemLockData,
|
|
2035
|
+
lockFile,
|
|
2036
|
+
options = {},
|
|
2037
|
+
) {
|
|
2038
|
+
const pkgList = [];
|
|
2005
2039
|
const pkgnames = {};
|
|
2006
2040
|
const dependenciesList = [];
|
|
2007
2041
|
const dependenciesMap = {};
|
|
@@ -2207,13 +2241,16 @@ export async function parseGemfileLockData(gemLockData, lockFile) {
|
|
|
2207
2241
|
}
|
|
2208
2242
|
// Bundler locks every gem against exactly one source, so the gem's
|
|
2209
2243
|
// own top-level line is where its remote belongs. A later duplicate
|
|
2210
|
-
// sighting of the same name would be the same release.
|
|
2244
|
+
// sighting of the same name would be the same release. The section
|
|
2245
|
+
// is kept as well: a gem under GIT or PATH is served from a source
|
|
2246
|
+
// no public registry holds.
|
|
2211
2247
|
if (!gemSourceInfo[name]) {
|
|
2212
2248
|
gemSourceInfo[name] = {
|
|
2213
2249
|
remote: lastRemote,
|
|
2214
2250
|
revision: lastRevision,
|
|
2215
2251
|
branch: lastBranch,
|
|
2216
2252
|
tag: lastTag,
|
|
2253
|
+
section: lastSection,
|
|
2217
2254
|
};
|
|
2218
2255
|
}
|
|
2219
2256
|
}
|
|
@@ -2369,7 +2406,20 @@ export async function parseGemfileLockData(gemLockData, lockFile) {
|
|
|
2369
2406
|
});
|
|
2370
2407
|
}
|
|
2371
2408
|
if (shouldFetchLicense()) {
|
|
2372
|
-
|
|
2409
|
+
// The caches on this machine answer first: the installed gemspec holds
|
|
2410
|
+
// the licence the registry would be asked for, and the compact index the
|
|
2411
|
+
// checksum, so the registry round below only fills what is still missing.
|
|
2412
|
+
await enrichGemsFromLocalCache(pkgList, options);
|
|
2413
|
+
// The gem the lockfile serves from the project's own directory is the
|
|
2414
|
+
// project itself, and a gem under GIT or PATH is served from a source no
|
|
2415
|
+
// public registry holds; only the rest are looked up.
|
|
2416
|
+
const lookupList = pkgList.filter(
|
|
2417
|
+
(p) =>
|
|
2418
|
+
!projectGemRefs.includes(p["bom-ref"]) &&
|
|
2419
|
+
gemSourceInfo[p.name]?.section !== "GIT" &&
|
|
2420
|
+
gemSourceInfo[p.name]?.section !== "PATH",
|
|
2421
|
+
);
|
|
2422
|
+
await getRubyGemsMetadata(lookupList);
|
|
2373
2423
|
}
|
|
2374
2424
|
return { pkgList, dependenciesList, rootList, projectGemRefs };
|
|
2375
2425
|
}
|
package/lib/ecosystems/rusi.js
CHANGED
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
safeSpawnSync,
|
|
11
11
|
} from "../core/fs.js";
|
|
12
12
|
import { dirNameStr } from "../core/paths.js";
|
|
13
|
+
import {
|
|
14
|
+
reportPluginRunFailure,
|
|
15
|
+
resolvePluginSourceDir,
|
|
16
|
+
} from "../core/pluginRun.js";
|
|
13
17
|
import { applyAlgorithmProperties } from "../inventory/cryptoAlgorithmFamily.js";
|
|
14
18
|
import { resolvePluginBinary } from "../inventory/plugins.js";
|
|
15
19
|
|
|
@@ -818,8 +822,14 @@ export function runRusiAnalysis(src, outputFile, options = {}) {
|
|
|
818
822
|
return false;
|
|
819
823
|
}
|
|
820
824
|
|
|
825
|
+
// cdxgen may run with its working directory already inside the project
|
|
826
|
+
// while the source argument is relative to a repository root; a plain
|
|
827
|
+
// resolve would join the two into a directory that does not exist. The
|
|
828
|
+
// helper checks the result and falls back to the working directory when it
|
|
829
|
+
// is itself the cargo project under analysis.
|
|
830
|
+
const analysisDir = resolvePluginSourceDir(src, ["Cargo.toml"]);
|
|
821
831
|
const rusiMode = options.rusiMode === "cryptos" ? "cryptos" : "analyze";
|
|
822
|
-
const args = [rusiMode, "--dir",
|
|
832
|
+
const args = [rusiMode, "--dir", analysisDir, "--out", resolve(outputFile)];
|
|
823
833
|
|
|
824
834
|
// Set callgraph and data-flow args
|
|
825
835
|
args.push("--callgraph", options.rusiCallgraph || "static");
|
|
@@ -850,18 +860,21 @@ export function runRusiAnalysis(src, outputFile, options = {}) {
|
|
|
850
860
|
}
|
|
851
861
|
|
|
852
862
|
const result = safeSpawnSync(executable, args, {
|
|
853
|
-
cwd:
|
|
863
|
+
cwd: analysisDir,
|
|
854
864
|
shell: false,
|
|
855
865
|
});
|
|
856
866
|
|
|
857
867
|
if (result?.status !== 0 || result?.error || !safeExistsSync(outputFile)) {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
868
|
+
reportPluginRunFailure({
|
|
869
|
+
tool: "rusi",
|
|
870
|
+
ecosystem: "rust",
|
|
871
|
+
executable,
|
|
872
|
+
args,
|
|
873
|
+
dir: analysisDir,
|
|
874
|
+
result,
|
|
875
|
+
outputFile,
|
|
876
|
+
options,
|
|
877
|
+
});
|
|
865
878
|
return false;
|
|
866
879
|
}
|
|
867
880
|
return true;
|