@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
|
@@ -90,8 +90,11 @@ const isVendoredArtifactPath = (filePath) => {
|
|
|
90
90
|
};
|
|
91
91
|
const GGUF_MIN_ALIGNMENT = 4;
|
|
92
92
|
const GGUF_MAX_ALIGNMENT = 1024 * 1024;
|
|
93
|
+
// Tested against full paths. The config exceptions follow IGNORE_FILE_PATTERN
|
|
94
|
+
// in analyzer.js, with the app exception anchored to a path separator instead
|
|
95
|
+
// of the start of a file name.
|
|
93
96
|
const IGNORE_SOURCE_FILE_PATTERN =
|
|
94
|
-
/(^|\/|\\)(__tests__|fixtures?|examples?|samples?)($|\/|\\)|(^|\/|\\)(test|spec|mock|setup-jest|conftest|sitecustomize)\.(
|
|
97
|
+
/(^|\/|\\)(__tests__|fixtures?|examples?|samples?)($|\/|\\)|(^|\/|\\)(test|spec|mock|setup-jest|conftest|sitecustomize)\.([cm]?[jt]sx?|py)$|(?<!vite\.|vue\.|svelte\.|astro\.|(?:^|\/|\\)app\.)(conf|config)\.[cm]?[jt]sx?$/iu;
|
|
95
98
|
const HOST_PROVIDER_PATTERNS = [
|
|
96
99
|
["openai", /(?:^|\.)openai\.com$/iu],
|
|
97
100
|
["anthropic", /(?:^|\.)anthropic\.com$/iu],
|
|
@@ -68,9 +68,19 @@ const IGNORE_DIRS = readEnvironmentVariable("ASTGEN_IGNORE_DIRS")
|
|
|
68
68
|
"coverage",
|
|
69
69
|
];
|
|
70
70
|
|
|
71
|
+
// The pattern is tested against file names. Config files are skipped because
|
|
72
|
+
// their imports are mostly build and test tooling. The exceptions hold code the
|
|
73
|
+
// application is built from: the Vite, Vue CLI, Svelte, and Astro configs name
|
|
74
|
+
// the build plugins and integrations the app needs, and app.config.* holds
|
|
75
|
+
// application code, such as the root providers of an Angular app. The app
|
|
76
|
+
// exception is anchored to the start of the name, so names such as
|
|
77
|
+
// webapp.config.ts are still skipped. [cm]?[jt]sx? covers every JavaScript and
|
|
78
|
+
// TypeScript module extension, as the default test globs of Jest and Vitest do.
|
|
79
|
+
// Keep the config exceptions in step with IGNORE_SOURCE_FILE_PATTERN in
|
|
80
|
+
// aiCollector.js.
|
|
71
81
|
const IGNORE_FILE_PATTERN = new RegExp(
|
|
72
82
|
readEnvironmentVariable("ASTGEN_IGNORE_FILE_PATTERN") ||
|
|
73
|
-
"(test|spec|mock|setup-jest|\\.d)\\.(
|
|
83
|
+
"(test|spec|mock|setup-jest|\\.d)\\.[cm]?[jt]sx?$|(?<!vite\\.|vue\\.|svelte\\.|astro\\.|^app\\.)(conf|config)\\.[cm]?[jt]sx?$",
|
|
74
84
|
"i",
|
|
75
85
|
);
|
|
76
86
|
|
|
@@ -210,6 +220,46 @@ const getAllFiles = (
|
|
|
210
220
|
return result;
|
|
211
221
|
};
|
|
212
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Walk a directory tree once and return the files whose names end with any of
|
|
225
|
+
* the given extensions.
|
|
226
|
+
*
|
|
227
|
+
* Files are grouped by extension in the order of `extensions`, and each group
|
|
228
|
+
* keeps the walk order. That is the order one walk per extension produced, and
|
|
229
|
+
* occurrences reach the BOM in it.
|
|
230
|
+
*
|
|
231
|
+
* @param {string} dir Directory to walk
|
|
232
|
+
* @param {string[]} extensions File extensions, each with its leading dot
|
|
233
|
+
* @param {boolean|Object} deepOrOptions Deep flag, or `{ deep, exclude, noIgnore }`
|
|
234
|
+
* @returns {string[]} Matching file paths
|
|
235
|
+
*/
|
|
236
|
+
const getAllFilesByExtensions = (dir, extensions, deepOrOptions) => {
|
|
237
|
+
const searchOptions = normalizeAnalyzerSearchOptions(deepOrOptions);
|
|
238
|
+
const files = getAllFiles(
|
|
239
|
+
searchOptions.deep,
|
|
240
|
+
dir,
|
|
241
|
+
undefined,
|
|
242
|
+
undefined,
|
|
243
|
+
undefined,
|
|
244
|
+
new RegExp(
|
|
245
|
+
`(?:${extensions.map((extension) => `\\${extension}`).join("|")})$`,
|
|
246
|
+
),
|
|
247
|
+
dir,
|
|
248
|
+
searchOptions.exclude,
|
|
249
|
+
searchOptions.noIgnore,
|
|
250
|
+
);
|
|
251
|
+
const filesByExtension = extensions.map(() => []);
|
|
252
|
+
for (const file of files) {
|
|
253
|
+
const extensionIndex = extensions.findIndex((extension) =>
|
|
254
|
+
file.endsWith(extension),
|
|
255
|
+
);
|
|
256
|
+
if (extensionIndex !== -1) {
|
|
257
|
+
filesByExtension[extensionIndex].push(file);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return filesByExtension.flat();
|
|
261
|
+
};
|
|
262
|
+
|
|
213
263
|
const babelParserOptions = {
|
|
214
264
|
sourceType: "unambiguous",
|
|
215
265
|
allowImportExportEverywhere: true,
|
|
@@ -1752,37 +1802,29 @@ export const parseFileASTTreeCollected = (src, file) => {
|
|
|
1752
1802
|
return { imports, exports };
|
|
1753
1803
|
};
|
|
1754
1804
|
|
|
1805
|
+
const JS_TS_SOURCE_EXTENSIONS = [
|
|
1806
|
+
".js",
|
|
1807
|
+
".jsx",
|
|
1808
|
+
".cjs",
|
|
1809
|
+
".mjs",
|
|
1810
|
+
".ts",
|
|
1811
|
+
".tsx",
|
|
1812
|
+
".mts",
|
|
1813
|
+
".cts",
|
|
1814
|
+
".vue",
|
|
1815
|
+
".svelte",
|
|
1816
|
+
];
|
|
1817
|
+
|
|
1755
1818
|
/**
|
|
1756
|
-
* Return paths to all
|
|
1819
|
+
* Return paths to all JavaScript, TypeScript, Vue, and Svelte source files,
|
|
1820
|
+
* found in one walk of the tree.
|
|
1821
|
+
*
|
|
1822
|
+
* @param {string} src Directory to walk
|
|
1823
|
+
* @param {boolean|Object} deep Deep flag, or `{ deep, exclude, noIgnore }`
|
|
1824
|
+
* @returns {string[]} Source file paths, grouped by extension
|
|
1757
1825
|
*/
|
|
1758
1826
|
const getAllSrcJSAndTSFiles = (src, deep) =>
|
|
1759
|
-
|
|
1760
|
-
[
|
|
1761
|
-
".js",
|
|
1762
|
-
".jsx",
|
|
1763
|
-
".cjs",
|
|
1764
|
-
".mjs",
|
|
1765
|
-
".ts",
|
|
1766
|
-
".tsx",
|
|
1767
|
-
".mts",
|
|
1768
|
-
".cts",
|
|
1769
|
-
".vue",
|
|
1770
|
-
".svelte",
|
|
1771
|
-
].map((extension) => {
|
|
1772
|
-
const searchOptions = normalizeAnalyzerSearchOptions(deep);
|
|
1773
|
-
return getAllFiles(
|
|
1774
|
-
searchOptions.deep,
|
|
1775
|
-
src,
|
|
1776
|
-
extension,
|
|
1777
|
-
undefined,
|
|
1778
|
-
undefined,
|
|
1779
|
-
undefined,
|
|
1780
|
-
src,
|
|
1781
|
-
searchOptions.exclude,
|
|
1782
|
-
searchOptions.noIgnore,
|
|
1783
|
-
);
|
|
1784
|
-
}),
|
|
1785
|
-
);
|
|
1827
|
+
getAllFilesByExtensions(src, JS_TS_SOURCE_EXTENSIONS, deep);
|
|
1786
1828
|
|
|
1787
1829
|
const getAngularWorkspaceManifestFiles = (
|
|
1788
1830
|
dir,
|
|
@@ -2139,51 +2181,42 @@ const parseAngularStyleFiles = (
|
|
|
2139
2181
|
excludePatterns,
|
|
2140
2182
|
noIgnore = false,
|
|
2141
2183
|
) => {
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
for (const
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
continue;
|
|
2160
|
-
}
|
|
2161
|
-
for (const referencePattern of STYLE_PACKAGE_REFERENCE_PATTERNS) {
|
|
2162
|
-
for (const match of content.matchAll(referencePattern)) {
|
|
2163
|
-
const reference = match[1];
|
|
2164
|
-
if (!reference) {
|
|
2165
|
-
continue;
|
|
2166
|
-
}
|
|
2167
|
-
if (
|
|
2168
|
-
match[0]?.trim().startsWith("url") &&
|
|
2169
|
-
!isPackageStyleUrlReference(reference)
|
|
2170
|
-
) {
|
|
2171
|
-
continue;
|
|
2172
|
-
}
|
|
2173
|
-
const prefix = content.slice(0, match.index || 0);
|
|
2174
|
-
const lineNumber = prefix.split(/\r?\n/).length;
|
|
2175
|
-
const lineStart = prefix.lastIndexOf("\n");
|
|
2176
|
-
const columnNumber =
|
|
2177
|
-
lineStart >= 0 ? prefix.length - lineStart - 1 : 0;
|
|
2178
|
-
setAngularPackageRef(
|
|
2179
|
-
allImports,
|
|
2180
|
-
allExports,
|
|
2181
|
-
src,
|
|
2182
|
-
styleFile,
|
|
2183
|
-
reference,
|
|
2184
|
-
{ column: columnNumber, line: lineNumber },
|
|
2185
|
-
);
|
|
2184
|
+
const styleFiles = getAllFilesByExtensions(
|
|
2185
|
+
src,
|
|
2186
|
+
ANGULAR_STYLE_FILE_EXTENSIONS,
|
|
2187
|
+
{ deep, exclude: excludePatterns, noIgnore },
|
|
2188
|
+
);
|
|
2189
|
+
for (const styleFile of styleFiles) {
|
|
2190
|
+
let content;
|
|
2191
|
+
try {
|
|
2192
|
+
content = readFileSync(styleFile, "utf-8");
|
|
2193
|
+
} catch {
|
|
2194
|
+
continue;
|
|
2195
|
+
}
|
|
2196
|
+
for (const referencePattern of STYLE_PACKAGE_REFERENCE_PATTERNS) {
|
|
2197
|
+
for (const match of content.matchAll(referencePattern)) {
|
|
2198
|
+
const reference = match[1];
|
|
2199
|
+
if (!reference) {
|
|
2200
|
+
continue;
|
|
2186
2201
|
}
|
|
2202
|
+
if (
|
|
2203
|
+
match[0]?.trim().startsWith("url") &&
|
|
2204
|
+
!isPackageStyleUrlReference(reference)
|
|
2205
|
+
) {
|
|
2206
|
+
continue;
|
|
2207
|
+
}
|
|
2208
|
+
const prefix = content.slice(0, match.index || 0);
|
|
2209
|
+
const lineNumber = prefix.split(/\r?\n/).length;
|
|
2210
|
+
const lineStart = prefix.lastIndexOf("\n");
|
|
2211
|
+
const columnNumber = lineStart >= 0 ? prefix.length - lineStart - 1 : 0;
|
|
2212
|
+
setAngularPackageRef(
|
|
2213
|
+
allImports,
|
|
2214
|
+
allExports,
|
|
2215
|
+
src,
|
|
2216
|
+
styleFile,
|
|
2217
|
+
reference,
|
|
2218
|
+
{ column: columnNumber, line: lineNumber },
|
|
2219
|
+
);
|
|
2187
2220
|
}
|
|
2188
2221
|
}
|
|
2189
2222
|
}
|
|
@@ -3478,8 +3511,7 @@ export const findJSImportsExports = async (src, deep) => {
|
|
|
3478
3511
|
// scope of astWorker.js. Absence is silent — tier 1 covers all scope
|
|
3479
3512
|
// evidence.
|
|
3480
3513
|
await primeSvelteParser();
|
|
3481
|
-
const
|
|
3482
|
-
const srcFiles = promiseMap.flat();
|
|
3514
|
+
const srcFiles = getAllSrcJSAndTSFiles(src, deep);
|
|
3483
3515
|
const tasks = srcFiles.map((file) => ({ src, file }));
|
|
3484
3516
|
const parallelWorthwhile =
|
|
3485
3517
|
totalSourceBytes(srcFiles) >= MIN_PARALLEL_PARSE_BYTES;
|
|
@@ -4580,8 +4612,7 @@ export const analyzeJsCryptoFile = (filePath) => {
|
|
|
4580
4612
|
export const detectJsCryptoInventory = async (src, deep = false) => {
|
|
4581
4613
|
let srcFiles = [];
|
|
4582
4614
|
try {
|
|
4583
|
-
|
|
4584
|
-
srcFiles = promiseMap.flat();
|
|
4615
|
+
srcFiles = getAllSrcJSAndTSFiles(src, deep);
|
|
4585
4616
|
} catch {
|
|
4586
4617
|
return { algorithms: [], libraries: [] };
|
|
4587
4618
|
}
|
|
@@ -4626,31 +4657,7 @@ export const detectExtensionCapabilities = (src, deep = false) => {
|
|
|
4626
4657
|
}
|
|
4627
4658
|
let srcFiles = [];
|
|
4628
4659
|
try {
|
|
4629
|
-
|
|
4630
|
-
srcFiles = [
|
|
4631
|
-
".js",
|
|
4632
|
-
".jsx",
|
|
4633
|
-
".cjs",
|
|
4634
|
-
".mjs",
|
|
4635
|
-
".ts",
|
|
4636
|
-
".tsx",
|
|
4637
|
-
".mts",
|
|
4638
|
-
".cts",
|
|
4639
|
-
".vue",
|
|
4640
|
-
".svelte",
|
|
4641
|
-
].flatMap((extension) =>
|
|
4642
|
-
getAllFiles(
|
|
4643
|
-
searchOptions.deep,
|
|
4644
|
-
src,
|
|
4645
|
-
extension,
|
|
4646
|
-
undefined,
|
|
4647
|
-
undefined,
|
|
4648
|
-
undefined,
|
|
4649
|
-
src,
|
|
4650
|
-
searchOptions.exclude,
|
|
4651
|
-
searchOptions.noIgnore,
|
|
4652
|
-
),
|
|
4653
|
-
);
|
|
4660
|
+
srcFiles = getAllSrcJSAndTSFiles(src, deep);
|
|
4654
4661
|
} catch (_err) {
|
|
4655
4662
|
return { capabilities: [], indicators: {} };
|
|
4656
4663
|
}
|
|
@@ -5857,31 +5864,7 @@ export const detectMcpInventory = (src, deep = false) => {
|
|
|
5857
5864
|
const servicesByKey = new Map();
|
|
5858
5865
|
let srcFiles = [];
|
|
5859
5866
|
try {
|
|
5860
|
-
|
|
5861
|
-
srcFiles = [
|
|
5862
|
-
".js",
|
|
5863
|
-
".jsx",
|
|
5864
|
-
".cjs",
|
|
5865
|
-
".mjs",
|
|
5866
|
-
".ts",
|
|
5867
|
-
".tsx",
|
|
5868
|
-
".mts",
|
|
5869
|
-
".cts",
|
|
5870
|
-
".vue",
|
|
5871
|
-
".svelte",
|
|
5872
|
-
].flatMap((extension) =>
|
|
5873
|
-
getAllFiles(
|
|
5874
|
-
searchOptions.deep,
|
|
5875
|
-
src,
|
|
5876
|
-
extension,
|
|
5877
|
-
undefined,
|
|
5878
|
-
undefined,
|
|
5879
|
-
undefined,
|
|
5880
|
-
src,
|
|
5881
|
-
searchOptions.exclude,
|
|
5882
|
-
searchOptions.noIgnore,
|
|
5883
|
-
),
|
|
5884
|
-
);
|
|
5867
|
+
srcFiles = getAllSrcJSAndTSFiles(src, deep);
|
|
5885
5868
|
} catch {
|
|
5886
5869
|
return { components: [], dependencies: [], services: [] };
|
|
5887
5870
|
}
|
|
@@ -6,7 +6,13 @@ import {
|
|
|
6
6
|
statSync,
|
|
7
7
|
} from "node:fs";
|
|
8
8
|
import { tmpdir, totalmem } from "node:os";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
delimiter as _delimiter,
|
|
11
|
+
basename,
|
|
12
|
+
dirname,
|
|
13
|
+
join,
|
|
14
|
+
resolve,
|
|
15
|
+
} from "node:path";
|
|
10
16
|
import process from "node:process";
|
|
11
17
|
|
|
12
18
|
import {
|
|
@@ -23,7 +29,9 @@ import {
|
|
|
23
29
|
} from "../core/fs.js";
|
|
24
30
|
import { TRACE_MODE } from "../core/logger.js";
|
|
25
31
|
import { dirNameStr, isWin } from "../core/paths.js";
|
|
32
|
+
import { formatDuration, reapProcessTree } from "../core/processTree.js";
|
|
26
33
|
import { readJsonFile } from "../parsers/largeJson.js";
|
|
34
|
+
import { cmakeBuildDirCandidates } from "./cmakeBuildDirs.js";
|
|
27
35
|
|
|
28
36
|
const ASTGEN_DEFAULT_IGNORE_DIRS = [
|
|
29
37
|
"venv",
|
|
@@ -83,9 +91,6 @@ const ATOM_C_LANGUAGES = new Set([
|
|
|
83
91
|
|
|
84
92
|
const COMPILE_COMMANDS_FILE = "compile_commands.json";
|
|
85
93
|
|
|
86
|
-
/** Build directories, under the scan root, searched for a compilation database. */
|
|
87
|
-
const COMPILE_COMMANDS_BUILD_DIRS = ["build", "out", "builddir"];
|
|
88
|
-
|
|
89
94
|
/**
|
|
90
95
|
* Characters a Windows shell command line would interpret: `&`, `|`, `<` and
|
|
91
96
|
* `>` chain or redirect commands, `%` expands variables even inside quotes,
|
|
@@ -117,9 +122,12 @@ function compileCommandsIn(dir) {
|
|
|
117
122
|
* language its build uses.
|
|
118
123
|
*
|
|
119
124
|
* An explicit `options.compileCommands` (a file, or a directory holding one
|
|
120
|
-
* directly or under `build/`) wins. Otherwise the scan root
|
|
121
|
-
*
|
|
122
|
-
*
|
|
125
|
+
* directly or under `build/`) wins. Otherwise the scan root and the project's
|
|
126
|
+
* build directories are searched: the directory of `options.cmakeCache`, the
|
|
127
|
+
* build directories of its CMake presets, and the conventional `build`,
|
|
128
|
+
* `out`, `builddir` and `cmake-build-` directories (see
|
|
129
|
+
* `cmakeBuildDirCandidates`). A database can come with the code it describes,
|
|
130
|
+
* and atom asks the
|
|
123
131
|
* GCC or Clang driver it names (from the PATH, or an absolute path outside
|
|
124
132
|
* the project) for its predefined macros, so in secure mode only an explicit
|
|
125
133
|
* database is used.
|
|
@@ -159,20 +167,7 @@ export function findCompileCommands(src, options = {}) {
|
|
|
159
167
|
if (!rootIsDir) {
|
|
160
168
|
return undefined;
|
|
161
169
|
}
|
|
162
|
-
const dirs = [root, ...
|
|
163
|
-
try {
|
|
164
|
-
dirs.push(
|
|
165
|
-
...readdirSync(root, { withFileTypes: true })
|
|
166
|
-
.filter((e) => e.isDirectory() && e.name.startsWith("cmake-build-"))
|
|
167
|
-
.map((e) => join(root, e.name))
|
|
168
|
-
.sort(),
|
|
169
|
-
);
|
|
170
|
-
} catch (_err) {
|
|
171
|
-
// an unreadable root has no build directories to offer
|
|
172
|
-
}
|
|
173
|
-
if (options.cmakeCache) {
|
|
174
|
-
dirs.push(dirname(resolve(`${options.cmakeCache}`)));
|
|
175
|
-
}
|
|
170
|
+
const dirs = [root, ...cmakeBuildDirCandidates(root, options)];
|
|
176
171
|
for (const dir of dirs) {
|
|
177
172
|
const candidate = join(dir, COMPILE_COMMANDS_FILE);
|
|
178
173
|
try {
|
|
@@ -751,18 +746,32 @@ export function buildAtomCommandEnv(options = {}, language = "") {
|
|
|
751
746
|
// that does not exist on native platforms, and atom 3.0.x crashes parsing
|
|
752
747
|
// that bogus value. Forward the resolved php-parse location through the env
|
|
753
748
|
// so executeAtom can bypass the dispatcher for PHP (see
|
|
754
|
-
// resolveDirectAtomBinaryPath).
|
|
749
|
+
// resolveDirectAtomBinaryPath). PHP_ASTGEN_BIN additionally names the
|
|
750
|
+
// batch-capable generator (phpastgen.js): chen parses the whole tree, vendor
|
|
751
|
+
// included, in one generator run instead of one php interpreter per file,
|
|
752
|
+
// which on windows is the difference between minutes and hours. Computed
|
|
753
|
+
// independently of exclude patterns.
|
|
755
754
|
const phpParseBin = ATOM_PHP_LANGUAGES.has(normalizedLanguage)
|
|
756
755
|
? resolvePhpParseBin()
|
|
757
756
|
: undefined;
|
|
757
|
+
const phpAstgenBin = ATOM_PHP_LANGUAGES.has(normalizedLanguage)
|
|
758
|
+
? resolvePhpAstgenBin()
|
|
759
|
+
: undefined;
|
|
760
|
+
const phpEnv = {};
|
|
761
|
+
if (phpParseBin) {
|
|
762
|
+
phpEnv.PHP_PARSER_BIN = phpParseBin;
|
|
763
|
+
}
|
|
764
|
+
if (phpAstgenBin) {
|
|
765
|
+
phpEnv.PHP_ASTGEN_BIN = phpAstgenBin;
|
|
766
|
+
}
|
|
758
767
|
if (!excludePatterns.length) {
|
|
759
|
-
return
|
|
768
|
+
return phpEnv;
|
|
760
769
|
}
|
|
761
770
|
const chenIgnoreDirs = mergeCsvValues(
|
|
762
771
|
readEnvironmentVariable("CHEN_IGNORE_DIRS"),
|
|
763
772
|
extractIgnoreDirsFromExcludePatterns(excludePatterns, true),
|
|
764
773
|
);
|
|
765
|
-
const env = {};
|
|
774
|
+
const env = { ...phpEnv };
|
|
766
775
|
if (chenIgnoreDirs) {
|
|
767
776
|
env.CHEN_IGNORE_DIRS = chenIgnoreDirs;
|
|
768
777
|
}
|
|
@@ -788,9 +797,6 @@ export function buildAtomCommandEnv(options = {}, language = "") {
|
|
|
788
797
|
env.ASTGEN_IGNORE_FILE_PATTERN = astgenIgnoreFilePattern;
|
|
789
798
|
}
|
|
790
799
|
}
|
|
791
|
-
if (phpParseBin) {
|
|
792
|
-
env.PHP_PARSER_BIN = phpParseBin;
|
|
793
|
-
}
|
|
794
800
|
return env;
|
|
795
801
|
}
|
|
796
802
|
|
|
@@ -880,15 +886,19 @@ export function resolveAtomProvider(opts = {}) {
|
|
|
880
886
|
* ceiling differently, and a native-image runtime option on a jar run reaches
|
|
881
887
|
* atom as an unknown argument that fails every slice. So the kind follows what
|
|
882
888
|
* is installed where cdxgen can see it: the native binary means native, the jar
|
|
883
|
-
* package without it means jar.
|
|
884
|
-
* install elsewhere) the
|
|
889
|
+
* package without it means jar. An `ATOM_CMD` is classified by what it names
|
|
890
|
+
* (see `atomCommandKind`). With nothing in view (an install elsewhere) the
|
|
891
|
+
* platform's kind stands.
|
|
885
892
|
*
|
|
886
893
|
* Also used to gate Java/JDK advice, so users on the five native platforms are
|
|
887
894
|
* not told to install a JDK for a failure that has nothing to do with Java.
|
|
888
895
|
*/
|
|
889
896
|
export function atomProviderKind() {
|
|
890
897
|
const { kind } = resolveAtomProvider();
|
|
891
|
-
if (
|
|
898
|
+
if (readEnvironmentVariable("ATOM_CMD")) {
|
|
899
|
+
return atomCommandKind(readEnvironmentVariable("ATOM_CMD"), kind);
|
|
900
|
+
}
|
|
901
|
+
if (kind !== "native") {
|
|
892
902
|
return kind;
|
|
893
903
|
}
|
|
894
904
|
const atomHome = readEnvironmentVariable("ATOM_HOME");
|
|
@@ -906,13 +916,64 @@ export function atomProviderKind() {
|
|
|
906
916
|
return jarPlugins ? "jar" : kind;
|
|
907
917
|
}
|
|
908
918
|
|
|
919
|
+
/**
|
|
920
|
+
* Whether `ATOM_CMD` launches a jar or follows the platform.
|
|
921
|
+
*
|
|
922
|
+
* The jar launchers (`plugins/bin/atom`, `plugins/bin/atom.bat`) sit next to a
|
|
923
|
+
* `plugins/lib` directory holding atom's jars, so a launcher with that sibling,
|
|
924
|
+
* or any `.bat` (only the jar payload ships one), runs on the JVM whatever the
|
|
925
|
+
* platform is. Everything else, including the npm dispatcher (`node
|
|
926
|
+
* .../index.js`, its `atom`/`atom.cmd` bin shims) and a native binary, follows
|
|
927
|
+
* the platform's kind. A GraalVM `-XX:` heap argument handed to a jar launcher
|
|
928
|
+
* is rejected by atom's option parser before any analysis starts, and a
|
|
929
|
+
* `JAVA_TOOL_OPTIONS` ceiling handed to a native image is silently ignored, so
|
|
930
|
+
* the distinction decides whether the heap is bounded at all.
|
|
931
|
+
*
|
|
932
|
+
* @param {string} command The `ATOM_CMD` value
|
|
933
|
+
* @param {"native"|"jar"} platformKind Kind the platform prefers
|
|
934
|
+
* @returns {"native"|"jar"}
|
|
935
|
+
*/
|
|
936
|
+
export function atomCommandKind(command, platformKind) {
|
|
937
|
+
const [bin, leadingArg] = splitAtomCommand(command);
|
|
938
|
+
const runsScript =
|
|
939
|
+
leadingArg !== undefined && /^node(\.exe)?$/i.test(basename(bin));
|
|
940
|
+
let launcher = runsScript ? leadingArg : bin;
|
|
941
|
+
if (/\.bat$/i.test(launcher)) {
|
|
942
|
+
return "jar";
|
|
943
|
+
}
|
|
944
|
+
try {
|
|
945
|
+
// npm bin entries are symlinks into the package (`/usr/local/bin/atom` ->
|
|
946
|
+
// `.../@appthreat/atom/index.js`), and `/usr/local` has a `lib` of its own.
|
|
947
|
+
launcher = realpathSync(launcher);
|
|
948
|
+
} catch {
|
|
949
|
+
return platformKind;
|
|
950
|
+
}
|
|
951
|
+
const binDir = dirname(launcher);
|
|
952
|
+
if (basename(binDir) !== "bin") {
|
|
953
|
+
return platformKind;
|
|
954
|
+
}
|
|
955
|
+
try {
|
|
956
|
+
const libDir = join(dirname(binDir), "lib");
|
|
957
|
+
if (
|
|
958
|
+
readdirSync(libDir).some(
|
|
959
|
+
(file) => file.startsWith("io.appthreat.atom") && file.endsWith(".jar"),
|
|
960
|
+
)
|
|
961
|
+
) {
|
|
962
|
+
return "jar";
|
|
963
|
+
}
|
|
964
|
+
} catch {
|
|
965
|
+
// no lib directory: not a jar layout
|
|
966
|
+
}
|
|
967
|
+
return platformKind;
|
|
968
|
+
}
|
|
969
|
+
|
|
909
970
|
/**
|
|
910
971
|
* Locate the `php-parse` binary that the PHP frontend needs.
|
|
911
972
|
*
|
|
912
973
|
* atom 3's dispatcher unconditionally sets `PHP_PARSER_BIN=<ATOM_HOME>/bin/php-parse`,
|
|
913
974
|
* which for a native sub-package does not exist and also clobbers a caller-set
|
|
914
|
-
* value. cdxgen therefore resolves the real location and forwards it through
|
|
915
|
-
*
|
|
975
|
+
* value. cdxgen therefore resolves the real location and forwards it through the
|
|
976
|
+
* child env (see `buildAtomCommandEnv`); `executeAtom` then spawns the
|
|
916
977
|
* native binary directly for PHP so the dispatcher cannot clobber it (see
|
|
917
978
|
* `resolveDirectAtomBinaryPath`). Resolution order:
|
|
918
979
|
* 1. explicit `PHP_PARSER_BIN` env var (operators / container images)
|
|
@@ -929,6 +990,44 @@ export function resolvePhpParseBin() {
|
|
|
929
990
|
if (readEnvironmentVariable("PHP_PARSER_BIN")) {
|
|
930
991
|
return readEnvironmentVariable("PHP_PARSER_BIN");
|
|
931
992
|
}
|
|
993
|
+
return parsetoolsFile("plugins", "bin", "php-parse");
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* Locate the `phpastgen` generator that lets the PHP frontend parse whole
|
|
998
|
+
* directories in one batch.
|
|
999
|
+
*
|
|
1000
|
+
* `php-parse` (forwarded as `PHP_PARSER_BIN`) is the per-file parser: atom
|
|
1001
|
+
* starts a php interpreter for every `.php` file, which on windows turns a
|
|
1002
|
+
* vendored PHP project (thousands of files under `vendor/`) into an hours-long
|
|
1003
|
+
* run that no timeout can rescue. `phpastgen` answers the `--parser-info`
|
|
1004
|
+
* capability probe, so atom's batch path engages, and atom-parsetools 1.9 and
|
|
1005
|
+
* later parse the whole tree, vendor included, with a few interpreters that
|
|
1006
|
+
* each take a chunk of files. It is a Node script, so the frontend launches it
|
|
1007
|
+
* with `node` rather than `php`; an atom that does not know `PHP_ASTGEN_BIN`
|
|
1008
|
+
* simply ignores it and keeps today's per-file behaviour. Resolution order:
|
|
1009
|
+
* 1. explicit `PHP_ASTGEN_BIN` env var (operators / container images)
|
|
1010
|
+
* 2. `@appthreat/atom-parsetools/phpastgen.js` under cdxgen's own
|
|
1011
|
+
* node_modules, then under `GLOBAL_NODE_MODULES_PATH` for global installs
|
|
1012
|
+
*
|
|
1013
|
+
* @returns {string|undefined}
|
|
1014
|
+
*/
|
|
1015
|
+
export function resolvePhpAstgenBin() {
|
|
1016
|
+
if (readEnvironmentVariable("PHP_ASTGEN_BIN")) {
|
|
1017
|
+
return readEnvironmentVariable("PHP_ASTGEN_BIN");
|
|
1018
|
+
}
|
|
1019
|
+
return parsetoolsFile("phpastgen.js");
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
/**
|
|
1023
|
+
* Resolve a file inside the installed `@appthreat/atom-parsetools` package,
|
|
1024
|
+
* searching cdxgen's own node_modules and `GLOBAL_NODE_MODULES_PATH` for global
|
|
1025
|
+
* installs.
|
|
1026
|
+
*
|
|
1027
|
+
* @param {...string} segments Path segments below the package root
|
|
1028
|
+
* @returns {string|undefined}
|
|
1029
|
+
*/
|
|
1030
|
+
export function parsetoolsFile(...segments) {
|
|
932
1031
|
const roots = [dirNameStr];
|
|
933
1032
|
if (readEnvironmentVariable("GLOBAL_NODE_MODULES_PATH")) {
|
|
934
1033
|
roots.push(dirname(readEnvironmentVariable("GLOBAL_NODE_MODULES_PATH")));
|
|
@@ -939,9 +1038,7 @@ export function resolvePhpParseBin() {
|
|
|
939
1038
|
"node_modules",
|
|
940
1039
|
"@appthreat",
|
|
941
1040
|
"atom-parsetools",
|
|
942
|
-
|
|
943
|
-
"bin",
|
|
944
|
-
"php-parse",
|
|
1041
|
+
...segments,
|
|
945
1042
|
);
|
|
946
1043
|
if (safeExistsSync(candidate)) {
|
|
947
1044
|
return candidate;
|
|
@@ -1213,25 +1310,41 @@ export function atomTimeouts() {
|
|
|
1213
1310
|
};
|
|
1214
1311
|
}
|
|
1215
1312
|
|
|
1216
|
-
function formatDuration(ms) {
|
|
1217
|
-
if (ms >= 60_000) {
|
|
1218
|
-
const minutes = Math.round(ms / 6_000) / 10;
|
|
1219
|
-
return `${minutes} minute${minutes === 1 ? "" : "s"}`;
|
|
1220
|
-
}
|
|
1221
|
-
return `${Math.round(ms / 100) / 10} seconds`;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
1313
|
// The status the atom dispatcher exits with when ATOM_TIMEOUT stops atom.
|
|
1225
1314
|
const ATOM_TIMEOUT_EXIT_CODE = 124;
|
|
1226
1315
|
|
|
1316
|
+
/**
|
|
1317
|
+
* Reap everything a timed-out atom run left behind on Windows.
|
|
1318
|
+
*
|
|
1319
|
+
* cdxgen starts atom through a shell there (`shell: isWin`), so the spawn
|
|
1320
|
+
* timeout terminates only that `cmd.exe`, and the runtime and every parser
|
|
1321
|
+
* worker under it (one `php.exe` per file for the per-file PHP frontend) keep
|
|
1322
|
+
* running against the next slice of the same run. See
|
|
1323
|
+
* {@link reapProcessTree} for how they are found. A chain broken by an
|
|
1324
|
+
* intermediate that already exited (the npm dispatcher stopping its runtime
|
|
1325
|
+
* itself) cannot be followed, and atom 4 stops its helpers once
|
|
1326
|
+
* `ATOM_PARENT_PID` is gone.
|
|
1327
|
+
*
|
|
1328
|
+
* @param {number|undefined} rootPid pid of the process cdxgen spawned
|
|
1329
|
+
* @param {number} startedAt Epoch milliseconds at which the run started
|
|
1330
|
+
* @param {number} [endedAt] Epoch milliseconds at which the spawned process ended
|
|
1331
|
+
* @returns {number[]} The pids that were stopped
|
|
1332
|
+
*/
|
|
1333
|
+
export function reapAtomProcessTree(rootPid, startedAt, endedAt = Date.now()) {
|
|
1334
|
+
return reapProcessTree(rootPid, startedAt, endedAt, "atom");
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1227
1337
|
/**
|
|
1228
1338
|
* Whether an atom run ended because it ran out of time.
|
|
1229
1339
|
*
|
|
1230
1340
|
* The dispatcher reports its own limit with status 124. cdxgen's spawn timeout
|
|
1231
1341
|
* shows up as `ETIMEDOUT`. A dispatcher older than the status code stops atom
|
|
1232
|
-
* with SIGTERM and
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1342
|
+
* with SIGTERM and passes on how the runtime ended: 1, or the runtime's own
|
|
1343
|
+
* exit on SIGTERM (143) or SIGKILL (137), which is what atom 3.1 reports. Those
|
|
1344
|
+
* statuses at or past the limit count as well, unless atom's own output shows
|
|
1345
|
+
* it failed for another reason first (an exhausted heap, a crash), which
|
|
1346
|
+
* deserves its own diagnosis. Missing one leaves the half-written atom behind,
|
|
1347
|
+
* and the next slice of the run fails to load it.
|
|
1235
1348
|
*
|
|
1236
1349
|
* @param {Object} result spawnSync result
|
|
1237
1350
|
* @param {number} elapsedMs How long the run took
|
|
@@ -1245,13 +1358,21 @@ export function atomRunTimedOut(result, elapsedMs, atomTimeoutMs) {
|
|
|
1245
1358
|
if (result?.error?.code === "ETIMEDOUT") {
|
|
1246
1359
|
return true;
|
|
1247
1360
|
}
|
|
1248
|
-
if (
|
|
1361
|
+
if (
|
|
1362
|
+
!ATOM_STOPPED_STATUSES.includes(result?.status) ||
|
|
1363
|
+
elapsedMs < atomTimeoutMs
|
|
1364
|
+
) {
|
|
1249
1365
|
return false;
|
|
1250
1366
|
}
|
|
1251
1367
|
const output = `${result.stdout || ""}\n${result.stderr || ""}`;
|
|
1252
1368
|
return !ATOM_FAILURE_MARKERS.some((marker) => output.includes(marker));
|
|
1253
1369
|
}
|
|
1254
1370
|
|
|
1371
|
+
// How a runtime stopped by an older dispatcher at ATOM_TIMEOUT exits: the
|
|
1372
|
+
// dispatcher's own 1, or the runtime's exit on SIGTERM (128 + 15) or SIGKILL
|
|
1373
|
+
// (128 + 9) passed through.
|
|
1374
|
+
const ATOM_STOPPED_STATUSES = [1, 137, 143];
|
|
1375
|
+
|
|
1255
1376
|
// Output that means atom failed by itself, whatever the clock says.
|
|
1256
1377
|
const ATOM_FAILURE_MARKERS = [
|
|
1257
1378
|
"OutOfMemoryError",
|
|
@@ -1350,10 +1471,12 @@ export function executeAtom(src, args, extra_env = {}) {
|
|
|
1350
1471
|
env,
|
|
1351
1472
|
timeout: spawnTimeoutMs,
|
|
1352
1473
|
});
|
|
1353
|
-
|
|
1474
|
+
const endedAt = Date.now();
|
|
1475
|
+
if (atomRunTimedOut(result, endedAt - startedAt, atomTimeoutMs)) {
|
|
1354
1476
|
console.warn(
|
|
1355
1477
|
`WARN: atom did not finish within ${formatDuration(atomTimeoutMs)} and was stopped, so its results are missing or incomplete. Allow more time with ATOM_TIMEOUT (milliseconds, atom only) or CDXGEN_TIMEOUT_MS (every external command).`,
|
|
1356
1478
|
);
|
|
1479
|
+
reapAtomProcessTree(result.pid, startedAt, endedAt);
|
|
1357
1480
|
// A stopped atom leaves its graph half written, and the next slice of the
|
|
1358
1481
|
// same run would try to reuse it and fail to load it.
|
|
1359
1482
|
const atomFileIndex = args.indexOf("-o");
|
|
@@ -23,6 +23,12 @@ export const GOLEM_AUDIT_CATEGORIES = Object.freeze([
|
|
|
23
23
|
"golem-compliance",
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
|
+
/** Frozen list of Scala Evinse (scalasem) audit categories. */
|
|
27
|
+
export const SCALA_AUDIT_CATEGORIES = Object.freeze([
|
|
28
|
+
"scala-security",
|
|
29
|
+
"scala-compliance",
|
|
30
|
+
]);
|
|
31
|
+
|
|
26
32
|
/** Frozen list of Cargo (Rust) audit categories. */
|
|
27
33
|
export const CARGO_AUDIT_CATEGORIES = Object.freeze([
|
|
28
34
|
"cargo-security",
|
|
@@ -64,6 +70,7 @@ export const BOM_AUDIT_CATEGORY_ALIASES = Object.freeze({
|
|
|
64
70
|
golem: [...GOLEM_AUDIT_CATEGORIES],
|
|
65
71
|
hbom: [...HBOM_AUDIT_CATEGORIES],
|
|
66
72
|
rust: [...CARGO_AUDIT_CATEGORIES],
|
|
73
|
+
scala: [...SCALA_AUDIT_CATEGORIES],
|
|
67
74
|
host: [...HBOM_AUDIT_CATEGORIES, ...HOST_TOPOLOGY_AUDIT_CATEGORIES],
|
|
68
75
|
});
|
|
69
76
|
|