@cyclonedx/cdxgen 12.1.4 → 12.2.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 +47 -39
- package/bin/cdxgen.js +181 -90
- package/bin/evinse.js +4 -4
- package/bin/repl.js +3 -3
- package/bin/sign.js +102 -0
- package/bin/validate.js +233 -0
- package/bin/verify.js +69 -28
- package/data/queries.json +1 -1
- package/data/rules/ci-permissions.yaml +186 -0
- package/data/rules/dependency-sources.yaml +123 -0
- package/data/rules/package-integrity.yaml +135 -0
- package/data/rules/vscode-extensions.yaml +228 -0
- package/lib/cli/index.js +484 -440
- package/lib/evinser/db.js +137 -0
- package/lib/{helpers → evinser}/db.poku.js +2 -6
- package/lib/evinser/evinser.js +5 -18
- package/lib/evinser/swiftsem.js +1 -1
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/bomSigner.poku.js +156 -0
- package/lib/helpers/caxa.js +1 -1
- package/lib/helpers/ciParsers/azurePipelines.js +295 -0
- package/lib/helpers/ciParsers/azurePipelines.poku.js +253 -0
- package/lib/helpers/ciParsers/circleCi.js +286 -0
- package/lib/helpers/ciParsers/circleCi.poku.js +230 -0
- package/lib/helpers/ciParsers/common.js +24 -0
- package/lib/helpers/ciParsers/githubActions.js +636 -0
- package/lib/helpers/ciParsers/githubActions.poku.js +802 -0
- package/lib/helpers/ciParsers/gitlabCi.js +213 -0
- package/lib/helpers/ciParsers/gitlabCi.poku.js +247 -0
- package/lib/helpers/ciParsers/jenkins.js +181 -0
- package/lib/helpers/ciParsers/jenkins.poku.js +197 -0
- package/lib/helpers/depsUtils.js +203 -0
- package/lib/helpers/depsUtils.poku.js +150 -0
- package/lib/helpers/display.js +429 -14
- package/lib/helpers/envcontext.js +23 -8
- package/lib/helpers/formulationParsers.js +351 -0
- package/lib/helpers/logger.js +14 -0
- package/lib/helpers/protobom.js +9 -9
- package/lib/helpers/pythonutils.js +305 -0
- package/lib/helpers/pythonutils.poku.js +469 -0
- package/lib/helpers/utils.js +970 -528
- package/lib/helpers/utils.poku.js +139 -256
- package/lib/helpers/versutils.js +202 -0
- package/lib/helpers/versutils.poku.js +315 -0
- package/lib/helpers/vsixutils.js +1061 -0
- package/lib/helpers/vsixutils.poku.js +2247 -0
- package/lib/managers/binary.js +19 -19
- package/lib/managers/docker.js +108 -1
- package/lib/managers/oci.js +10 -0
- package/lib/managers/piptree.js +4 -10
- package/lib/parsers/npmrc.js +92 -0
- package/lib/parsers/npmrc.poku.js +528 -0
- package/lib/server/openapi.yaml +1 -10
- package/lib/server/server.js +58 -16
- package/lib/server/server.poku.js +123 -144
- package/lib/stages/postgen/annotator.js +1 -1
- package/lib/stages/postgen/auditBom.js +197 -0
- package/lib/stages/postgen/auditBom.poku.js +378 -0
- package/lib/stages/postgen/postgen.js +54 -1
- package/lib/stages/postgen/postgen.poku.js +90 -1
- package/lib/stages/postgen/ruleEngine.js +369 -0
- package/lib/stages/pregen/envAudit.js +299 -0
- package/lib/stages/pregen/envAudit.poku.js +572 -0
- package/lib/stages/pregen/pregen.js +12 -8
- package/lib/third-party/arborist/lib/deepest-nesting-target.js +1 -1
- package/lib/third-party/arborist/lib/node.js +3 -3
- package/lib/third-party/arborist/lib/shrinkwrap.js +1 -1
- package/lib/third-party/arborist/lib/tree-check.js +1 -1
- package/lib/{helpers/validator.js → validator/bomValidator.js} +107 -47
- package/lib/validator/complianceEngine.js +241 -0
- package/lib/validator/complianceEngine.poku.js +168 -0
- package/lib/validator/complianceRules.js +1610 -0
- package/lib/validator/complianceRules.poku.js +328 -0
- package/lib/validator/index.js +222 -0
- package/lib/validator/index.poku.js +144 -0
- package/lib/validator/reporters/annotations.js +121 -0
- package/lib/validator/reporters/console.js +149 -0
- package/lib/validator/reporters/index.js +41 -0
- package/lib/validator/reporters/json.js +37 -0
- package/lib/validator/reporters/sarif.js +184 -0
- package/lib/validator/reporters.poku.js +150 -0
- package/package.json +8 -8
- package/types/bin/sign.d.ts +3 -0
- package/types/bin/sign.d.ts.map +1 -0
- package/types/bin/validate.d.ts +3 -0
- package/types/bin/validate.d.ts.map +1 -0
- package/types/helpers/utils.d.ts +0 -1
- package/types/lib/cli/index.d.ts +49 -52
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/db.d.ts +34 -0
- package/types/lib/evinser/db.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +63 -16
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/bomSigner.d.ts +27 -0
- package/types/lib/helpers/bomSigner.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/azurePipelines.d.ts +17 -0
- package/types/lib/helpers/ciParsers/azurePipelines.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/circleCi.d.ts +17 -0
- package/types/lib/helpers/ciParsers/circleCi.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/common.d.ts +11 -0
- package/types/lib/helpers/ciParsers/common.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/githubActions.d.ts +34 -0
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/gitlabCi.d.ts +17 -0
- package/types/lib/helpers/ciParsers/gitlabCi.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/jenkins.d.ts +17 -0
- package/types/lib/helpers/ciParsers/jenkins.d.ts.map +1 -0
- package/types/lib/helpers/depsUtils.d.ts +21 -0
- package/types/lib/helpers/depsUtils.d.ts.map +1 -0
- package/types/lib/helpers/display.d.ts +111 -11
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/envcontext.d.ts +19 -7
- package/types/lib/helpers/envcontext.d.ts.map +1 -1
- package/types/lib/helpers/formulationParsers.d.ts +50 -0
- package/types/lib/helpers/formulationParsers.d.ts.map +1 -0
- package/types/lib/helpers/logger.d.ts +15 -1
- package/types/lib/helpers/logger.d.ts.map +1 -1
- package/types/lib/helpers/protobom.d.ts +2 -2
- package/types/lib/helpers/pythonutils.d.ts +18 -0
- package/types/lib/helpers/pythonutils.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +532 -128
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/helpers/versutils.d.ts +8 -0
- package/types/lib/helpers/versutils.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +130 -0
- package/types/lib/helpers/vsixutils.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts +12 -31
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +11 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/managers/piptree.d.ts.map +1 -1
- package/types/lib/parsers/npmrc.d.ts +26 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +21 -2
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts +20 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +8 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
- package/types/lib/stages/pregen/envAudit.d.ts +8 -0
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/{helpers/validator.d.ts → validator/bomValidator.d.ts} +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -0
- package/types/lib/validator/complianceEngine.d.ts +66 -0
- package/types/lib/validator/complianceEngine.d.ts.map +1 -0
- package/types/lib/validator/complianceRules.d.ts +70 -0
- package/types/lib/validator/complianceRules.d.ts.map +1 -0
- package/types/lib/validator/index.d.ts +70 -0
- package/types/lib/validator/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/annotations.d.ts +31 -0
- package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
- package/types/lib/validator/reporters/console.d.ts +30 -0
- package/types/lib/validator/reporters/console.d.ts.map +1 -0
- package/types/lib/validator/reporters/index.d.ts +21 -0
- package/types/lib/validator/reporters/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/json.d.ts +11 -0
- package/types/lib/validator/reporters/json.d.ts.map +1 -0
- package/types/lib/validator/reporters/sarif.d.ts +16 -0
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
- package/lib/helpers/db.js +0 -162
- package/types/helpers/db.d.ts +0 -35
- package/types/helpers/db.d.ts.map +0 -1
- package/types/lib/helpers/db.d.ts +0 -35
- package/types/lib/helpers/db.d.ts.map +0 -1
- package/types/lib/helpers/validator.d.ts.map +0 -1
- package/types/managers/binary.d.ts +0 -37
- package/types/managers/binary.d.ts.map +0 -1
- package/types/managers/docker.d.ts +0 -56
- package/types/managers/docker.d.ts.map +0 -1
- package/types/managers/oci.d.ts +0 -2
- package/types/managers/oci.d.ts.map +0 -1
- package/types/managers/piptree.d.ts +0 -2
- package/types/managers/piptree.d.ts.map +0 -1
- package/types/server/server.d.ts +0 -34
- package/types/server/server.d.ts.map +0 -1
- package/types/stages/postgen/annotator.d.ts +0 -27
- package/types/stages/postgen/annotator.d.ts.map +0 -1
- package/types/stages/postgen/postgen.d.ts +0 -51
- package/types/stages/postgen/postgen.d.ts.map +0 -1
- package/types/stages/pregen/pregen.d.ts +0 -59
- package/types/stages/pregen/pregen.d.ts.map +0 -1
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
|
|
3
|
+
import { v4 as uuidv4 } from "uuid";
|
|
4
|
+
|
|
5
|
+
import { collectOSCryptoLibs } from "./cbomutils.js";
|
|
6
|
+
import { azurePipelinesParser } from "./ciParsers/azurePipelines.js";
|
|
7
|
+
import { circleCiParser } from "./ciParsers/circleCi.js";
|
|
8
|
+
import { githubActionsParser } from "./ciParsers/githubActions.js";
|
|
9
|
+
import { gitlabCiParser } from "./ciParsers/gitlabCi.js";
|
|
10
|
+
import { jenkinsParser } from "./ciParsers/jenkins.js";
|
|
11
|
+
import { trimComponents } from "./depsUtils.js";
|
|
12
|
+
import {
|
|
13
|
+
collectEnvInfo,
|
|
14
|
+
getBranch,
|
|
15
|
+
getOriginUrl,
|
|
16
|
+
gitTreeHashes,
|
|
17
|
+
listFiles,
|
|
18
|
+
} from "./envcontext.js";
|
|
19
|
+
import { getAllFiles } from "./utils.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The parser registry. Pre-populated with the five built-in CI system parsers.
|
|
23
|
+
*
|
|
24
|
+
* External parsers added via {@link registerParser} are appended here.
|
|
25
|
+
*
|
|
26
|
+
* Each entry must satisfy the FormulationParser contract:
|
|
27
|
+
* ```
|
|
28
|
+
* {
|
|
29
|
+
* id: string, // unique stable identifier
|
|
30
|
+
* patterns: string[], // non-empty array of glob patterns for file discovery
|
|
31
|
+
* parse(files: string[], options: Object): // synchronous function
|
|
32
|
+
* { workflows?, components?, services?, properties?, dependencies? }
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
const _parsers = [
|
|
37
|
+
githubActionsParser,
|
|
38
|
+
gitlabCiParser,
|
|
39
|
+
jenkinsParser,
|
|
40
|
+
circleCiParser,
|
|
41
|
+
azurePipelinesParser,
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Register an external formulation parser.
|
|
46
|
+
*
|
|
47
|
+
* The parser is appended to the registry and will be invoked by
|
|
48
|
+
* {@link addFormulationSection} on the next call.
|
|
49
|
+
*
|
|
50
|
+
* @param {{ id: string, patterns: string[], parse: Function }} parser
|
|
51
|
+
*/
|
|
52
|
+
export function registerParser(parser) {
|
|
53
|
+
const hasValidPatterns =
|
|
54
|
+
Array.isArray(parser?.patterns) &&
|
|
55
|
+
parser.patterns.length > 0 &&
|
|
56
|
+
parser.patterns.every(
|
|
57
|
+
(pattern) => typeof pattern === "string" && pattern.trim().length > 0,
|
|
58
|
+
);
|
|
59
|
+
if (
|
|
60
|
+
typeof parser?.id !== "string" ||
|
|
61
|
+
parser.id.trim().length === 0 ||
|
|
62
|
+
!hasValidPatterns ||
|
|
63
|
+
typeof parser?.parse !== "function"
|
|
64
|
+
) {
|
|
65
|
+
throw new TypeError(
|
|
66
|
+
"registerParser: parser must have id (string), patterns (non-empty string[]), and parse (function)",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
_parsers.push(parser);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Return a shallow copy of the currently registered parsers.
|
|
74
|
+
*
|
|
75
|
+
* @returns {Array<{ id: string, patterns: string[], parse: Function }>}
|
|
76
|
+
*/
|
|
77
|
+
export function getParsers() {
|
|
78
|
+
return [..._parsers];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Environment-variable prefixes whose values are safe to include in the
|
|
83
|
+
* formulation section. All other variables are ignored.
|
|
84
|
+
*/
|
|
85
|
+
const ENV_PREFIXES = [
|
|
86
|
+
"GIT_",
|
|
87
|
+
"ANDROID_",
|
|
88
|
+
"DENO_",
|
|
89
|
+
"DOTNET_",
|
|
90
|
+
"JAVA_",
|
|
91
|
+
"SDKMAN_",
|
|
92
|
+
"CARGO_",
|
|
93
|
+
"CONDA_",
|
|
94
|
+
"RUST",
|
|
95
|
+
"GEM_",
|
|
96
|
+
"SCALA_",
|
|
97
|
+
"MAVEN_",
|
|
98
|
+
"GRADLE_",
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Sub-strings that, when found (case-insensitively) in the variable *name*
|
|
103
|
+
* or *value*, cause the variable to be excluded from the formulation section.
|
|
104
|
+
*
|
|
105
|
+
* This blocklist is intentionally conservative to avoid leaking secrets.
|
|
106
|
+
* Common CI tokens and credentials patterns are enumerated explicitly.
|
|
107
|
+
*/
|
|
108
|
+
const ENV_BLOCKLIST = [
|
|
109
|
+
"key",
|
|
110
|
+
"token",
|
|
111
|
+
"pass",
|
|
112
|
+
"secret",
|
|
113
|
+
"user",
|
|
114
|
+
"email",
|
|
115
|
+
"auth",
|
|
116
|
+
"session",
|
|
117
|
+
"proxy",
|
|
118
|
+
"cred",
|
|
119
|
+
"askpass",
|
|
120
|
+
"api_key",
|
|
121
|
+
"apikey",
|
|
122
|
+
"private",
|
|
123
|
+
"signature",
|
|
124
|
+
"webhook",
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Build the formulation section for a CycloneDX BOM.
|
|
129
|
+
*
|
|
130
|
+
* This function is the top-level aggregator: it collects git metadata,
|
|
131
|
+
* invokes every registered CI parser, and merges the results into a single
|
|
132
|
+
* CycloneDX formulation entry.
|
|
133
|
+
*
|
|
134
|
+
* The function falls back to a minimal stub workflow when no CI config files
|
|
135
|
+
* are detected at the given path.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} filePath File path
|
|
138
|
+
* @param {Object} options CLI options; `options.path` is used as the
|
|
139
|
+
* project root for file discovery.
|
|
140
|
+
* @param {Object} [context={}] Optional context object. If it contains a
|
|
141
|
+
* non-empty `formulationList` array those
|
|
142
|
+
* components are merged into the result.
|
|
143
|
+
*
|
|
144
|
+
* @returns {{ formulation: Object[], dependencies: Object[] }}
|
|
145
|
+
* `formulation` – array to be placed at `bomJson.formulation`
|
|
146
|
+
* `dependencies` – dependency objects to be merged into
|
|
147
|
+
* `bomJson.dependencies` via `mergeDependencies`
|
|
148
|
+
*/
|
|
149
|
+
export function addFormulationSection(filePath, options, context = {}) {
|
|
150
|
+
const projectPath = filePath;
|
|
151
|
+
const formulation = [];
|
|
152
|
+
const dependencies = [];
|
|
153
|
+
|
|
154
|
+
// ── Git metadata ─────────────────────────────────────────────────────────
|
|
155
|
+
const gitBranch = getBranch(undefined, projectPath);
|
|
156
|
+
const originUrl = getOriginUrl(projectPath);
|
|
157
|
+
const gitFiles = listFiles(projectPath);
|
|
158
|
+
const treeHashes = gitTreeHashes(projectPath);
|
|
159
|
+
|
|
160
|
+
let components = [];
|
|
161
|
+
|
|
162
|
+
// Reuse any existing formulation components (e.g. from Pixi lock data)
|
|
163
|
+
// See: PR #1172
|
|
164
|
+
if (context?.formulationList?.length) {
|
|
165
|
+
components = components.concat(trimComponents(context.formulationList));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// OmniBOR / Artifact Dependency Graph components (spec 1.6+)
|
|
169
|
+
let parentOmniborId;
|
|
170
|
+
let treeOmniborId;
|
|
171
|
+
if (options.specVersion >= 1.6 && Object.keys(treeHashes).length === 2) {
|
|
172
|
+
// treeHashes.parent is the parent commit SHA → gitoid:commit:sha1:
|
|
173
|
+
// treeHashes.tree is the git tree object SHA → gitoid:tree:sha1:
|
|
174
|
+
parentOmniborId = `gitoid:commit:sha1:${treeHashes.parent}`;
|
|
175
|
+
treeOmniborId = `gitoid:tree:sha1:${treeHashes.tree}`;
|
|
176
|
+
components.push({
|
|
177
|
+
type: "file",
|
|
178
|
+
name: "git-parent",
|
|
179
|
+
description: "Git Parent Node.",
|
|
180
|
+
"bom-ref": parentOmniborId,
|
|
181
|
+
omniborId: [parentOmniborId],
|
|
182
|
+
swhid: [`swh:1:rev:${treeHashes.parent}`],
|
|
183
|
+
});
|
|
184
|
+
components.push({
|
|
185
|
+
type: "file",
|
|
186
|
+
name: "git-tree",
|
|
187
|
+
description: "Git Tree Node.",
|
|
188
|
+
"bom-ref": treeOmniborId,
|
|
189
|
+
omniborId: [treeOmniborId],
|
|
190
|
+
swhid: [`swh:1:dir:${treeHashes.tree}`],
|
|
191
|
+
});
|
|
192
|
+
// OmniBOR linkage goes into the top-level dependencies array
|
|
193
|
+
dependencies.push({ ref: parentOmniborId, provides: [treeOmniborId] });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Git file list
|
|
197
|
+
if (gitBranch && gitFiles?.length) {
|
|
198
|
+
const gitFileComponents = gitFiles.map((f) =>
|
|
199
|
+
options.specVersion >= 1.6
|
|
200
|
+
? {
|
|
201
|
+
type: "file",
|
|
202
|
+
name: f.name,
|
|
203
|
+
version: f.hash,
|
|
204
|
+
"bom-ref": f.omniborId,
|
|
205
|
+
omniborId: [f.omniborId],
|
|
206
|
+
swhid: [f.swhid],
|
|
207
|
+
}
|
|
208
|
+
: {
|
|
209
|
+
type: "file",
|
|
210
|
+
name: f.name,
|
|
211
|
+
version: f.hash,
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
components = components.concat(gitFileComponents);
|
|
215
|
+
|
|
216
|
+
// Complete the Artifact Dependency Graph: tree → blob links
|
|
217
|
+
if (options.specVersion >= 1.6 && treeOmniborId) {
|
|
218
|
+
dependencies.push({
|
|
219
|
+
ref: treeOmniborId,
|
|
220
|
+
provides: gitFiles.map((f) => f.omniborId).filter(Boolean),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Build environment details (Java, .NET, Python, Node, GCC, Rust, Go, Ruby)
|
|
226
|
+
const infoComponents = collectEnvInfo(projectPath);
|
|
227
|
+
if (infoComponents?.length) {
|
|
228
|
+
components = components.concat(infoComponents);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// OS crypto libraries (cbom mode)
|
|
232
|
+
if (options.includeCrypto) {
|
|
233
|
+
const cryptoLibs = collectOSCryptoLibs(options);
|
|
234
|
+
if (cryptoLibs?.length) {
|
|
235
|
+
components = components.concat(cryptoLibs);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ── CI parser dispatch ────────────────────────────────────────────────────
|
|
240
|
+
const ciWorkflows = [];
|
|
241
|
+
const ciComponents = [];
|
|
242
|
+
const ciServices = [];
|
|
243
|
+
const ciProperties = [];
|
|
244
|
+
|
|
245
|
+
const discoveryPath = projectPath || ".";
|
|
246
|
+
|
|
247
|
+
for (const parser of _parsers) {
|
|
248
|
+
const matchedFiles = [];
|
|
249
|
+
for (const pattern of parser.patterns) {
|
|
250
|
+
const found = getAllFiles(discoveryPath, pattern, options);
|
|
251
|
+
if (found?.length) {
|
|
252
|
+
matchedFiles.push(...found);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const uniqueMatchedFiles = [...new Set(matchedFiles)];
|
|
256
|
+
if (!uniqueMatchedFiles.length) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let result;
|
|
261
|
+
try {
|
|
262
|
+
result = parser.parse(uniqueMatchedFiles, options);
|
|
263
|
+
} catch (err) {
|
|
264
|
+
// A broken parser must not kill SBOM generation
|
|
265
|
+
console.warn(
|
|
266
|
+
`[formulationParsers] Parser "${parser.id}" threw an error:`,
|
|
267
|
+
err.message,
|
|
268
|
+
);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (result?.workflows?.length) {
|
|
273
|
+
ciWorkflows.push(...result.workflows);
|
|
274
|
+
}
|
|
275
|
+
if (result?.components?.length) {
|
|
276
|
+
ciComponents.push(...result.components);
|
|
277
|
+
}
|
|
278
|
+
if (result?.services?.length) {
|
|
279
|
+
ciServices.push(...result.services);
|
|
280
|
+
}
|
|
281
|
+
if (result?.properties?.length) {
|
|
282
|
+
ciProperties.push(...result.properties);
|
|
283
|
+
}
|
|
284
|
+
if (result?.dependencies?.length) {
|
|
285
|
+
dependencies.push(...result.dependencies);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Merge CI components into the formulation component list
|
|
290
|
+
if (ciComponents.length) {
|
|
291
|
+
components = components.concat(ciComponents);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ── Environment variables ─────────────────────────────────────────────────
|
|
295
|
+
let environmentVars = gitBranch?.length
|
|
296
|
+
? [{ name: "GIT_BRANCH", value: gitBranch }]
|
|
297
|
+
: [];
|
|
298
|
+
|
|
299
|
+
for (const aevar of Object.keys(process.env)) {
|
|
300
|
+
const lower = aevar.toLowerCase();
|
|
301
|
+
const value = process.env[aevar] ?? "";
|
|
302
|
+
if (
|
|
303
|
+
ENV_PREFIXES.some((p) => aevar.startsWith(p)) &&
|
|
304
|
+
!ENV_BLOCKLIST.some((b) => lower.includes(b)) &&
|
|
305
|
+
!ENV_BLOCKLIST.some((b) => value.toLowerCase().includes(b)) &&
|
|
306
|
+
value.length
|
|
307
|
+
) {
|
|
308
|
+
environmentVars.push({ name: aevar, value });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!environmentVars.length) {
|
|
313
|
+
environmentVars = undefined;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ── Assemble formulation object ───────────────────────────────────────────
|
|
317
|
+
const aformulation = {
|
|
318
|
+
"bom-ref": uuidv4(),
|
|
319
|
+
components: trimComponents(components),
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
if (ciServices.length) {
|
|
323
|
+
aformulation.services = ciServices;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (ciProperties.length) {
|
|
327
|
+
aformulation.properties = ciProperties;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Use CI-detected workflows; fall back to a minimal stub when none found
|
|
331
|
+
if (ciWorkflows.length) {
|
|
332
|
+
aformulation.workflows = ciWorkflows;
|
|
333
|
+
} else {
|
|
334
|
+
let sourceInput;
|
|
335
|
+
if (environmentVars) {
|
|
336
|
+
sourceInput = { environmentVars };
|
|
337
|
+
}
|
|
338
|
+
const sourceWorkflow = {
|
|
339
|
+
"bom-ref": uuidv4(),
|
|
340
|
+
uid: uuidv4(),
|
|
341
|
+
taskTypes: originUrl ? ["build", "clone"] : ["build"],
|
|
342
|
+
};
|
|
343
|
+
if (sourceInput) {
|
|
344
|
+
sourceWorkflow.inputs = [sourceInput];
|
|
345
|
+
}
|
|
346
|
+
aformulation.workflows = [sourceWorkflow];
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
formulation.push(aformulation);
|
|
350
|
+
return { formulation, dependencies };
|
|
351
|
+
}
|
package/lib/helpers/logger.js
CHANGED
|
@@ -44,6 +44,14 @@ const traceLogger = new Console({
|
|
|
44
44
|
if (THINK_MODE) {
|
|
45
45
|
thinkLogger.group(colorizeText("<think>"));
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Logs a thought message to the think logger if THINK_MODE is enabled.
|
|
49
|
+
* Automatically appends a period to the message if it lacks terminal punctuation.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} s The thought message to log
|
|
52
|
+
* @param {Object} [args] Optional additional arguments to log alongside the message
|
|
53
|
+
* @returns {void}
|
|
54
|
+
*/
|
|
47
55
|
export function thoughtLog(s, args) {
|
|
48
56
|
if (!THINK_MODE) {
|
|
49
57
|
return;
|
|
@@ -58,6 +66,12 @@ export function thoughtLog(s, args) {
|
|
|
58
66
|
thinkLogger.log(colorizeText(`${s}`));
|
|
59
67
|
}
|
|
60
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Closes the think log group by emitting the closing `</think>` marker.
|
|
71
|
+
* Has no effect if THINK_MODE is not enabled.
|
|
72
|
+
*
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
61
75
|
export function thoughtEnd() {
|
|
62
76
|
if (THINK_MODE) {
|
|
63
77
|
thinkLogger.groupEnd();
|
package/lib/helpers/protobom.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { cdx_16, cdx_17 } from "@appthreat/cdx-proto";
|
|
4
4
|
import {
|
|
5
5
|
fromBinary,
|
|
6
6
|
fromJsonString,
|
|
@@ -32,10 +32,10 @@ const stringifyIfNeeded = (bomJson) => {
|
|
|
32
32
|
export const writeBinary = (bomJson, binFile) => {
|
|
33
33
|
if (bomJson && binFile) {
|
|
34
34
|
let bomSchema;
|
|
35
|
-
if (+bomJson.specVersion === 1.
|
|
36
|
-
bomSchema =
|
|
35
|
+
if (+bomJson.specVersion === 1.7) {
|
|
36
|
+
bomSchema = cdx_17.BomSchema;
|
|
37
37
|
} else {
|
|
38
|
-
bomSchema =
|
|
38
|
+
bomSchema = cdx_16.BomSchema;
|
|
39
39
|
}
|
|
40
40
|
writeFileSync(
|
|
41
41
|
binFile,
|
|
@@ -57,17 +57,17 @@ export const writeBinary = (bomJson, binFile) => {
|
|
|
57
57
|
*
|
|
58
58
|
* @param {string} binFile Binary file name
|
|
59
59
|
* @param {boolean} asJson Convert to JSON
|
|
60
|
-
* @param {number} specVersion Specification version. Defaults to 1.
|
|
60
|
+
* @param {number} specVersion Specification version. Defaults to 1.7
|
|
61
61
|
*/
|
|
62
|
-
export const readBinary = (binFile, asJson = true, specVersion = 1.
|
|
62
|
+
export const readBinary = (binFile, asJson = true, specVersion = 1.7) => {
|
|
63
63
|
if (!safeExistsSync(binFile)) {
|
|
64
64
|
return undefined;
|
|
65
65
|
}
|
|
66
66
|
let bomSchema;
|
|
67
|
-
if (specVersion === 1.
|
|
68
|
-
bomSchema =
|
|
67
|
+
if (specVersion === 1.7) {
|
|
68
|
+
bomSchema = cdx_17.BomSchema;
|
|
69
69
|
} else {
|
|
70
|
-
bomSchema =
|
|
70
|
+
bomSchema = cdx_16.BomSchema;
|
|
71
71
|
}
|
|
72
72
|
const bomObject = fromBinary(bomSchema, readFileSync(binFile), {
|
|
73
73
|
readUnknownFields: true,
|