@cdxgen/cdxgen 13.4.0 → 13.5.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 +7 -7
- package/bin/cdxgen-secure.js +15 -0
- package/bin/cdxgen.js +25 -5
- package/bin/evinse.js +5 -0
- package/bin/hbom.js +15 -7
- package/bin/repl.js +29 -0
- package/data/cbomosdb-queries.json +13 -1
- package/data/component-tags.json +8 -0
- package/data/queries-darwin.json +25 -1
- package/data/queries-win.json +19 -1
- package/data/queries.json +41 -0
- package/data/remediations.json +283 -1
- package/data/rules/cbom-security.yaml +235 -4
- package/data/rules/go-binaries.yaml +46 -0
- package/data/rules/golem-go.yaml +80 -0
- package/data/rules/hbom-compliance.yaml +40 -22
- package/data/rules/hbom-performance.yaml +7 -1
- package/data/rules/host-topology.yaml +1 -1
- package/data/rules/obom-runtime.yaml +31 -2
- package/data/rules/php-runtime.yaml +143 -0
- package/lib/audit/index.js +14 -0
- package/lib/cli/bomAssembly.js +28 -3
- package/lib/cli/cliOptions.js +110 -3
- package/lib/cli/index.js +73 -4
- package/lib/cli/jvmBom.js +126 -20
- package/lib/cli/managedBom.js +711 -71
- package/lib/cli/nativeBom.js +225 -28
- package/lib/core/env.js +30 -8
- package/lib/core/fs.js +28 -19
- package/lib/core/httpClient.js +74 -45
- package/lib/core/projectConfig.js +1 -0
- package/lib/core/projectTooling.js +97 -0
- package/lib/core/propertySanitizer.js +72 -0
- package/lib/ecosystems/golem.js +550 -6
- package/lib/ecosystems/gradleutils.js +30 -20
- package/lib/ecosystems/parsers-dotnet.js +117 -18
- package/lib/ecosystems/parsers-go.js +1090 -367
- package/lib/ecosystems/parsers-jvm.js +259 -17
- package/lib/ecosystems/parsers-misc.js +229 -44
- package/lib/ecosystems/parsers-python.js +11 -10
- package/lib/ecosystems/rubyutils.js +6 -3
- package/lib/ecosystems/rusi.js +10 -0
- package/lib/ecosystems/scalacliutils.js +2 -1
- package/lib/ecosystems/scalasem.js +3 -1
- package/lib/evinser/evinser.js +126 -18
- package/lib/evinser/swiftsem.js +68 -5
- package/lib/inventory/agentSkillSpec.js +17 -0
- package/lib/inventory/apkInstalledDb.js +243 -0
- package/lib/inventory/atomUtils.js +33 -0
- package/lib/inventory/auditCategories.js +3 -3
- package/lib/inventory/cacheDir.js +52 -9
- package/lib/inventory/certificates.js +2371 -0
- package/lib/inventory/communityAiConfigParser.js +4 -9
- package/lib/inventory/deps.js +6 -4
- package/lib/inventory/display.js +200 -3
- package/lib/inventory/dosai.js +500 -58
- package/lib/inventory/dynamic.js +45 -3
- package/lib/inventory/envcontext.js +168 -5
- package/lib/inventory/evidenceUtils.js +436 -23
- package/lib/inventory/formulationParsers.js +3 -2
- package/lib/inventory/goBuildInfo.js +140 -0
- package/lib/inventory/hbom.js +67 -7
- package/lib/inventory/hbomAnalysis.js +16 -0
- package/lib/inventory/hostTopology.js +21 -0
- package/lib/inventory/osPackagePurl.js +244 -0
- package/lib/inventory/osPackageResolver.js +89 -87
- package/lib/inventory/osinfo.js +79 -31
- package/lib/inventory/osqueryTransform.js +114 -5
- package/lib/inventory/phpBuildInfo.js +487 -0
- package/lib/inventory/phpHostProbe.js +641 -0
- package/lib/inventory/rootfsCerts.js +426 -0
- package/lib/inventory/source.js +207 -3
- package/lib/inventory/spdx.js +144 -0
- package/lib/inventory/traceRunner.js +5 -1
- package/lib/inventory/tracedCrypto.js +129 -0
- package/lib/managers/binary.js +529 -183
- package/lib/managers/docker.js +166 -12
- package/lib/parsers/email.js +277 -0
- package/lib/parsers/largeJson.js +34 -2
- package/lib/server/server.js +186 -1
- package/lib/stages/postgen/annotator.js +17 -1
- package/lib/stages/postgen/introspection/reflect.js +4 -1
- package/lib/stages/postgen/postgen.js +5 -5
- package/lib/stages/postgen/ruleEngine.js +58 -1
- package/lib/stages/postgen/specVersionCompat.js +30 -0
- package/lib/stages/pregen/pregen.js +117 -5
- package/lib/validator/bomValidator.js +26 -5
- package/lib/validator/generated/runtime.mjs +13 -0
- package/lib/validator/generated/validate-1.6.mjs +26 -7
- package/lib/validator/generated/validate-1.7.mjs +31 -12
- package/lib/validator/generated/validate-2.0.mjs +30 -11
- package/package.json +17 -17
- package/types/bin/cdxgen-secure.d.ts +3 -0
- package/types/bin/cdxgen-secure.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +9 -2
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +43 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +20 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +18 -2
- 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.map +1 -1
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/projectTooling.d.ts +41 -0
- package/types/lib/core/projectTooling.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +26 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +1 -1
- package/types/lib/ecosystems/golem.d.ts +81 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +10 -8
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +40 -4
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +85 -13
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +28 -2
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +18 -58
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +4 -3
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +1 -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/scalacliutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +25 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +10 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
- package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
- package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
- package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +14 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/cacheDir.d.ts +12 -4
- package/types/lib/inventory/cacheDir.d.ts.map +1 -1
- package/types/lib/inventory/certificates.d.ts +205 -0
- package/types/lib/inventory/certificates.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/deps.d.ts +2 -1
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts +18 -0
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +145 -6
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +6 -1
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts +40 -2
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +29 -10
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/goBuildInfo.d.ts +10 -0
- package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
- package/types/lib/inventory/hostTopology.d.ts.map +1 -1
- package/types/lib/inventory/osPackagePurl.d.ts +99 -0
- package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +6 -2
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/osinfo.d.ts +31 -6
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- package/types/lib/inventory/osqueryTransform.d.ts +51 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
- package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/phpHostProbe.d.ts +35 -0
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/rootfsCerts.d.ts +27 -0
- package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +28 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +15 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +4 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +22 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +10 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +12 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/parsers/email.d.ts +19 -0
- package/types/lib/parsers/email.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +13 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +8 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +14 -1
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
package/lib/evinser/evinser.js
CHANGED
|
@@ -5,6 +5,7 @@ import process from "node:process";
|
|
|
5
5
|
import { Purl } from "@cdxgen/cdx-purl";
|
|
6
6
|
|
|
7
7
|
import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
|
|
8
|
+
import { recordDegradation } from "../core/buildLedger.js";
|
|
8
9
|
import { PROJECT_TYPE_ALIASES } from "../core/env.js";
|
|
9
10
|
import {
|
|
10
11
|
getAllFiles,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
safeRmSync,
|
|
16
17
|
safeWriteSync,
|
|
17
18
|
} from "../core/fs.js";
|
|
19
|
+
import { isProjectToolingAllowed } from "../core/projectTooling.js";
|
|
18
20
|
import { hasCppSources } from "../ecosystems/cppEvidence.js";
|
|
19
21
|
import {
|
|
20
22
|
createIncludeAttributor,
|
|
@@ -23,11 +25,11 @@ import {
|
|
|
23
25
|
import {
|
|
24
26
|
analyzeGolemProject,
|
|
25
27
|
collectGolemEvidence,
|
|
28
|
+
collectGolemServices,
|
|
26
29
|
isGolemGoLanguage,
|
|
27
30
|
} from "../ecosystems/golem.js";
|
|
28
31
|
import {
|
|
29
32
|
collectGradleDependencies,
|
|
30
|
-
getGradleCommand,
|
|
31
33
|
getMavenCommand,
|
|
32
34
|
} from "../ecosystems/gradleutils.js";
|
|
33
35
|
import {
|
|
@@ -52,6 +54,7 @@ import {
|
|
|
52
54
|
isScalasemLanguage,
|
|
53
55
|
} from "../ecosystems/scalasem.js";
|
|
54
56
|
import {
|
|
57
|
+
atomBuildToolArgs,
|
|
55
58
|
atomCompileCommandsArgs,
|
|
56
59
|
buildAtomCommandEnv,
|
|
57
60
|
executeAtom,
|
|
@@ -77,7 +80,10 @@ import {
|
|
|
77
80
|
collectDosaiServicesFromMethods,
|
|
78
81
|
createDosaiDataFlowSlice,
|
|
79
82
|
createDosaiMethodsSlice,
|
|
80
|
-
|
|
83
|
+
dosaiFailureReported,
|
|
84
|
+
dosaiOmittedSections,
|
|
85
|
+
dosaiReportFileOmittedSections,
|
|
86
|
+
dosaiSectionsCdxgenReads,
|
|
81
87
|
isDosaiDotnetLanguage,
|
|
82
88
|
normalizeDosaiServiceMap,
|
|
83
89
|
persistDosaiSemanticsReport,
|
|
@@ -401,9 +407,25 @@ export async function catalogMavenDeps(
|
|
|
401
407
|
options = {},
|
|
402
408
|
) {
|
|
403
409
|
let jarNSMapping = readNamespaceMap(dirPath, options);
|
|
404
|
-
if (!jarNSMapping) {
|
|
410
|
+
if (!jarNSMapping && !isProjectToolingAllowed(options)) {
|
|
411
|
+
// `mvn dependency:copy-dependencies` evaluates the project's build and
|
|
412
|
+
// its `.mvn` configuration, so only the local repository is read.
|
|
413
|
+
console.log(
|
|
414
|
+
options.withDeepJarCollector
|
|
415
|
+
? "Skipping 'mvn dependency:copy-dependencies' since dependency installation is disabled. Only the jars already in the local Maven repository are used."
|
|
416
|
+
: "Skipping 'mvn dependency:copy-dependencies' since dependency installation is disabled. Pass --with-deep-jar-collector to use the jars already in the local Maven repository.",
|
|
417
|
+
);
|
|
418
|
+
if (options.withDeepJarCollector) {
|
|
419
|
+
jarNSMapping = await collectMvnDependencies(
|
|
420
|
+
undefined,
|
|
421
|
+
undefined,
|
|
422
|
+
true,
|
|
423
|
+
true,
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
} else if (!jarNSMapping) {
|
|
405
427
|
console.log("About to collect jar dependencies for the path", dirPath);
|
|
406
|
-
const mavenCmd = getMavenCommand(dirPath, dirPath);
|
|
428
|
+
const mavenCmd = getMavenCommand(dirPath, dirPath, options);
|
|
407
429
|
// collect all jars including from the cache if data-flow mode is enabled
|
|
408
430
|
jarNSMapping = await collectMvnDependencies(
|
|
409
431
|
mavenCmd,
|
|
@@ -457,10 +479,10 @@ export async function catalogGradleDeps(
|
|
|
457
479
|
console.log(
|
|
458
480
|
"About to collect jar dependencies from the gradle cache. This would take a while ...",
|
|
459
481
|
);
|
|
460
|
-
|
|
461
|
-
//
|
|
482
|
+
// Only the Gradle cache is read, so no Gradle command is resolved: that
|
|
483
|
+
// would probe the project's own gradlew.
|
|
462
484
|
jarNSMapping = await collectGradleDependencies(
|
|
463
|
-
|
|
485
|
+
undefined,
|
|
464
486
|
dirPath,
|
|
465
487
|
false,
|
|
466
488
|
true,
|
|
@@ -645,9 +667,9 @@ export async function createSlice(
|
|
|
645
667
|
resolve(slicesFile),
|
|
646
668
|
options,
|
|
647
669
|
);
|
|
648
|
-
// A stopped run
|
|
649
|
-
// project is supported (issue 4438).
|
|
650
|
-
if (!sliceResult && !
|
|
670
|
+
// A stopped run, or one the .NET host refused to start, has already said
|
|
671
|
+
// why; it says nothing about whether the project is supported (issue 4438).
|
|
672
|
+
if (!sliceResult && !dosaiFailureReported(resolve(slicesFile))) {
|
|
651
673
|
console.warn(
|
|
652
674
|
`Unable to generate ${sliceType} slice using dosai. Check if this is a supported .NET project.`,
|
|
653
675
|
);
|
|
@@ -658,6 +680,13 @@ export async function createSlice(
|
|
|
658
680
|
slicesFile,
|
|
659
681
|
};
|
|
660
682
|
}
|
|
683
|
+
const buildToolArgs = atomBuildToolArgs(language, options);
|
|
684
|
+
if (!buildToolArgs) {
|
|
685
|
+
console.log(
|
|
686
|
+
`Skipping the ${sliceType} slice for ${resolve(filePath)} since dependency installation is disabled and the installed atom cannot be stopped from running Maven. Upgrade atom to slice this project without its build.`,
|
|
687
|
+
);
|
|
688
|
+
return { tempDir: sliceOutputDir, tempDirOwned };
|
|
689
|
+
}
|
|
661
690
|
console.log(
|
|
662
691
|
`Creating ${sliceType} slice for ${resolve(filePath)}. Please wait ...`,
|
|
663
692
|
);
|
|
@@ -706,6 +735,7 @@ export async function createSlice(
|
|
|
706
735
|
args.push(readEnvironmentVariable("ATOM_SLICE_DEPTH"));
|
|
707
736
|
}
|
|
708
737
|
args.push(...atomCompileCommandsArgs(filePath, language, options));
|
|
738
|
+
args.push(...buildToolArgs);
|
|
709
739
|
args.push(resolve(filePath));
|
|
710
740
|
const atomExcludeEnv = buildAtomCommandEnv(options, language);
|
|
711
741
|
// Execute atom
|
|
@@ -1143,6 +1173,49 @@ export function mergeServiceDefinitions(target, source) {
|
|
|
1143
1173
|
return target;
|
|
1144
1174
|
}
|
|
1145
1175
|
|
|
1176
|
+
/**
|
|
1177
|
+
* Collect the services of a Go project for the golem evidence path (#4498).
|
|
1178
|
+
*
|
|
1179
|
+
* Two sources are kept and merged by service name, the way the Scala path
|
|
1180
|
+
* merges a user-provided spec into its report's services. They roll services
|
|
1181
|
+
* up differently — golem per server, OpenAPI per path and method — so a
|
|
1182
|
+
* route both name appears under both entries:
|
|
1183
|
+
*
|
|
1184
|
+
* - the golem report itself, whose `services[]` section rolls the registered
|
|
1185
|
+
* routes up per server (a gin engine, a net/http listener) with methods and
|
|
1186
|
+
* frameworks, and the outbound hosts it calls into `kind: "external"`
|
|
1187
|
+
* services flagged as trust-boundary crossings;
|
|
1188
|
+
* - an OpenAPI document, either the one `--openapi-spec-file` names or the
|
|
1189
|
+
* `openapi.json` an earlier `atom-tools convert -t go` left in the repo,
|
|
1190
|
+
* which is reused when present so `golem`/`atom-tools` and `cdxgen` can be
|
|
1191
|
+
* run as separate steps.
|
|
1192
|
+
*
|
|
1193
|
+
* @param {object|null|undefined} golemReport Parsed golem analysis report,
|
|
1194
|
+
* when one was produced; a missing or `null` report adds no services.
|
|
1195
|
+
* @param {string} dirPath Project directory the report was produced from.
|
|
1196
|
+
* @param {Object} options Command line options.
|
|
1197
|
+
* @param {Object} [servicesMap={}] Service map to populate.
|
|
1198
|
+
* @returns {Object} The service map
|
|
1199
|
+
*/
|
|
1200
|
+
export function collectGoServices(
|
|
1201
|
+
golemReport,
|
|
1202
|
+
dirPath,
|
|
1203
|
+
options = {},
|
|
1204
|
+
servicesMap = {},
|
|
1205
|
+
) {
|
|
1206
|
+
servicesMap = collectGolemServices(golemReport, servicesMap);
|
|
1207
|
+
const openapiSpecFile = resolve(
|
|
1208
|
+
dirPath,
|
|
1209
|
+
options.openapiSpecFile || "openapi.json",
|
|
1210
|
+
);
|
|
1211
|
+
if (safeExistsSync(openapiSpecFile)) {
|
|
1212
|
+
const openapiServices = {};
|
|
1213
|
+
detectServicesFromOpenAPI("go", openapiSpecFile, openapiServices);
|
|
1214
|
+
mergeServiceDefinitions(servicesMap, openapiServices);
|
|
1215
|
+
}
|
|
1216
|
+
return servicesMap;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1146
1219
|
/**
|
|
1147
1220
|
* Function to analyze the project
|
|
1148
1221
|
*
|
|
@@ -1183,6 +1256,7 @@ export async function analyzeProject(dbObjMap, options) {
|
|
|
1183
1256
|
|
|
1184
1257
|
if (isGolemGoLanguage(language)) {
|
|
1185
1258
|
const golemReport = analyzeGolemProject(dirPath, options);
|
|
1259
|
+
servicesMap = collectGoServices(golemReport, dirPath, options, servicesMap);
|
|
1186
1260
|
if (golemReport && Object.keys(golemReport).length) {
|
|
1187
1261
|
const golemEvidence = collectGolemEvidence(golemReport, [
|
|
1188
1262
|
bomJson.metadata?.component,
|
|
@@ -1329,24 +1403,58 @@ export async function analyzeProject(dbObjMap, options) {
|
|
|
1329
1403
|
options.withDataFlow = true;
|
|
1330
1404
|
options.includeCrypto = true;
|
|
1331
1405
|
}
|
|
1406
|
+
let needsUsagesRun = true;
|
|
1332
1407
|
if (
|
|
1333
1408
|
options.usagesSlicesFile &&
|
|
1334
1409
|
usableSlicesFile(options.usagesSlicesFile)
|
|
1335
1410
|
) {
|
|
1336
1411
|
usageSlice = readDosaiMethodsReport(options.usagesSlicesFile);
|
|
1337
1412
|
usagesSlicesFile = options.usagesSlicesFile;
|
|
1413
|
+
needsUsagesRun = false;
|
|
1414
|
+
// A user-supplied usages slice is used as given. When it was written
|
|
1415
|
+
// with --sections and left out a section cdxgen reads, the evidence
|
|
1416
|
+
// lacks that input; persistDosaiSemanticsReport reports separately
|
|
1417
|
+
// that the persisted report is partial.
|
|
1418
|
+
const missingInputs = dosaiSectionsCdxgenReads(
|
|
1419
|
+
dosaiOmittedSections(usageSlice),
|
|
1420
|
+
);
|
|
1421
|
+
if (missingInputs.length) {
|
|
1422
|
+
recordDegradation("dosai.usages.trimmed-report", {
|
|
1423
|
+
ecosystem: "csharp",
|
|
1424
|
+
tool: "dosai",
|
|
1425
|
+
impact: "components",
|
|
1426
|
+
command: `usages ${usagesSlicesFile}`,
|
|
1427
|
+
detail: `The supplied dosai methods report was written without sections cdxgen reads: ${missingInputs.join(", ")}. The evidence from those sections is missing. Run dosai methods without --sections, or with every section cdxgen reads.`,
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1338
1430
|
} else if (usableSlicesFile(options.depsSlicesFile)) {
|
|
1339
1431
|
// createCsharpBom already ran dosai methods on this tree for --deep runs
|
|
1340
1432
|
// and wrote the deps slice. For dosai, that output IS the usages slice,
|
|
1341
|
-
// so reuse it instead of invoking dosai a second time
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1433
|
+
// so reuse it instead of invoking dosai a second time - unless it was
|
|
1434
|
+
// written with --sections (a --deep run that performs no evidence
|
|
1435
|
+
// analysis trims it): evinse persists this file as the full native
|
|
1436
|
+
// report, so it must not build on a trimmed one and dosai runs again.
|
|
1437
|
+
const omittedSections = dosaiReportFileOmittedSections(
|
|
1438
|
+
options.depsSlicesFile,
|
|
1439
|
+
);
|
|
1440
|
+
if (omittedSections.length) {
|
|
1441
|
+
if (DEBUG_MODE) {
|
|
1442
|
+
console.log(
|
|
1443
|
+
`The dosai deps slices file "${options.depsSlicesFile}" omits sections (${omittedSections.join(", ")}); running dosai for the full usages report.`,
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
} else {
|
|
1447
|
+
if (DEBUG_MODE) {
|
|
1448
|
+
console.log(
|
|
1449
|
+
`Reusing the dosai deps slices file "${options.depsSlicesFile}" for the usages analysis.`,
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
usageSlice = readDosaiMethodsReport(options.depsSlicesFile);
|
|
1453
|
+
usagesSlicesFile = options.depsSlicesFile;
|
|
1454
|
+
needsUsagesRun = false;
|
|
1346
1455
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
} else {
|
|
1456
|
+
}
|
|
1457
|
+
if (needsUsagesRun) {
|
|
1350
1458
|
retMap = await createSlice(language, dirPath, "usages", options);
|
|
1351
1459
|
if (retMap?.slicesFile && safeExistsSync(retMap.slicesFile)) {
|
|
1352
1460
|
usageSlice = readDosaiMethodsReport(retMap.slicesFile);
|
package/lib/evinser/swiftsem.js
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
safeRmSync,
|
|
21
21
|
safeSpawnSync,
|
|
22
22
|
} from "../core/fs.js";
|
|
23
|
+
import { isProjectToolingAllowed } from "../ecosystems/gradleutils.js";
|
|
23
24
|
import { splitCommandArgs } from "../ecosystems/parsers-js.js";
|
|
24
25
|
import { collectSwiftProductionTargets } from "../ecosystems/parsers-misc.js";
|
|
25
26
|
import { runSwiftCommand } from "../inventory/envcontext.js";
|
|
@@ -585,6 +586,45 @@ export function sanitizeSwiftModuleArgs(tokens) {
|
|
|
585
586
|
return args;
|
|
586
587
|
}
|
|
587
588
|
|
|
589
|
+
// Compiler arguments that load code into the compiler or the SourceKit
|
|
590
|
+
// service: macro plugins and their search paths, and the clang arguments
|
|
591
|
+
// (`-Xcc -fplugin=...`) behind -Xcc.
|
|
592
|
+
const SWIFT_CODE_LOADING_ARGS = new Set([
|
|
593
|
+
"-plugin-path",
|
|
594
|
+
"-external-plugin-path",
|
|
595
|
+
"-load-plugin-executable",
|
|
596
|
+
"-load-plugin-library",
|
|
597
|
+
"-in-process-plugin-server-path",
|
|
598
|
+
"-Xcc",
|
|
599
|
+
]);
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Remove the arguments that would make SourceKit load code named by the
|
|
603
|
+
* project. A `.build` directory that cdxgen did not create is project content,
|
|
604
|
+
* so the compiler arguments read from it are cleaned this way whenever the
|
|
605
|
+
* project's own tooling may not run.
|
|
606
|
+
*
|
|
607
|
+
* @param {Array<String>} args Sanitized compiler arguments
|
|
608
|
+
* @returns {Array<String>} Arguments without plugin and clang pass-through flags
|
|
609
|
+
*/
|
|
610
|
+
export function withoutSwiftPluginArgs(args) {
|
|
611
|
+
const kept = [];
|
|
612
|
+
for (let i = 0; i < (args || []).length; i++) {
|
|
613
|
+
const token = args[i];
|
|
614
|
+
if (SWIFT_CODE_LOADING_ARGS.has(token)) {
|
|
615
|
+
i++;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
// -Xfrontend <plugin flag> -Xfrontend <value>
|
|
619
|
+
if (token === "-Xfrontend" && SWIFT_CODE_LOADING_ARGS.has(args[i + 1])) {
|
|
620
|
+
i += 3;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
kept.push(token);
|
|
624
|
+
}
|
|
625
|
+
return kept;
|
|
626
|
+
}
|
|
627
|
+
|
|
588
628
|
/**
|
|
589
629
|
* Read the sources listed in a response or file-list file (`@<path>`), one
|
|
590
630
|
* path per line.
|
|
@@ -2198,7 +2238,16 @@ export function createSemanticsSlices(basePath, options) {
|
|
|
2198
2238
|
if (!pkgSwiftFiles.length) {
|
|
2199
2239
|
return undefined;
|
|
2200
2240
|
}
|
|
2201
|
-
|
|
2241
|
+
// A SwiftPM manifest is a Swift program and the verbose build compiles the
|
|
2242
|
+
// project, so both belong to the dependency-tooling surface disabled by
|
|
2243
|
+
// --no-install-deps and the pre-build lifecycle. Evidence then comes from
|
|
2244
|
+
// the .build artifacts a previous build left and import declarations.
|
|
2245
|
+
const toolingAllowed = isProjectToolingAllowed(options);
|
|
2246
|
+
// swiftly picks a toolchain from the project's .swift-version, so the
|
|
2247
|
+
// toolchain is resolved outside the project when its tooling may not run
|
|
2248
|
+
const toolchain = resolveSwiftToolchain(
|
|
2249
|
+
toolingAllowed ? basePath : getTmpDir(),
|
|
2250
|
+
);
|
|
2202
2251
|
const sourcekittenEnv = sourcekittenEnvForToolchain(toolchain);
|
|
2203
2252
|
// Without a working sourcekitten, the evidence is limited to the import
|
|
2204
2253
|
// declarations of the modules the build describes
|
|
@@ -2211,13 +2260,22 @@ export function createSemanticsSlices(basePath, options) {
|
|
|
2211
2260
|
: "",
|
|
2212
2261
|
);
|
|
2213
2262
|
}
|
|
2263
|
+
if (!toolingAllowed) {
|
|
2264
|
+
console.log(
|
|
2265
|
+
"Skipping 'swift package dump-package' and the swift build for evidence since dependency installation is disabled. Evidence is limited to the build artifacts already in the project, without their compiler plugins.",
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
2214
2268
|
// Package.swift contains the root targets, including which ones are tests
|
|
2215
|
-
const packageMetadata =
|
|
2269
|
+
const packageMetadata = toolingAllowed
|
|
2270
|
+
? parseDumpPackage(dumpPackage(basePath))
|
|
2271
|
+
: undefined;
|
|
2216
2272
|
const userCompilerArgs = process?.env?.SWIFT_COMPILER_ARGS;
|
|
2217
2273
|
const userSdkArgs = process?.env?.SWIFT_SDK_ARGS;
|
|
2218
2274
|
// A clean verbose debug build reveals the compiler arguments of every module
|
|
2219
2275
|
const buildOutput =
|
|
2220
|
-
userCompilerArgs && userSdkArgs
|
|
2276
|
+
!toolingAllowed || (userCompilerArgs && userSdkArgs)
|
|
2277
|
+
? undefined
|
|
2278
|
+
: verboseBuild(basePath);
|
|
2221
2279
|
const buildPlan = collectSwiftBuildPlan(
|
|
2222
2280
|
basePath,
|
|
2223
2281
|
buildOutput,
|
|
@@ -2267,7 +2325,9 @@ export function createSemanticsSlices(basePath, options) {
|
|
|
2267
2325
|
moduleArgs[moduleName] = [
|
|
2268
2326
|
...(userCompilerArgs
|
|
2269
2327
|
? splitSwiftCommandArgs(`${userCompilerArgs} ${userSdkArgs || ""}`)
|
|
2270
|
-
:
|
|
2328
|
+
: toolingAllowed
|
|
2329
|
+
? amodule.args
|
|
2330
|
+
: withoutSwiftPluginArgs(amodule.args)),
|
|
2271
2331
|
"-module-cache-path",
|
|
2272
2332
|
moduleCachePath,
|
|
2273
2333
|
];
|
|
@@ -2284,12 +2344,15 @@ export function createSemanticsSlices(basePath, options) {
|
|
|
2284
2344
|
}
|
|
2285
2345
|
// Sources that belong to no known module, for example when the build
|
|
2286
2346
|
// failed, are indexed with the merged arguments of the root modules
|
|
2287
|
-
|
|
2347
|
+
let fallbackArgs = userCompilerArgs
|
|
2288
2348
|
? splitSwiftCommandArgs(`${userCompilerArgs} ${userSdkArgs || ""}`)
|
|
2289
2349
|
: extractCompilerParamsFromBuild(
|
|
2290
2350
|
buildOutput,
|
|
2291
2351
|
packageMetadata?.rootModules,
|
|
2292
2352
|
).compilerArgs;
|
|
2353
|
+
if (!userCompilerArgs && !toolingAllowed) {
|
|
2354
|
+
fallbackArgs = withoutSwiftPluginArgs(fallbackArgs);
|
|
2355
|
+
}
|
|
2293
2356
|
// Sources of test and dependency modules are never indexed
|
|
2294
2357
|
const plannedSources = new Set();
|
|
2295
2358
|
for (const amodule of Object.values(buildPlan.modules)) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the frontmatter of a SKILL.md satisfies the open Agent Skills
|
|
3
|
+
* constraints (agentskills.io): a name of 1-64 lowercase letters, digits and
|
|
4
|
+
* hyphens, and a description of 1-1024 characters.
|
|
5
|
+
*
|
|
6
|
+
* @param {{name?: unknown, description?: unknown}|undefined} metadata Frontmatter values
|
|
7
|
+
* @returns {boolean} true when both constraints hold
|
|
8
|
+
*/
|
|
9
|
+
export function isAgentSkillSpecValid(metadata) {
|
|
10
|
+
return (
|
|
11
|
+
typeof metadata?.name === "string" &&
|
|
12
|
+
/^[a-z0-9-]{1,64}$/u.test(metadata.name) &&
|
|
13
|
+
typeof metadata?.description === "string" &&
|
|
14
|
+
metadata.description.length >= 1 &&
|
|
15
|
+
metadata.description.length <= 1024
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// Bounded, read-only reader of the apk installed database.
|
|
2
|
+
//
|
|
3
|
+
// osquery has no apk table, so an Alpine, Wolfi or Chainguard host would have no
|
|
4
|
+
// OS package inventory in an OBOM, and the PHP host probe needs the same
|
|
5
|
+
// database to tell which PHP files a package owns. Both read it through here, so
|
|
6
|
+
// what the OBOM lists and what the probe treats as owned follow one parser: the
|
|
7
|
+
// same file, location order, caps and record rules.
|
|
8
|
+
//
|
|
9
|
+
// The database is `/lib/apk/db/installed`. A usr-merged system keeps it at
|
|
10
|
+
// `/usr/lib/apk/db/installed` (and `/lib` is a link to `/usr/lib`, so the two
|
|
11
|
+
// names are one file), and Alpaquita keeps it under `/var/lib/apk/db`. The first
|
|
12
|
+
// of those that exists is the database. One that exists but cannot be read
|
|
13
|
+
// leaves the packages unknown: it is reported as unreadable, never read in part
|
|
14
|
+
// and never skipped for the next name.
|
|
15
|
+
//
|
|
16
|
+
// A record is a run of `<letter>:<value>` lines ended by a blank line. P: names
|
|
17
|
+
// the package, V: its version, A: its architecture, o: its origin (the source
|
|
18
|
+
// package), m: its maintainer, L: its licence, U: its home page and T: its
|
|
19
|
+
// description. F: names a directory and each R: after it a file in that
|
|
20
|
+
// directory. A record may start with C: (Alpine) or P: (Wolfi).
|
|
21
|
+
|
|
22
|
+
import { statSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import process from "node:process";
|
|
25
|
+
|
|
26
|
+
import { isDryRun, recordActivity } from "../core/activity.js";
|
|
27
|
+
import { safeExistsSync, safeReadFileSync } from "../core/fs.js";
|
|
28
|
+
import { thoughtLog } from "../core/logger.js";
|
|
29
|
+
|
|
30
|
+
/** The database, or the packages it lists, past these is unreadable rather than read in part. */
|
|
31
|
+
export const MAX_APK_DATABASE_BYTES = 64 * 1024 * 1024;
|
|
32
|
+
export const MAX_APK_PACKAGES = 100000;
|
|
33
|
+
|
|
34
|
+
/** Where apk keeps the installed database, relative to the root, in the order they are tried. */
|
|
35
|
+
export const APK_INSTALLED_DB_PATHS = [
|
|
36
|
+
"lib/apk/db/installed",
|
|
37
|
+
"usr/lib/apk/db/installed",
|
|
38
|
+
"var/lib/apk/db/installed",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// No field of a package record is longer than this once read.
|
|
42
|
+
const MAX_FIELD_LENGTH = 4096;
|
|
43
|
+
|
|
44
|
+
const FIELD_NAMES = {
|
|
45
|
+
P: "name",
|
|
46
|
+
V: "version",
|
|
47
|
+
A: "arch",
|
|
48
|
+
o: "origin",
|
|
49
|
+
m: "maintainer",
|
|
50
|
+
L: "license",
|
|
51
|
+
U: "url",
|
|
52
|
+
T: "description",
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function readBounded(file, maxBytes) {
|
|
56
|
+
try {
|
|
57
|
+
const stats = statSync(file);
|
|
58
|
+
if (!stats.isFile() || stats.size > maxBytes) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const text = safeReadFileSync(file, "utf-8");
|
|
65
|
+
// A file that grew between the stat and the read is over the cap too.
|
|
66
|
+
return typeof text === "string" && text.length <= maxBytes ? text : undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function newRecord() {
|
|
70
|
+
return { fields: {}, fileCount: 0, files: [], touched: false };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Parse the text of an installed database.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} text Database text
|
|
77
|
+
* @param {Set<string>|undefined} wantedFiles Absolute paths whose owner is wanted
|
|
78
|
+
* @param {number} maxPackages Most packages to accept
|
|
79
|
+
* @returns {{packages: Object[], malformed: number, overflow: boolean}}
|
|
80
|
+
*/
|
|
81
|
+
function parseDatabase(text, wantedFiles, maxPackages) {
|
|
82
|
+
const packages = [];
|
|
83
|
+
let malformed = 0;
|
|
84
|
+
let overflow = false;
|
|
85
|
+
let record = newRecord();
|
|
86
|
+
let directory = "";
|
|
87
|
+
const finishRecord = () => {
|
|
88
|
+
const { fields, fileCount, files, touched } = record;
|
|
89
|
+
record = newRecord();
|
|
90
|
+
directory = "";
|
|
91
|
+
if (!touched) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// A package with no name or no version cannot be named by a purl.
|
|
95
|
+
if (!fields.name || !fields.version) {
|
|
96
|
+
malformed++;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
packages.push({ ...fields, fileCount, files });
|
|
100
|
+
if (packages.length > maxPackages) {
|
|
101
|
+
overflow = true;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
let position = 0;
|
|
105
|
+
while (position <= text.length && !overflow) {
|
|
106
|
+
let end = text.indexOf("\n", position);
|
|
107
|
+
if (end === -1) {
|
|
108
|
+
end = text.length;
|
|
109
|
+
}
|
|
110
|
+
let line = text.slice(position, end);
|
|
111
|
+
position = end + 1;
|
|
112
|
+
if (line.endsWith("\r")) {
|
|
113
|
+
line = line.slice(0, -1);
|
|
114
|
+
}
|
|
115
|
+
if (line === "") {
|
|
116
|
+
finishRecord();
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (line.length < 2 || line[1] !== ":") {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const letter = line[0];
|
|
123
|
+
const value = line.slice(2);
|
|
124
|
+
if (Object.hasOwn(FIELD_NAMES, letter)) {
|
|
125
|
+
record.touched = true;
|
|
126
|
+
if (value) {
|
|
127
|
+
record.fields[FIELD_NAMES[letter]] =
|
|
128
|
+
value.length > MAX_FIELD_LENGTH
|
|
129
|
+
? value.slice(0, MAX_FIELD_LENGTH)
|
|
130
|
+
: value;
|
|
131
|
+
}
|
|
132
|
+
} else if (letter === "F") {
|
|
133
|
+
record.touched = true;
|
|
134
|
+
directory = value;
|
|
135
|
+
} else if (letter === "R") {
|
|
136
|
+
record.touched = true;
|
|
137
|
+
record.fileCount++;
|
|
138
|
+
if (wantedFiles) {
|
|
139
|
+
const file = `/${directory ? `${directory}/` : ""}${value}`;
|
|
140
|
+
if (wantedFiles.has(file)) {
|
|
141
|
+
record.files.push(file);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (!overflow) {
|
|
147
|
+
finishRecord();
|
|
148
|
+
}
|
|
149
|
+
return { packages, malformed, overflow };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Read the packages of the apk installed database.
|
|
154
|
+
*
|
|
155
|
+
* @param {Object} [options] Read options
|
|
156
|
+
* @param {string} [options.rootPath="/"] Directory the database paths hang off;
|
|
157
|
+
* tests point it at a built tree
|
|
158
|
+
* @param {string} [options.databaseFile] Read this file instead of looking
|
|
159
|
+
* under `rootPath`
|
|
160
|
+
* @param {Set<string>} [options.wantedFiles] Absolute paths whose owner is
|
|
161
|
+
* wanted. A package comes back with the ones it owns in `files`; the other
|
|
162
|
+
* files of a package are only counted, so a large database stays small.
|
|
163
|
+
* @param {number} [options.maxBytes] Largest database to read, 64 MiB by default
|
|
164
|
+
* @param {number} [options.maxPackages] Most packages to accept, 100000 by default
|
|
165
|
+
* @param {string} [options.platform] `linux` by default for the process; an apk
|
|
166
|
+
* database exists on Linux only
|
|
167
|
+
* @returns {{state: string, path?: string, packages: Object[], malformed: number}}
|
|
168
|
+
* `state` is `ok`, `absent` (no database, or not Linux), `unreadable` (a
|
|
169
|
+
* database that could not be read in full) or `skipped` (a dry run).
|
|
170
|
+
* `malformed` counts the records left out for having no name or version.
|
|
171
|
+
* Each package has `name`, `version` and `fileCount`, `files`, and, when the
|
|
172
|
+
* record has them, `arch`, `origin`, `maintainer`, `license`, `url` and
|
|
173
|
+
* `description`.
|
|
174
|
+
*/
|
|
175
|
+
export function readApkInstalledDb(options = {}) {
|
|
176
|
+
const result = (state, extra = {}) => ({
|
|
177
|
+
state,
|
|
178
|
+
packages: [],
|
|
179
|
+
malformed: 0,
|
|
180
|
+
...extra,
|
|
181
|
+
});
|
|
182
|
+
const platform = options.platform || process.platform;
|
|
183
|
+
if (platform !== "linux") {
|
|
184
|
+
return result("absent");
|
|
185
|
+
}
|
|
186
|
+
const rootPath = options.rootPath || "/";
|
|
187
|
+
if (isDryRun) {
|
|
188
|
+
recordActivity({
|
|
189
|
+
capability: "apk-installed-db",
|
|
190
|
+
kind: "read",
|
|
191
|
+
reason:
|
|
192
|
+
"Dry run mode blocks reading the apk installed database, which lives outside the project.",
|
|
193
|
+
status: "blocked",
|
|
194
|
+
target: options.databaseFile || rootPath,
|
|
195
|
+
});
|
|
196
|
+
return result("skipped");
|
|
197
|
+
}
|
|
198
|
+
const candidates = options.databaseFile
|
|
199
|
+
? [options.databaseFile]
|
|
200
|
+
: APK_INSTALLED_DB_PATHS.map((location) => join(rootPath, location));
|
|
201
|
+
const file = candidates.find((candidate) => safeExistsSync(candidate));
|
|
202
|
+
if (!file) {
|
|
203
|
+
return result("absent");
|
|
204
|
+
}
|
|
205
|
+
const unreadable = (reason) => {
|
|
206
|
+
thoughtLog(`The apk installed database ${file} was not read: ${reason}.`);
|
|
207
|
+
recordActivity({
|
|
208
|
+
capability: "apk-installed-db",
|
|
209
|
+
kind: "read",
|
|
210
|
+
reason: `The apk installed database ${file} could not be read: ${reason}.`,
|
|
211
|
+
status: "failed",
|
|
212
|
+
target: file,
|
|
213
|
+
});
|
|
214
|
+
return result("unreadable", { path: file });
|
|
215
|
+
};
|
|
216
|
+
const maxBytes = options.maxBytes ?? MAX_APK_DATABASE_BYTES;
|
|
217
|
+
const text = readBounded(file, maxBytes);
|
|
218
|
+
if (text === undefined) {
|
|
219
|
+
return unreadable(`it is not a file of at most ${maxBytes} bytes`);
|
|
220
|
+
}
|
|
221
|
+
const maxPackages = options.maxPackages ?? MAX_APK_PACKAGES;
|
|
222
|
+
const { packages, malformed, overflow } = parseDatabase(
|
|
223
|
+
text,
|
|
224
|
+
options.wantedFiles,
|
|
225
|
+
maxPackages,
|
|
226
|
+
);
|
|
227
|
+
if (overflow) {
|
|
228
|
+
return unreadable(`it lists more than ${maxPackages} packages`);
|
|
229
|
+
}
|
|
230
|
+
if (malformed) {
|
|
231
|
+
thoughtLog(
|
|
232
|
+
`${malformed} record(s) of the apk installed database ${file} have no name or no version and were left out.`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
recordActivity({
|
|
236
|
+
capability: "apk-installed-db",
|
|
237
|
+
kind: "read",
|
|
238
|
+
reason: `Read ${packages.length} package(s) from the apk installed database ${file}.`,
|
|
239
|
+
status: "completed",
|
|
240
|
+
target: file,
|
|
241
|
+
});
|
|
242
|
+
return result("ok", { path: file, packages, malformed });
|
|
243
|
+
}
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
import { TRACE_MODE } from "../core/logger.js";
|
|
31
31
|
import { dirNameStr, isWin } from "../core/paths.js";
|
|
32
32
|
import { formatDuration, reapProcessTree } from "../core/processTree.js";
|
|
33
|
+
import { isProjectToolingAllowed } from "../core/projectTooling.js";
|
|
33
34
|
import { readJsonFile } from "../parsers/largeJson.js";
|
|
34
35
|
import { cmakeBuildDirCandidates } from "./cmakeBuildDirs.js";
|
|
35
36
|
|
|
@@ -314,6 +315,38 @@ export function atomCompileCommandsArgs(src, language, options = {}) {
|
|
|
314
315
|
return ["--frontend-args", `compile-commands=${database}`];
|
|
315
316
|
}
|
|
316
317
|
|
|
318
|
+
/**
|
|
319
|
+
* The arguments that stop atom's Java frontend from running the scanned
|
|
320
|
+
* project's build. In its default delombok mode, atom runs
|
|
321
|
+
* `mvn dependency:build-classpath` inside a Maven project, which loads the
|
|
322
|
+
* project's `.mvn` configuration and build extensions, so delombok and
|
|
323
|
+
* dependency fetching are turned off whenever the project's own tooling may
|
|
324
|
+
* not run.
|
|
325
|
+
*
|
|
326
|
+
* @param {string} language atom `-l` value
|
|
327
|
+
* @param {Object} options CLI options
|
|
328
|
+
* @returns {string[]|undefined} Arguments to add to the atom command, or
|
|
329
|
+
* undefined when the installed atom cannot be told to leave the build alone
|
|
330
|
+
*/
|
|
331
|
+
export function atomBuildToolArgs(language, options = {}) {
|
|
332
|
+
if (
|
|
333
|
+
`${language}`.toLowerCase() !== "java" ||
|
|
334
|
+
isProjectToolingAllowed(options)
|
|
335
|
+
) {
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
const keys = atomFrontendArgKeys(language);
|
|
339
|
+
if (!keys.has("delombok-mode")) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
return [
|
|
343
|
+
"--frontend-args",
|
|
344
|
+
keys.has("fetch-dependencies")
|
|
345
|
+
? "delombok-mode=no-delombok,fetch-dependencies=false"
|
|
346
|
+
: "delombok-mode=no-delombok",
|
|
347
|
+
];
|
|
348
|
+
}
|
|
349
|
+
|
|
317
350
|
// Absolute ceiling on atom's heap. Past this point a larger heap buys a
|
|
318
351
|
// collector that runs less often rather than an analysis that succeeds where it
|
|
319
352
|
// otherwise would not, while the reservation itself is what pushes a build
|