@cyclonedx/cdxgen 12.3.2 → 12.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 +70 -22
- package/bin/audit.js +21 -7
- package/bin/cdxgen.js +238 -116
- package/bin/convert.js +28 -13
- package/bin/hbom.js +490 -0
- package/bin/repl.js +580 -29
- package/bin/validate.js +34 -4
- package/bin/verify.js +40 -5
- package/data/README.md +298 -25
- package/data/component-tags.json +6 -0
- package/data/crypto-oid.json +16 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/queries-darwin.json +12 -1
- package/data/queries-win.json +7 -1
- package/data/queries.json +39 -2
- package/data/rules/ai-agent-governance.yaml +16 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/chrome-extensions.yaml +8 -0
- package/data/rules/ci-permissions.yaml +171 -15
- package/data/rules/container-risk.yaml +14 -7
- package/data/rules/dependency-sources.yaml +76 -5
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +18 -3
- package/data/rules/obom-runtime.yaml +907 -22
- package/data/rules/package-integrity.yaml +36 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +9 -0
- package/lib/audit/index.js +209 -8
- package/lib/audit/index.poku.js +332 -0
- package/lib/audit/reporters.js +222 -0
- package/lib/audit/targets.js +146 -1
- package/lib/audit/targets.poku.js +186 -0
- package/lib/cli/asar.poku.js +328 -0
- package/lib/cli/index.js +647 -127
- package/lib/cli/index.poku.js +1905 -187
- package/lib/evinser/evinser.js +14 -9
- package/lib/helpers/agentFormulationParser.js +6 -2
- package/lib/helpers/agentFormulationParser.poku.js +42 -0
- package/lib/helpers/analyzer.js +1444 -38
- package/lib/helpers/analyzer.poku.js +409 -0
- package/lib/helpers/analyzerScope.js +712 -0
- package/lib/helpers/asarutils.js +1556 -0
- package/lib/helpers/asarutils.poku.js +443 -0
- package/lib/helpers/auditCategories.js +12 -0
- package/lib/helpers/auditCategories.poku.js +32 -0
- package/lib/helpers/cbomutils.js +271 -1
- package/lib/helpers/cbomutils.poku.js +248 -5
- package/lib/helpers/chromextutils.js +25 -3
- package/lib/helpers/chromextutils.poku.js +68 -0
- package/lib/helpers/ciParsers/githubActions.js +79 -0
- package/lib/helpers/ciParsers/githubActions.poku.js +103 -0
- package/lib/helpers/communityAiConfigParser.js +15 -5
- package/lib/helpers/communityAiConfigParser.poku.js +71 -0
- package/lib/helpers/depsUtils.js +5 -0
- package/lib/helpers/depsUtils.poku.js +55 -0
- package/lib/helpers/display.js +336 -23
- package/lib/helpers/display.poku.js +179 -43
- package/lib/helpers/evidenceUtils.js +58 -0
- package/lib/helpers/evidenceUtils.poku.js +54 -0
- package/lib/helpers/exportUtils.js +9 -0
- package/lib/helpers/gtfobins.js +142 -8
- package/lib/helpers/gtfobins.poku.js +24 -1
- package/lib/helpers/hbom.js +710 -0
- package/lib/helpers/hbom.poku.js +496 -0
- package/lib/helpers/hbomAnalysis.js +268 -0
- package/lib/helpers/hbomAnalysis.poku.js +249 -0
- package/lib/helpers/hbomLoader.js +35 -0
- package/lib/helpers/hostTopology.js +803 -0
- package/lib/helpers/hostTopology.poku.js +363 -0
- package/lib/helpers/inventoryStats.js +69 -0
- package/lib/helpers/inventoryStats.poku.js +86 -0
- package/lib/helpers/lolbas.js +19 -1
- package/lib/helpers/lolbas.poku.js +23 -0
- package/lib/helpers/mcpConfigParser.js +21 -5
- package/lib/helpers/mcpConfigParser.poku.js +39 -2
- package/lib/helpers/osqueryTransform.js +47 -0
- package/lib/helpers/osqueryTransform.poku.js +47 -0
- package/lib/helpers/plugins.js +349 -0
- package/lib/helpers/plugins.poku.js +57 -0
- package/lib/helpers/propertySanitizer.js +121 -0
- package/lib/helpers/protobom.js +156 -45
- package/lib/helpers/protobom.poku.js +140 -5
- package/lib/helpers/remote/dependency-track.js +36 -3
- package/lib/helpers/remote/dependency-track.poku.js +44 -0
- package/lib/helpers/source.js +24 -0
- package/lib/helpers/source.poku.js +32 -0
- package/lib/helpers/utils.js +2454 -198
- package/lib/helpers/utils.poku.js +1798 -74
- package/lib/managers/binary.e2e.poku.js +367 -0
- package/lib/managers/binary.js +2306 -350
- package/lib/managers/binary.poku.js +1700 -1
- package/lib/managers/docker.js +441 -95
- package/lib/managers/docker.poku.js +1479 -14
- package/lib/server/server.js +2 -24
- package/lib/server/server.poku.js +36 -1
- package/lib/stages/postgen/annotator.js +38 -0
- package/lib/stages/postgen/annotator.poku.js +107 -1
- package/lib/stages/postgen/auditBom.js +121 -18
- package/lib/stages/postgen/auditBom.poku.js +2967 -990
- package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
- package/lib/stages/postgen/postgen.js +192 -1
- package/lib/stages/postgen/postgen.poku.js +321 -0
- package/lib/stages/postgen/ruleEngine.js +116 -0
- package/lib/stages/pregen/envAudit.js +14 -3
- package/package.json +24 -21
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +44 -0
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/reporters.d.ts +16 -0
- package/types/lib/audit/reporters.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +16 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +4 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +33 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/analyzerScope.d.ts +11 -0
- package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
- package/types/lib/helpers/asarutils.d.ts +34 -0
- package/types/lib/helpers/asarutils.d.ts.map +1 -0
- package/types/lib/helpers/auditCategories.d.ts +5 -0
- package/types/lib/helpers/auditCategories.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +3 -2
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/chromextutils.d.ts.map +1 -1
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
- package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +1 -0
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/evidenceUtils.d.ts +8 -0
- package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +8 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -1
- package/types/lib/helpers/hbom.d.ts +49 -0
- package/types/lib/helpers/hbom.d.ts.map +1 -0
- package/types/lib/helpers/hbomAnalysis.d.ts +62 -0
- package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/helpers/hbomLoader.d.ts +7 -0
- package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
- package/types/lib/helpers/hostTopology.d.ts +12 -0
- package/types/lib/helpers/hostTopology.d.ts.map +1 -0
- package/types/lib/helpers/inventoryStats.d.ts +11 -0
- package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/osqueryTransform.d.ts +3 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
- package/types/lib/helpers/plugins.d.ts +58 -0
- package/types/lib/helpers/plugins.d.ts.map +1 -0
- package/types/lib/helpers/propertySanitizer.d.ts +3 -0
- package/types/lib/helpers/propertySanitizer.d.ts.map +1 -0
- package/types/lib/helpers/protobom.d.ts +3 -4
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/helpers/source.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +74 -8
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +5 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +3 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +2 -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/auditBom.d.ts +26 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +2 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/data/spdx-model-v3.0.1.jsonld +0 -15999
|
@@ -112,6 +112,34 @@ const CARGO_CACHE_ACTION_PATTERNS = [/^swatinem\/rust-cache(?:@|$)/i];
|
|
|
112
112
|
|
|
113
113
|
const CARGO_TOOL_INSTALL_ACTION_PATTERNS = [/^taiki-e\/install-action(?:@|$)/i];
|
|
114
114
|
|
|
115
|
+
const DEPENDENCY_CACHE_SETUP_ACTIONS = [
|
|
116
|
+
{
|
|
117
|
+
pattern: /^actions\/setup-node(?:@|$)/i,
|
|
118
|
+
ecosystem: "npm",
|
|
119
|
+
inputNames: ["package-manager-cache", "cache"],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
pattern: /^actions\/setup-python(?:@|$)/i,
|
|
123
|
+
ecosystem: "pypi",
|
|
124
|
+
inputNames: ["cache"],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
pattern: /^actions\/setup-go(?:@|$)/i,
|
|
128
|
+
ecosystem: "go",
|
|
129
|
+
inputNames: ["cache"],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
pattern: /^actions\/setup-java(?:@|$)/i,
|
|
133
|
+
ecosystem: "java",
|
|
134
|
+
inputNames: ["cache"],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
pattern: /^moonrepo\/setup-rust(?:@|$)/i,
|
|
138
|
+
ecosystem: "cargo",
|
|
139
|
+
inputNames: ["cache"],
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
|
|
115
143
|
const FORK_CONTEXT_PATTERNS = [
|
|
116
144
|
[
|
|
117
145
|
"github.event.pull_request.head.repo.fork",
|
|
@@ -479,6 +507,56 @@ function analyzeCargoActionStep(step) {
|
|
|
479
507
|
return props;
|
|
480
508
|
}
|
|
481
509
|
|
|
510
|
+
function isExplicitFalseLikeValue(value) {
|
|
511
|
+
if (value === false) {
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
if (typeof value !== "string") {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
return ["0", "false", "no", "off", "disabled"].includes(
|
|
518
|
+
value.trim().toLowerCase(),
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function analyzeSetupActionCacheStep(step) {
|
|
523
|
+
const props = [];
|
|
524
|
+
if (!step?.uses || typeof step.uses !== "string") {
|
|
525
|
+
return props;
|
|
526
|
+
}
|
|
527
|
+
const setupAction = DEPENDENCY_CACHE_SETUP_ACTIONS.find((candidate) =>
|
|
528
|
+
candidate.pattern.test(step.uses),
|
|
529
|
+
);
|
|
530
|
+
if (!setupAction || !step.with || typeof step.with !== "object") {
|
|
531
|
+
return props;
|
|
532
|
+
}
|
|
533
|
+
const disableInputName = setupAction.inputNames.find(
|
|
534
|
+
(inputName) =>
|
|
535
|
+
Object.hasOwn(step.with, inputName) &&
|
|
536
|
+
isExplicitFalseLikeValue(step.with[inputName]),
|
|
537
|
+
);
|
|
538
|
+
if (!disableInputName) {
|
|
539
|
+
return props;
|
|
540
|
+
}
|
|
541
|
+
props.push({
|
|
542
|
+
name: "cdx:github:action:disablesBuildCache",
|
|
543
|
+
value: "true",
|
|
544
|
+
});
|
|
545
|
+
props.push({
|
|
546
|
+
name: "cdx:github:action:buildCacheEcosystem",
|
|
547
|
+
value: setupAction.ecosystem,
|
|
548
|
+
});
|
|
549
|
+
props.push({
|
|
550
|
+
name: "cdx:github:action:buildCacheDisableInput",
|
|
551
|
+
value: disableInputName,
|
|
552
|
+
});
|
|
553
|
+
props.push({
|
|
554
|
+
name: "cdx:github:action:buildCacheDisableValue",
|
|
555
|
+
value: String(step.with[disableInputName]),
|
|
556
|
+
});
|
|
557
|
+
return props;
|
|
558
|
+
}
|
|
559
|
+
|
|
482
560
|
function analyzeCargoRunStep(normalizedRun) {
|
|
483
561
|
const props = [];
|
|
484
562
|
if (!normalizedRun || typeof normalizedRun !== "string") {
|
|
@@ -2018,6 +2096,7 @@ export function parseWorkflowFile(f, options) {
|
|
|
2018
2096
|
actionProperties.push(...analyzeCheckoutStep(step));
|
|
2019
2097
|
actionProperties.push(...analyzeCacheStep(step));
|
|
2020
2098
|
actionProperties.push(...analyzeCargoActionStep(step));
|
|
2099
|
+
actionProperties.push(...analyzeSetupActionCacheStep(step));
|
|
2021
2100
|
actionProperties.push(...analyzeDispatchActionStep(step));
|
|
2022
2101
|
if (
|
|
2023
2102
|
step.uses?.includes("actions/github-script") &&
|
|
@@ -505,6 +505,109 @@ describe("githubActionsParser", () => {
|
|
|
505
505
|
});
|
|
506
506
|
});
|
|
507
507
|
|
|
508
|
+
describe("setup action cache disable property emission", () => {
|
|
509
|
+
it("emits cache disable properties for setup-node, setup-python, and setup-rust", () => {
|
|
510
|
+
const tmpDir = mkdtempSync(path.join(os.tmpdir(), "cdxgen-gha-cache-"));
|
|
511
|
+
const workflowFile = path.join(tmpDir, "cache-disable.yml");
|
|
512
|
+
writeFileSync(
|
|
513
|
+
workflowFile,
|
|
514
|
+
[
|
|
515
|
+
"name: Cache disable",
|
|
516
|
+
"on: push",
|
|
517
|
+
"jobs:",
|
|
518
|
+
" build:",
|
|
519
|
+
" runs-on: ubuntu-latest",
|
|
520
|
+
" steps:",
|
|
521
|
+
" - uses: actions/setup-node@v4",
|
|
522
|
+
" with:",
|
|
523
|
+
" node-version: 20",
|
|
524
|
+
" package-manager-cache: false",
|
|
525
|
+
" - uses: actions/setup-python@v5",
|
|
526
|
+
" with:",
|
|
527
|
+
" python-version: '3.12'",
|
|
528
|
+
" cache: false",
|
|
529
|
+
" - uses: moonrepo/setup-rust@v1",
|
|
530
|
+
" with:",
|
|
531
|
+
" cache: false",
|
|
532
|
+
].join("\n"),
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
try {
|
|
536
|
+
const result = parseWorkflowFile(workflowFile, { specVersion: 1.7 });
|
|
537
|
+
const setupNodeComp = result.components.find(
|
|
538
|
+
(component) =>
|
|
539
|
+
getProp(component, "cdx:github:action:uses") ===
|
|
540
|
+
"actions/setup-node@v4",
|
|
541
|
+
);
|
|
542
|
+
const setupPythonComp = result.components.find(
|
|
543
|
+
(component) =>
|
|
544
|
+
getProp(component, "cdx:github:action:uses") ===
|
|
545
|
+
"actions/setup-python@v5",
|
|
546
|
+
);
|
|
547
|
+
const setupRustComp = result.components.find(
|
|
548
|
+
(component) =>
|
|
549
|
+
getProp(component, "cdx:github:action:uses") ===
|
|
550
|
+
"moonrepo/setup-rust@v1",
|
|
551
|
+
);
|
|
552
|
+
assert.ok(setupNodeComp, "expected setup-node component");
|
|
553
|
+
assert.ok(setupPythonComp, "expected setup-python component");
|
|
554
|
+
assert.ok(setupRustComp, "expected setup-rust component");
|
|
555
|
+
assert.strictEqual(
|
|
556
|
+
getProp(setupNodeComp, "cdx:github:action:disablesBuildCache"),
|
|
557
|
+
"true",
|
|
558
|
+
);
|
|
559
|
+
assert.strictEqual(
|
|
560
|
+
getProp(setupNodeComp, "cdx:github:action:buildCacheEcosystem"),
|
|
561
|
+
"npm",
|
|
562
|
+
);
|
|
563
|
+
assert.strictEqual(
|
|
564
|
+
getProp(setupNodeComp, "cdx:github:action:buildCacheDisableInput"),
|
|
565
|
+
"package-manager-cache",
|
|
566
|
+
);
|
|
567
|
+
assert.strictEqual(
|
|
568
|
+
getProp(setupPythonComp, "cdx:github:action:disablesBuildCache"),
|
|
569
|
+
"true",
|
|
570
|
+
);
|
|
571
|
+
assert.strictEqual(
|
|
572
|
+
getProp(setupPythonComp, "cdx:github:action:buildCacheEcosystem"),
|
|
573
|
+
"pypi",
|
|
574
|
+
);
|
|
575
|
+
assert.strictEqual(
|
|
576
|
+
getProp(setupPythonComp, "cdx:github:action:buildCacheDisableInput"),
|
|
577
|
+
"cache",
|
|
578
|
+
);
|
|
579
|
+
assert.strictEqual(
|
|
580
|
+
getProp(setupRustComp, "cdx:github:action:disablesBuildCache"),
|
|
581
|
+
"true",
|
|
582
|
+
);
|
|
583
|
+
assert.strictEqual(
|
|
584
|
+
getProp(setupRustComp, "cdx:github:action:buildCacheEcosystem"),
|
|
585
|
+
"cargo",
|
|
586
|
+
);
|
|
587
|
+
assert.strictEqual(
|
|
588
|
+
getProp(setupRustComp, "cdx:github:action:buildCacheDisableInput"),
|
|
589
|
+
"cache",
|
|
590
|
+
);
|
|
591
|
+
} finally {
|
|
592
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it("does not emit cache disable properties when cache is not explicitly disabled", () => {
|
|
597
|
+
const result = parseWorkflow("simple-build.yml");
|
|
598
|
+
const setupNodeComp = result.components.find(
|
|
599
|
+
(component) =>
|
|
600
|
+
getProp(component, "cdx:github:action:uses") ===
|
|
601
|
+
"actions/setup-node@v4",
|
|
602
|
+
);
|
|
603
|
+
assert.ok(setupNodeComp, "expected setup-node component");
|
|
604
|
+
assert.strictEqual(
|
|
605
|
+
getProp(setupNodeComp, "cdx:github:action:disablesBuildCache"),
|
|
606
|
+
undefined,
|
|
607
|
+
);
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
|
|
508
611
|
describe("script injection interpolation detection", () => {
|
|
509
612
|
it("detects github.event.pull_request interpolation", () => {
|
|
510
613
|
const result = parseWorkflow("injection-pull-request-title.yml");
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
credentialIndicatorsForText,
|
|
9
9
|
sanitizeMcpRefToken,
|
|
10
10
|
} from "./mcpDiscovery.js";
|
|
11
|
+
import { sanitizeBomPropertyValue } from "./propertySanitizer.js";
|
|
11
12
|
import { scanTextForHiddenUnicode } from "./unicodeScan.js";
|
|
12
13
|
|
|
13
14
|
const COMMUNITY_AI_PATTERNS = [
|
|
@@ -46,13 +47,22 @@ const COMMUNITY_AI_PATTERNS = [
|
|
|
46
47
|
];
|
|
47
48
|
|
|
48
49
|
function addUniqueProperty(properties, name, value) {
|
|
49
|
-
|
|
50
|
+
const sanitizedValue = sanitizeBomPropertyValue(name, value);
|
|
51
|
+
if (
|
|
52
|
+
sanitizedValue === undefined ||
|
|
53
|
+
sanitizedValue === null ||
|
|
54
|
+
sanitizedValue === ""
|
|
55
|
+
) {
|
|
50
56
|
return;
|
|
51
57
|
}
|
|
52
|
-
if (
|
|
58
|
+
if (
|
|
59
|
+
properties.some(
|
|
60
|
+
(prop) => prop.name === name && prop.value === String(sanitizedValue),
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
53
63
|
return;
|
|
54
64
|
}
|
|
55
|
-
properties.push({ name, value: String(
|
|
65
|
+
properties.push({ name, value: String(sanitizedValue) });
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
function normalizeFilePath(filePath) {
|
|
@@ -217,7 +227,7 @@ function parseSkillFile(filePath, raw) {
|
|
|
217
227
|
addUniqueProperty(
|
|
218
228
|
component.properties,
|
|
219
229
|
"cdx:skill:metadata",
|
|
220
|
-
|
|
230
|
+
metadata.metadata,
|
|
221
231
|
);
|
|
222
232
|
}
|
|
223
233
|
maybeAddFileSignals(component.properties, filePath, raw);
|
|
@@ -399,7 +409,7 @@ function parseOpencodeConfig(filePath, raw) {
|
|
|
399
409
|
addUniqueProperty(
|
|
400
410
|
component.properties,
|
|
401
411
|
"cdx:agent:permission",
|
|
402
|
-
|
|
412
|
+
agentConfig.permission,
|
|
403
413
|
);
|
|
404
414
|
}
|
|
405
415
|
components.push(component);
|
|
@@ -60,4 +60,75 @@ describe("communityAiConfigParser", () => {
|
|
|
60
60
|
),
|
|
61
61
|
);
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
it("sanitizes secret-bearing AI inventory properties before emission", async () => {
|
|
65
|
+
const readFileSync = sinon.stub();
|
|
66
|
+
readFileSync.withArgs("/repo/opencode.json", "utf-8").returns(
|
|
67
|
+
JSON.stringify({
|
|
68
|
+
agent: {
|
|
69
|
+
release: {
|
|
70
|
+
description:
|
|
71
|
+
"Deploy with https://user:pass@example.com/release?access_token=abc#frag and sk_test_super_secret_value",
|
|
72
|
+
permission: {
|
|
73
|
+
endpoints: [
|
|
74
|
+
"https://user:pass@example.com/private?token=abc#frag",
|
|
75
|
+
],
|
|
76
|
+
__proto__: {
|
|
77
|
+
polluted: true,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
readFileSync
|
|
85
|
+
.withArgs("/repo/.claude/skills/release/SKILL.md", "utf-8")
|
|
86
|
+
.returns(
|
|
87
|
+
[
|
|
88
|
+
"---",
|
|
89
|
+
"name: release",
|
|
90
|
+
"description: Publish release notes",
|
|
91
|
+
"metadata:",
|
|
92
|
+
" endpoint: https://user:pass@example.com/skill?token=abc#frag",
|
|
93
|
+
" apiKey: sk_test_skill_secret_value",
|
|
94
|
+
"---",
|
|
95
|
+
"Use the release workflow.",
|
|
96
|
+
].join("\n"),
|
|
97
|
+
);
|
|
98
|
+
const { communityAiConfigParser } = await esmock(
|
|
99
|
+
"./communityAiConfigParser.js",
|
|
100
|
+
{
|
|
101
|
+
"node:fs": { readFileSync },
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const result = communityAiConfigParser.parse([
|
|
106
|
+
"/repo/opencode.json",
|
|
107
|
+
"/repo/.claude/skills/release/SKILL.md",
|
|
108
|
+
]);
|
|
109
|
+
const agent = result.components.find(
|
|
110
|
+
(component) => getProp(component, "cdx:file:kind") === "agent-config",
|
|
111
|
+
);
|
|
112
|
+
const skill = result.components.find(
|
|
113
|
+
(component) => getProp(component, "cdx:file:kind") === "skill-file",
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
assert.strictEqual(
|
|
117
|
+
getProp(agent, "cdx:agent:description"),
|
|
118
|
+
"Deploy with https://example.com/release and [redacted]",
|
|
119
|
+
);
|
|
120
|
+
assert.strictEqual(
|
|
121
|
+
getProp(agent, "cdx:agent:permission"),
|
|
122
|
+
JSON.stringify({
|
|
123
|
+
endpoints: ["https://example.com/private"],
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
assert.strictEqual(
|
|
127
|
+
getProp(skill, "cdx:skill:metadata"),
|
|
128
|
+
JSON.stringify({
|
|
129
|
+
endpoint: "https://example.com/skill",
|
|
130
|
+
apiKey: "[redacted]",
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
63
134
|
});
|
package/lib/helpers/depsUtils.js
CHANGED
|
@@ -272,6 +272,11 @@ export function trimComponents(components) {
|
|
|
272
272
|
if (!existIdent.methods) {
|
|
273
273
|
existIdent.methods = [];
|
|
274
274
|
}
|
|
275
|
+
if (aident.tools?.length) {
|
|
276
|
+
existIdent.tools = Array.from(
|
|
277
|
+
new Set([...(existIdent.tools || []), ...aident.tools]),
|
|
278
|
+
);
|
|
279
|
+
}
|
|
275
280
|
let isDup = false;
|
|
276
281
|
for (const emethod of existIdent.methods) {
|
|
277
282
|
if (emethod?.value === amethod?.value) {
|
|
@@ -208,6 +208,61 @@ describe("trimComponents()", () => {
|
|
|
208
208
|
{ alg: "SHA-256", content: "def456" },
|
|
209
209
|
]);
|
|
210
210
|
});
|
|
211
|
+
|
|
212
|
+
it("retains identity tool references when merging duplicate components", () => {
|
|
213
|
+
const components = [
|
|
214
|
+
{
|
|
215
|
+
name: "openssl",
|
|
216
|
+
version: "3.0.0",
|
|
217
|
+
purl: "pkg:rpm/redhat/openssl@3.0.0",
|
|
218
|
+
type: "library",
|
|
219
|
+
evidence: {
|
|
220
|
+
identity: [
|
|
221
|
+
{
|
|
222
|
+
field: "purl",
|
|
223
|
+
confidence: 1,
|
|
224
|
+
methods: [
|
|
225
|
+
{
|
|
226
|
+
technique: "binary-analysis",
|
|
227
|
+
confidence: 1,
|
|
228
|
+
value: "openssl",
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
tools: ["pkg:generic/trivy@0.1.0"],
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: "openssl",
|
|
238
|
+
version: "3.0.0",
|
|
239
|
+
purl: "pkg:rpm/redhat/openssl@3.0.0",
|
|
240
|
+
type: "library",
|
|
241
|
+
evidence: {
|
|
242
|
+
identity: [
|
|
243
|
+
{
|
|
244
|
+
field: "purl",
|
|
245
|
+
confidence: 1,
|
|
246
|
+
methods: [
|
|
247
|
+
{
|
|
248
|
+
technique: "binary-analysis",
|
|
249
|
+
confidence: 1,
|
|
250
|
+
value: "openssl",
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
tools: ["pkg:generic/blint@1.2.3"],
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
const result = trimComponents(components);
|
|
260
|
+
assert.strictEqual(result.length, 1);
|
|
261
|
+
assert.deepStrictEqual(result[0].evidence.identity[0].tools, [
|
|
262
|
+
"pkg:generic/trivy@0.1.0",
|
|
263
|
+
"pkg:generic/blint@1.2.3",
|
|
264
|
+
]);
|
|
265
|
+
});
|
|
211
266
|
});
|
|
212
267
|
|
|
213
268
|
describe("mergeServices()", () => {
|