@cyclonedx/cdxgen 12.1.5 → 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 +175 -96
- package/bin/evinse.js +4 -4
- package/bin/repl.js +1 -1
- 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 +327 -372
- package/lib/evinser/db.js +137 -0
- package/lib/{helpers → evinser}/db.poku.js +2 -6
- package/lib/evinser/evinser.js +2 -14
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/bomSigner.poku.js +156 -0
- 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 +423 -4
- package/lib/helpers/envcontext.js +18 -3
- 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 +9 -0
- package/lib/helpers/utils.js +681 -406
- package/lib/helpers/utils.poku.js +55 -255
- 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 +3 -9
- package/lib/parsers/npmrc.js +17 -13
- package/lib/parsers/npmrc.poku.js +41 -5
- package/lib/server/openapi.yaml +1 -1
- package/lib/server/server.js +40 -11
- 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/{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 +10 -1
- package/types/lib/helpers/pythonutils.d.ts.map +1 -1
- 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 +4 -1
- package/types/lib/parsers/npmrc.d.ts.map +1 -1
- 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/lib/stages/pregen/env-audit.js +0 -34
- package/lib/stages/pregen/env-audit.poku.js +0 -290
- 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/lib/stages/pregen/env-audit.d.ts +0 -2
- package/types/lib/stages/pregen/env-audit.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
|
@@ -11,53 +11,71 @@ import {
|
|
|
11
11
|
validateAndRejectGitSource,
|
|
12
12
|
} from "./server.js";
|
|
13
13
|
|
|
14
|
+
function nullProtoObj(obj) {
|
|
15
|
+
if (obj === null || typeof obj !== "object") {
|
|
16
|
+
return obj;
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(obj)) {
|
|
19
|
+
return obj.map(nullProtoObj);
|
|
20
|
+
}
|
|
21
|
+
if (Object.prototype.toString.call(obj) === "[object Object]") {
|
|
22
|
+
const result = Object.create(null);
|
|
23
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
24
|
+
result[key] = nullProtoObj(value);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function checkEqual(actual, expected, message) {
|
|
32
|
+
assert.deepStrictEqual(nullProtoObj(actual), nullProtoObj(expected), message);
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
it("parseValue tests", () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
36
|
+
checkEqual(parseValue("foo"), "foo");
|
|
37
|
+
checkEqual(parseValue("foo\n"), "foo");
|
|
38
|
+
checkEqual(parseValue("foo\r\n"), "foo");
|
|
39
|
+
checkEqual(parseValue(1), 1);
|
|
40
|
+
checkEqual(parseValue("true"), true);
|
|
41
|
+
checkEqual(parseValue("false"), false);
|
|
42
|
+
checkEqual(parseValue(["foo", "bar", 42]), ["foo", "bar", 42]);
|
|
22
43
|
assert.throws(() => parseValue({ foo: "bar" }), TypeError);
|
|
23
44
|
assert.throws(() => parseValue([42, "foo", { foo: "bar" }]), TypeError);
|
|
24
45
|
assert.throws(() => parseValue([42, "foo", new Error()]), TypeError);
|
|
25
46
|
assert.throws(() => parseValue(["foo", "bar", new String(42)]), TypeError);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
checkEqual(parseValue(true), true);
|
|
48
|
+
checkEqual(parseValue(false), false);
|
|
49
|
+
checkEqual(parseValue(null), null);
|
|
50
|
+
checkEqual(parseValue(undefined), undefined);
|
|
51
|
+
checkEqual(parseValue([null, undefined, null]), [null, undefined, null]);
|
|
52
|
+
checkEqual(parseValue(""), "");
|
|
53
|
+
checkEqual(parseValue(" \n"), " ");
|
|
54
|
+
checkEqual(parseValue("42"), "42");
|
|
55
|
+
checkEqual(parseValue("0"), "0");
|
|
56
|
+
checkEqual(parseValue("-1"), "-1");
|
|
57
|
+
checkEqual(parseValue("True"), "True");
|
|
58
|
+
checkEqual(parseValue("False"), "False");
|
|
59
|
+
checkEqual(parseValue(" TRUE "), " TRUE ");
|
|
60
|
+
checkEqual(parseValue(["true", "false", 0, "0", null, undefined]), [
|
|
61
|
+
true,
|
|
62
|
+
false,
|
|
63
|
+
0,
|
|
64
|
+
"0",
|
|
31
65
|
null,
|
|
32
66
|
undefined,
|
|
33
|
-
null,
|
|
34
67
|
]);
|
|
35
|
-
assert.deepStrictEqual(parseValue(""), "");
|
|
36
|
-
assert.deepStrictEqual(parseValue(" \n"), " ");
|
|
37
|
-
assert.deepStrictEqual(parseValue("42"), "42");
|
|
38
|
-
assert.deepStrictEqual(parseValue("0"), "0");
|
|
39
|
-
assert.deepStrictEqual(parseValue("-1"), "-1");
|
|
40
|
-
assert.deepStrictEqual(parseValue("True"), "True");
|
|
41
|
-
assert.deepStrictEqual(parseValue("False"), "False");
|
|
42
|
-
assert.deepStrictEqual(parseValue(" TRUE "), " TRUE ");
|
|
43
|
-
assert.deepStrictEqual(
|
|
44
|
-
parseValue(["true", "false", 0, "0", null, undefined]),
|
|
45
|
-
[true, false, 0, "0", null, undefined],
|
|
46
|
-
);
|
|
47
68
|
assert.throws(() => parseValue([["nested"]]), TypeError);
|
|
48
69
|
assert.throws(() => parseValue(Symbol("test")), TypeError);
|
|
49
70
|
assert.throws(() => parseValue(BigInt(42)), TypeError);
|
|
50
71
|
// biome-ignore-start lint/suspicious/noEmptyBlockStatements: test
|
|
51
72
|
assert.throws(() => parseValue(() => {}), TypeError);
|
|
52
73
|
// biome-ignore-end lint/suspicious/noEmptyBlockStatements: test
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
parseValue(Number.POSITIVE_INFINITY),
|
|
56
|
-
Number.POSITIVE_INFINITY,
|
|
57
|
-
);
|
|
74
|
+
checkEqual(parseValue(Number.NaN), Number.NaN);
|
|
75
|
+
checkEqual(parseValue(Number.POSITIVE_INFINITY), Number.POSITIVE_INFINITY);
|
|
58
76
|
const obj = { toString: () => "foo" };
|
|
59
77
|
assert.throws(() => parseValue(obj), TypeError);
|
|
60
|
-
|
|
78
|
+
checkEqual(parseValue("hello\r\n"), "hello");
|
|
61
79
|
});
|
|
62
80
|
|
|
63
81
|
describe("parseQueryString tests", () => {
|
|
@@ -70,22 +88,22 @@ describe("parseQueryString tests", () => {
|
|
|
70
88
|
};
|
|
71
89
|
const options = {};
|
|
72
90
|
const result = parseQueryString(q, body, options);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
91
|
+
checkEqual(result.foo, undefined);
|
|
92
|
+
checkEqual(result.excludeType, ["2"]);
|
|
93
|
+
checkEqual(result.technique, ["manifest-analysis"]);
|
|
76
94
|
});
|
|
77
95
|
|
|
78
96
|
it("splits type into projectType and removes type", () => {
|
|
79
97
|
const options = { type: "a,b,c" };
|
|
80
98
|
const result = parseQueryString({}, {}, options);
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
checkEqual(result.projectType, ["a", "b", "c"]);
|
|
100
|
+
checkEqual(result.type, undefined);
|
|
83
101
|
});
|
|
84
102
|
|
|
85
103
|
it("sets installDeps to false for pre-build lifecycle", () => {
|
|
86
104
|
const options = { lifecycle: "pre-build" };
|
|
87
105
|
const result = parseQueryString({}, {}, options);
|
|
88
|
-
|
|
106
|
+
checkEqual(result.installDeps, false);
|
|
89
107
|
});
|
|
90
108
|
});
|
|
91
109
|
|
|
@@ -102,23 +120,23 @@ describe("isAllowedHost()", () => {
|
|
|
102
120
|
|
|
103
121
|
it("returns true if CDXGEN_SERVER_ALLOWED_HOSTS is not set", () => {
|
|
104
122
|
delete process.env.CDXGEN_SERVER_ALLOWED_HOSTS;
|
|
105
|
-
|
|
123
|
+
checkEqual(isAllowedHost("anything"), true);
|
|
106
124
|
});
|
|
107
125
|
|
|
108
126
|
it("returns true for a hostname that is in the list", () => {
|
|
109
127
|
process.env.CDXGEN_SERVER_ALLOWED_HOSTS = "foo.com,bar.com";
|
|
110
|
-
|
|
111
|
-
|
|
128
|
+
checkEqual(isAllowedHost("foo.com"), true);
|
|
129
|
+
checkEqual(isAllowedHost("bar.com"), true);
|
|
112
130
|
});
|
|
113
131
|
|
|
114
132
|
it("returns false for a hostname not in the list", () => {
|
|
115
133
|
process.env.CDXGEN_SERVER_ALLOWED_HOSTS = "foo.com,bar.com";
|
|
116
|
-
|
|
134
|
+
checkEqual(isAllowedHost("baz.com"), false);
|
|
117
135
|
});
|
|
118
136
|
|
|
119
137
|
it("treats an empty-string env var as unset (returns true)", () => {
|
|
120
138
|
process.env.CDXGEN_SERVER_ALLOWED_HOSTS = "";
|
|
121
|
-
|
|
139
|
+
checkEqual(isAllowedHost("whatever"), true);
|
|
122
140
|
});
|
|
123
141
|
});
|
|
124
142
|
|
|
@@ -203,15 +221,15 @@ describe("isAllowedPath()", () => {
|
|
|
203
221
|
describe("isAllowedWinPath windows tests()", () => {
|
|
204
222
|
it("returns false for windows device name paths", () => {
|
|
205
223
|
if (isWin) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
224
|
+
checkEqual(isAllowedWinPath("CON:../foo"), false);
|
|
225
|
+
checkEqual(isAllowedWinPath("X:\\foo\\..\\bar"), true);
|
|
226
|
+
checkEqual(isAllowedWinPath("C:\\Users"), true);
|
|
227
|
+
checkEqual(isAllowedWinPath("C:\\🚀"), true);
|
|
228
|
+
checkEqual(isAllowedWinPath("C:"), true);
|
|
229
|
+
checkEqual(isAllowedWinPath("c:"), true);
|
|
230
|
+
checkEqual(isAllowedWinPath("CON:"), false);
|
|
231
|
+
checkEqual(isAllowedWinPath("COM¹:"), false);
|
|
232
|
+
checkEqual(isAllowedWinPath("COM¹:../foo"), false);
|
|
215
233
|
for (const d of [
|
|
216
234
|
"PRN:.\\..\\bar",
|
|
217
235
|
"LpT5:/another/path",
|
|
@@ -244,7 +262,7 @@ describe("isAllowedWinPath windows tests()", () => {
|
|
|
244
262
|
"🚀:\\",
|
|
245
263
|
"⚡:\\",
|
|
246
264
|
]) {
|
|
247
|
-
|
|
265
|
+
checkEqual(isAllowedWinPath(d), false);
|
|
248
266
|
}
|
|
249
267
|
}
|
|
250
268
|
});
|
|
@@ -264,7 +282,7 @@ describe("getQueryParams", () => {
|
|
|
264
282
|
);
|
|
265
283
|
const result = getQueryParams(req);
|
|
266
284
|
|
|
267
|
-
|
|
285
|
+
checkEqual(result, {
|
|
268
286
|
url: "https://example.com",
|
|
269
287
|
multiProject: "true",
|
|
270
288
|
type: "js",
|
|
@@ -277,7 +295,7 @@ describe("getQueryParams", () => {
|
|
|
277
295
|
);
|
|
278
296
|
const result = getQueryParams(req);
|
|
279
297
|
|
|
280
|
-
|
|
298
|
+
checkEqual(result, {
|
|
281
299
|
q: "hello world",
|
|
282
300
|
filter: "category=tech",
|
|
283
301
|
});
|
|
@@ -288,7 +306,7 @@ describe("getQueryParams", () => {
|
|
|
288
306
|
const result = getQueryParams(req);
|
|
289
307
|
|
|
290
308
|
// URLSearchParams.entries() returns the first value when there are duplicates
|
|
291
|
-
|
|
309
|
+
checkEqual(result, {
|
|
292
310
|
tags: ["javascript", "react", "node"],
|
|
293
311
|
});
|
|
294
312
|
});
|
|
@@ -297,21 +315,21 @@ describe("getQueryParams", () => {
|
|
|
297
315
|
const req = createMockRequest("/sbom");
|
|
298
316
|
const result = getQueryParams(req);
|
|
299
317
|
|
|
300
|
-
|
|
318
|
+
checkEqual(result, {});
|
|
301
319
|
});
|
|
302
320
|
|
|
303
321
|
it("should handle query string with only question mark", () => {
|
|
304
322
|
const req = createMockRequest("/sbom?");
|
|
305
323
|
const result = getQueryParams(req);
|
|
306
324
|
|
|
307
|
-
|
|
325
|
+
checkEqual(result, {});
|
|
308
326
|
});
|
|
309
327
|
|
|
310
328
|
it("should handle parameters without values", () => {
|
|
311
329
|
const req = createMockRequest("/api?flag1&flag2¶m=value");
|
|
312
330
|
const result = getQueryParams(req);
|
|
313
331
|
|
|
314
|
-
|
|
332
|
+
checkEqual(result, {
|
|
315
333
|
flag1: "",
|
|
316
334
|
flag2: "",
|
|
317
335
|
param: "value",
|
|
@@ -325,7 +343,7 @@ describe("getQueryParams", () => {
|
|
|
325
343
|
);
|
|
326
344
|
const result = getQueryParams(req);
|
|
327
345
|
|
|
328
|
-
|
|
346
|
+
checkEqual(result, {
|
|
329
347
|
param1: "value1",
|
|
330
348
|
});
|
|
331
349
|
});
|
|
@@ -338,7 +356,7 @@ describe("getQueryParams", () => {
|
|
|
338
356
|
);
|
|
339
357
|
const result = getQueryParams(req);
|
|
340
358
|
|
|
341
|
-
|
|
359
|
+
checkEqual(result, {
|
|
342
360
|
token: "abc123",
|
|
343
361
|
});
|
|
344
362
|
});
|
|
@@ -349,7 +367,7 @@ describe("getQueryParams", () => {
|
|
|
349
367
|
);
|
|
350
368
|
const result = getQueryParams(req);
|
|
351
369
|
|
|
352
|
-
|
|
370
|
+
checkEqual(result, {
|
|
353
371
|
name: "john",
|
|
354
372
|
age: "25",
|
|
355
373
|
active: "true",
|
|
@@ -362,7 +380,7 @@ describe("getQueryParams", () => {
|
|
|
362
380
|
);
|
|
363
381
|
const result = getQueryParams(req);
|
|
364
382
|
|
|
365
|
-
|
|
383
|
+
checkEqual(result, {
|
|
366
384
|
q: "hello world!",
|
|
367
385
|
category: "web development",
|
|
368
386
|
});
|
|
@@ -372,14 +390,14 @@ describe("getQueryParams", () => {
|
|
|
372
390
|
const req = createMockRequest(undefined);
|
|
373
391
|
const result = getQueryParams(req);
|
|
374
392
|
|
|
375
|
-
|
|
393
|
+
checkEqual(result, {});
|
|
376
394
|
});
|
|
377
395
|
|
|
378
396
|
it("should handle numeric values as strings", () => {
|
|
379
397
|
const req = createMockRequest("/calculate?x=10&y=20&operation=add");
|
|
380
398
|
const result = getQueryParams(req);
|
|
381
399
|
|
|
382
|
-
|
|
400
|
+
checkEqual(result, {
|
|
383
401
|
x: "10",
|
|
384
402
|
y: "20",
|
|
385
403
|
operation: "add",
|
|
@@ -390,7 +408,7 @@ describe("getQueryParams", () => {
|
|
|
390
408
|
const req = createMockRequest("/config?debug=true&verbose=false&enabled=1");
|
|
391
409
|
const result = getQueryParams(req);
|
|
392
410
|
|
|
393
|
-
|
|
411
|
+
checkEqual(result, {
|
|
394
412
|
debug: "true",
|
|
395
413
|
verbose: "false",
|
|
396
414
|
enabled: "1",
|
|
@@ -402,7 +420,7 @@ describe("getQueryParams", () => {
|
|
|
402
420
|
const req = createMockRequest("not-a-valid-url");
|
|
403
421
|
const result = getQueryParams(req);
|
|
404
422
|
|
|
405
|
-
|
|
423
|
+
checkEqual(result, {});
|
|
406
424
|
});
|
|
407
425
|
|
|
408
426
|
it("should handle empty host gracefully", () => {
|
|
@@ -413,7 +431,7 @@ describe("getQueryParams", () => {
|
|
|
413
431
|
};
|
|
414
432
|
const result = getQueryParams(req);
|
|
415
433
|
|
|
416
|
-
|
|
434
|
+
checkEqual(result, {
|
|
417
435
|
param: "value",
|
|
418
436
|
});
|
|
419
437
|
});
|
|
@@ -426,7 +444,7 @@ describe("getQueryParams", () => {
|
|
|
426
444
|
};
|
|
427
445
|
const result = getQueryParams(req);
|
|
428
446
|
|
|
429
|
-
|
|
447
|
+
checkEqual(result, {
|
|
430
448
|
param: "value",
|
|
431
449
|
});
|
|
432
450
|
});
|
|
@@ -450,84 +468,60 @@ describe("validateGitSource() tests", () => {
|
|
|
450
468
|
});
|
|
451
469
|
|
|
452
470
|
it("should reject ext:: and fd:: outright", () => {
|
|
453
|
-
|
|
471
|
+
checkEqual(
|
|
454
472
|
validateAndRejectGitSource("ext::sh -c id").error,
|
|
455
473
|
"Invalid Protocol",
|
|
456
474
|
);
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
"Invalid Protocol",
|
|
460
|
-
);
|
|
461
|
-
assert.deepStrictEqual(
|
|
475
|
+
checkEqual(validateAndRejectGitSource("fd::123").error, "Invalid Protocol");
|
|
476
|
+
checkEqual(
|
|
462
477
|
validateAndRejectGitSource("EXT::sh -c id").error,
|
|
463
478
|
"Invalid Protocol",
|
|
464
479
|
);
|
|
465
480
|
});
|
|
466
481
|
|
|
467
482
|
it("should allow standard local paths to bypass validation", () => {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
validateAndRejectGitSource("C:\\Users\\local"),
|
|
471
|
-
null,
|
|
472
|
-
);
|
|
483
|
+
checkEqual(validateAndRejectGitSource("/tmp/local-path"), null);
|
|
484
|
+
checkEqual(validateAndRejectGitSource("C:\\Users\\local"), null);
|
|
473
485
|
});
|
|
474
486
|
|
|
475
487
|
it("should handle ssh git@ format gracefully", () => {
|
|
476
|
-
|
|
477
|
-
validateAndRejectGitSource("git@github.com:foo/bar.git"),
|
|
478
|
-
null,
|
|
479
|
-
);
|
|
488
|
+
checkEqual(validateAndRejectGitSource("git@github.com:foo/bar.git"), null);
|
|
480
489
|
});
|
|
481
490
|
|
|
482
491
|
it("should reject malformed git URLs", () => {
|
|
483
492
|
// invalid URL format (can't parse via node's new URL object)
|
|
484
|
-
|
|
493
|
+
checkEqual(
|
|
485
494
|
validateAndRejectGitSource("http://[:::1]/bad-ipv6").error,
|
|
486
495
|
"Invalid URL Format",
|
|
487
496
|
);
|
|
488
497
|
});
|
|
489
498
|
|
|
490
499
|
it("should enforce GIT_ALLOW_PROTOCOL default schemes", () => {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
details: "The protocol 'http:' is not permitted by GIT_ALLOW_PROTOCOL.",
|
|
501
|
-
},
|
|
502
|
-
);
|
|
503
|
-
assert.deepStrictEqual(
|
|
504
|
-
validateAndRejectGitSource("git://github.com/repo"),
|
|
505
|
-
null,
|
|
506
|
-
);
|
|
507
|
-
assert.deepStrictEqual(
|
|
508
|
-
validateAndRejectGitSource("ssh://github.com/repo"),
|
|
509
|
-
null,
|
|
510
|
-
);
|
|
511
|
-
assert.deepStrictEqual(
|
|
512
|
-
validateAndRejectGitSource("git+ssh://github.com/repo"),
|
|
513
|
-
null,
|
|
514
|
-
);
|
|
500
|
+
checkEqual(validateAndRejectGitSource("https://github.com/repo"), null);
|
|
501
|
+
checkEqual(validateAndRejectGitSource("http://github.com/repo"), {
|
|
502
|
+
status: 400,
|
|
503
|
+
error: "Protocol Not Allowed",
|
|
504
|
+
details: "The protocol 'http:' is not permitted by GIT_ALLOW_PROTOCOL.",
|
|
505
|
+
});
|
|
506
|
+
checkEqual(validateAndRejectGitSource("git://github.com/repo"), null);
|
|
507
|
+
checkEqual(validateAndRejectGitSource("ssh://github.com/repo"), null);
|
|
508
|
+
checkEqual(validateAndRejectGitSource("git+ssh://github.com/repo"), null);
|
|
515
509
|
|
|
516
510
|
// ftp is not allowed by default
|
|
517
511
|
const res = validateAndRejectGitSource("ftp://github.com/repo");
|
|
518
|
-
|
|
519
|
-
|
|
512
|
+
checkEqual(res.error, "Protocol Not Allowed");
|
|
513
|
+
checkEqual(
|
|
520
514
|
res.details,
|
|
521
515
|
"The protocol 'ftp:' is not permitted by GIT_ALLOW_PROTOCOL.",
|
|
522
516
|
);
|
|
523
517
|
});
|
|
524
518
|
|
|
525
519
|
it("should reject protocol smuggling techniques", () => {
|
|
526
|
-
|
|
520
|
+
checkEqual(
|
|
527
521
|
validateAndRejectGitSource("git+ext://github.com/repo").error,
|
|
528
522
|
"Protocol Not Allowed",
|
|
529
523
|
);
|
|
530
|
-
|
|
524
|
+
checkEqual(
|
|
531
525
|
validateAndRejectGitSource("http+ext://github.com/repo").error,
|
|
532
526
|
"Protocol Not Allowed",
|
|
533
527
|
);
|
|
@@ -535,30 +529,24 @@ describe("validateGitSource() tests", () => {
|
|
|
535
529
|
|
|
536
530
|
it("should respect custom CDXGEN_SERVER_GIT_ALLOW_PROTOCOL configs", () => {
|
|
537
531
|
process.env.CDXGEN_SERVER_GIT_ALLOW_PROTOCOL = "https:git";
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
null,
|
|
541
|
-
);
|
|
542
|
-
assert.deepStrictEqual(
|
|
543
|
-
validateAndRejectGitSource("git://github.com/repo"),
|
|
544
|
-
null,
|
|
545
|
-
);
|
|
532
|
+
checkEqual(validateAndRejectGitSource("https://github.com/repo"), null);
|
|
533
|
+
checkEqual(validateAndRejectGitSource("git://github.com/repo"), null);
|
|
546
534
|
|
|
547
535
|
// http is no longer allowed
|
|
548
536
|
const res = validateAndRejectGitSource("http://github.com/repo");
|
|
549
|
-
|
|
550
|
-
|
|
537
|
+
checkEqual(res.error, "Protocol Not Allowed");
|
|
538
|
+
checkEqual(
|
|
551
539
|
res.details,
|
|
552
540
|
"The protocol 'http:' is not permitted by GIT_ALLOW_PROTOCOL.",
|
|
553
541
|
);
|
|
554
542
|
});
|
|
555
543
|
|
|
556
544
|
it("should reject remote helper syntax (::) inside valid schemes", () => {
|
|
557
|
-
|
|
545
|
+
checkEqual(
|
|
558
546
|
validateAndRejectGitSource("https://github.com/ext::sh -c id").error,
|
|
559
547
|
"Invalid URL Syntax",
|
|
560
548
|
);
|
|
561
|
-
|
|
549
|
+
checkEqual(
|
|
562
550
|
validateAndRejectGitSource("git://foo::bar/repo").error,
|
|
563
551
|
"Invalid URL Format",
|
|
564
552
|
);
|
|
@@ -566,44 +554,35 @@ describe("validateGitSource() tests", () => {
|
|
|
566
554
|
|
|
567
555
|
it("should validate allowed hosts", () => {
|
|
568
556
|
process.env.CDXGEN_SERVER_ALLOWED_HOSTS = "github.com,gitlab.com";
|
|
569
|
-
|
|
570
|
-
validateAndRejectGitSource("https://github.com/repo"),
|
|
571
|
-
null,
|
|
572
|
-
);
|
|
557
|
+
checkEqual(validateAndRejectGitSource("https://github.com/repo"), null);
|
|
573
558
|
|
|
574
559
|
const res = validateAndRejectGitSource("https://evil.com/repo");
|
|
575
|
-
|
|
576
|
-
|
|
560
|
+
checkEqual(res.error, "Host Not Allowed");
|
|
561
|
+
checkEqual(res.status, 403);
|
|
577
562
|
});
|
|
578
563
|
});
|
|
579
564
|
it("should correctly normalize and validate various git@ (SCP-like) formats", () => {
|
|
580
|
-
|
|
565
|
+
checkEqual(
|
|
581
566
|
validateAndRejectGitSource("git@gitlab.com:group/project.git"),
|
|
582
567
|
null,
|
|
583
568
|
);
|
|
584
|
-
|
|
569
|
+
checkEqual(
|
|
585
570
|
validateAndRejectGitSource("git@bitbucket.org:workspace/repo:name.git"),
|
|
586
571
|
null,
|
|
587
572
|
);
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
null,
|
|
591
|
-
);
|
|
592
|
-
assert.deepStrictEqual(
|
|
573
|
+
checkEqual(validateAndRejectGitSource("git@github.com/user/repo.git"), null);
|
|
574
|
+
checkEqual(
|
|
593
575
|
validateAndRejectGitSource("ssh://git@github.com/user/repo.git"),
|
|
594
576
|
null,
|
|
595
577
|
);
|
|
596
578
|
process.env.CDXGEN_SERVER_ALLOWED_HOSTS = "github.com,bitbucket.org";
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
null,
|
|
600
|
-
);
|
|
601
|
-
assert.deepStrictEqual(
|
|
579
|
+
checkEqual(validateAndRejectGitSource("git@github.com:user/repo.git"), null);
|
|
580
|
+
checkEqual(
|
|
602
581
|
validateAndRejectGitSource("git@bitbucket.org:workspace/repo.git"),
|
|
603
582
|
null,
|
|
604
583
|
);
|
|
605
584
|
const deniedRes = validateAndRejectGitSource("git@evil.com:foo/bar.git");
|
|
606
|
-
|
|
607
|
-
|
|
585
|
+
checkEqual(deniedRes.status, 403);
|
|
586
|
+
checkEqual(deniedRes.error, "Host Not Allowed");
|
|
608
587
|
delete process.env.CDXGEN_SERVER_ALLOWED_HOSTS;
|
|
609
588
|
});
|
|
@@ -289,7 +289,7 @@ export function textualMetadata(bomJson) {
|
|
|
289
289
|
(c) => c.type === "cryptographic-asset",
|
|
290
290
|
).length;
|
|
291
291
|
const vsixCount = bomJson?.components?.filter((c) =>
|
|
292
|
-
c?.purl?.startsWith("pkg:
|
|
292
|
+
c?.purl?.startsWith("pkg:vscode-extension"),
|
|
293
293
|
).length;
|
|
294
294
|
const swidCount = bomJson?.components?.filter((c) =>
|
|
295
295
|
c?.purl?.startsWith("pkg:swid"),
|