@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.
Files changed (181) hide show
  1. package/README.md +47 -39
  2. package/bin/cdxgen.js +175 -96
  3. package/bin/evinse.js +4 -4
  4. package/bin/repl.js +1 -1
  5. package/bin/sign.js +102 -0
  6. package/bin/validate.js +233 -0
  7. package/bin/verify.js +69 -28
  8. package/data/queries.json +1 -1
  9. package/data/rules/ci-permissions.yaml +186 -0
  10. package/data/rules/dependency-sources.yaml +123 -0
  11. package/data/rules/package-integrity.yaml +135 -0
  12. package/data/rules/vscode-extensions.yaml +228 -0
  13. package/lib/cli/index.js +327 -372
  14. package/lib/evinser/db.js +137 -0
  15. package/lib/{helpers → evinser}/db.poku.js +2 -6
  16. package/lib/evinser/evinser.js +2 -14
  17. package/lib/helpers/bomSigner.js +312 -0
  18. package/lib/helpers/bomSigner.poku.js +156 -0
  19. package/lib/helpers/ciParsers/azurePipelines.js +295 -0
  20. package/lib/helpers/ciParsers/azurePipelines.poku.js +253 -0
  21. package/lib/helpers/ciParsers/circleCi.js +286 -0
  22. package/lib/helpers/ciParsers/circleCi.poku.js +230 -0
  23. package/lib/helpers/ciParsers/common.js +24 -0
  24. package/lib/helpers/ciParsers/githubActions.js +636 -0
  25. package/lib/helpers/ciParsers/githubActions.poku.js +802 -0
  26. package/lib/helpers/ciParsers/gitlabCi.js +213 -0
  27. package/lib/helpers/ciParsers/gitlabCi.poku.js +247 -0
  28. package/lib/helpers/ciParsers/jenkins.js +181 -0
  29. package/lib/helpers/ciParsers/jenkins.poku.js +197 -0
  30. package/lib/helpers/depsUtils.js +203 -0
  31. package/lib/helpers/depsUtils.poku.js +150 -0
  32. package/lib/helpers/display.js +423 -4
  33. package/lib/helpers/envcontext.js +18 -3
  34. package/lib/helpers/formulationParsers.js +351 -0
  35. package/lib/helpers/logger.js +14 -0
  36. package/lib/helpers/protobom.js +9 -9
  37. package/lib/helpers/pythonutils.js +9 -0
  38. package/lib/helpers/utils.js +681 -406
  39. package/lib/helpers/utils.poku.js +55 -255
  40. package/lib/helpers/versutils.js +202 -0
  41. package/lib/helpers/versutils.poku.js +315 -0
  42. package/lib/helpers/vsixutils.js +1061 -0
  43. package/lib/helpers/vsixutils.poku.js +2247 -0
  44. package/lib/managers/binary.js +19 -19
  45. package/lib/managers/docker.js +108 -1
  46. package/lib/managers/oci.js +10 -0
  47. package/lib/managers/piptree.js +3 -9
  48. package/lib/parsers/npmrc.js +17 -13
  49. package/lib/parsers/npmrc.poku.js +41 -5
  50. package/lib/server/openapi.yaml +1 -1
  51. package/lib/server/server.js +40 -11
  52. package/lib/server/server.poku.js +123 -144
  53. package/lib/stages/postgen/annotator.js +1 -1
  54. package/lib/stages/postgen/auditBom.js +197 -0
  55. package/lib/stages/postgen/auditBom.poku.js +378 -0
  56. package/lib/stages/postgen/postgen.js +54 -1
  57. package/lib/stages/postgen/postgen.poku.js +90 -1
  58. package/lib/stages/postgen/ruleEngine.js +369 -0
  59. package/lib/stages/pregen/envAudit.js +299 -0
  60. package/lib/stages/pregen/envAudit.poku.js +572 -0
  61. package/lib/stages/pregen/pregen.js +12 -8
  62. package/lib/{helpers/validator.js → validator/bomValidator.js} +107 -47
  63. package/lib/validator/complianceEngine.js +241 -0
  64. package/lib/validator/complianceEngine.poku.js +168 -0
  65. package/lib/validator/complianceRules.js +1610 -0
  66. package/lib/validator/complianceRules.poku.js +328 -0
  67. package/lib/validator/index.js +222 -0
  68. package/lib/validator/index.poku.js +144 -0
  69. package/lib/validator/reporters/annotations.js +121 -0
  70. package/lib/validator/reporters/console.js +149 -0
  71. package/lib/validator/reporters/index.js +41 -0
  72. package/lib/validator/reporters/json.js +37 -0
  73. package/lib/validator/reporters/sarif.js +184 -0
  74. package/lib/validator/reporters.poku.js +150 -0
  75. package/package.json +8 -8
  76. package/types/bin/sign.d.ts +3 -0
  77. package/types/bin/sign.d.ts.map +1 -0
  78. package/types/bin/validate.d.ts +3 -0
  79. package/types/bin/validate.d.ts.map +1 -0
  80. package/types/helpers/utils.d.ts +0 -1
  81. package/types/lib/cli/index.d.ts +49 -52
  82. package/types/lib/cli/index.d.ts.map +1 -1
  83. package/types/lib/evinser/db.d.ts +34 -0
  84. package/types/lib/evinser/db.d.ts.map +1 -0
  85. package/types/lib/evinser/evinser.d.ts +63 -16
  86. package/types/lib/evinser/evinser.d.ts.map +1 -1
  87. package/types/lib/helpers/bomSigner.d.ts +27 -0
  88. package/types/lib/helpers/bomSigner.d.ts.map +1 -0
  89. package/types/lib/helpers/ciParsers/azurePipelines.d.ts +17 -0
  90. package/types/lib/helpers/ciParsers/azurePipelines.d.ts.map +1 -0
  91. package/types/lib/helpers/ciParsers/circleCi.d.ts +17 -0
  92. package/types/lib/helpers/ciParsers/circleCi.d.ts.map +1 -0
  93. package/types/lib/helpers/ciParsers/common.d.ts +11 -0
  94. package/types/lib/helpers/ciParsers/common.d.ts.map +1 -0
  95. package/types/lib/helpers/ciParsers/githubActions.d.ts +34 -0
  96. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -0
  97. package/types/lib/helpers/ciParsers/gitlabCi.d.ts +17 -0
  98. package/types/lib/helpers/ciParsers/gitlabCi.d.ts.map +1 -0
  99. package/types/lib/helpers/ciParsers/jenkins.d.ts +17 -0
  100. package/types/lib/helpers/ciParsers/jenkins.d.ts.map +1 -0
  101. package/types/lib/helpers/depsUtils.d.ts +21 -0
  102. package/types/lib/helpers/depsUtils.d.ts.map +1 -0
  103. package/types/lib/helpers/display.d.ts +111 -11
  104. package/types/lib/helpers/display.d.ts.map +1 -1
  105. package/types/lib/helpers/envcontext.d.ts +19 -7
  106. package/types/lib/helpers/envcontext.d.ts.map +1 -1
  107. package/types/lib/helpers/formulationParsers.d.ts +50 -0
  108. package/types/lib/helpers/formulationParsers.d.ts.map +1 -0
  109. package/types/lib/helpers/logger.d.ts +15 -1
  110. package/types/lib/helpers/logger.d.ts.map +1 -1
  111. package/types/lib/helpers/protobom.d.ts +2 -2
  112. package/types/lib/helpers/pythonutils.d.ts +10 -1
  113. package/types/lib/helpers/pythonutils.d.ts.map +1 -1
  114. package/types/lib/helpers/utils.d.ts +532 -128
  115. package/types/lib/helpers/utils.d.ts.map +1 -1
  116. package/types/lib/helpers/versutils.d.ts +8 -0
  117. package/types/lib/helpers/versutils.d.ts.map +1 -0
  118. package/types/lib/helpers/vsixutils.d.ts +130 -0
  119. package/types/lib/helpers/vsixutils.d.ts.map +1 -0
  120. package/types/lib/managers/docker.d.ts +12 -31
  121. package/types/lib/managers/docker.d.ts.map +1 -1
  122. package/types/lib/managers/oci.d.ts +11 -1
  123. package/types/lib/managers/oci.d.ts.map +1 -1
  124. package/types/lib/managers/piptree.d.ts.map +1 -1
  125. package/types/lib/parsers/npmrc.d.ts +4 -1
  126. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  127. package/types/lib/server/server.d.ts +21 -2
  128. package/types/lib/server/server.d.ts.map +1 -1
  129. package/types/lib/stages/postgen/auditBom.d.ts +20 -0
  130. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
  131. package/types/lib/stages/postgen/postgen.d.ts +8 -1
  132. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  133. package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
  134. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
  135. package/types/lib/stages/pregen/envAudit.d.ts +8 -0
  136. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
  137. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  138. package/types/lib/{helpers/validator.d.ts → validator/bomValidator.d.ts} +1 -1
  139. package/types/lib/validator/bomValidator.d.ts.map +1 -0
  140. package/types/lib/validator/complianceEngine.d.ts +66 -0
  141. package/types/lib/validator/complianceEngine.d.ts.map +1 -0
  142. package/types/lib/validator/complianceRules.d.ts +70 -0
  143. package/types/lib/validator/complianceRules.d.ts.map +1 -0
  144. package/types/lib/validator/index.d.ts +70 -0
  145. package/types/lib/validator/index.d.ts.map +1 -0
  146. package/types/lib/validator/reporters/annotations.d.ts +31 -0
  147. package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
  148. package/types/lib/validator/reporters/console.d.ts +30 -0
  149. package/types/lib/validator/reporters/console.d.ts.map +1 -0
  150. package/types/lib/validator/reporters/index.d.ts +21 -0
  151. package/types/lib/validator/reporters/index.d.ts.map +1 -0
  152. package/types/lib/validator/reporters/json.d.ts +11 -0
  153. package/types/lib/validator/reporters/json.d.ts.map +1 -0
  154. package/types/lib/validator/reporters/sarif.d.ts +16 -0
  155. package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
  156. package/lib/helpers/db.js +0 -162
  157. package/lib/stages/pregen/env-audit.js +0 -34
  158. package/lib/stages/pregen/env-audit.poku.js +0 -290
  159. package/types/helpers/db.d.ts +0 -35
  160. package/types/helpers/db.d.ts.map +0 -1
  161. package/types/lib/helpers/db.d.ts +0 -35
  162. package/types/lib/helpers/db.d.ts.map +0 -1
  163. package/types/lib/helpers/validator.d.ts.map +0 -1
  164. package/types/lib/stages/pregen/env-audit.d.ts +0 -2
  165. package/types/lib/stages/pregen/env-audit.d.ts.map +0 -1
  166. package/types/managers/binary.d.ts +0 -37
  167. package/types/managers/binary.d.ts.map +0 -1
  168. package/types/managers/docker.d.ts +0 -56
  169. package/types/managers/docker.d.ts.map +0 -1
  170. package/types/managers/oci.d.ts +0 -2
  171. package/types/managers/oci.d.ts.map +0 -1
  172. package/types/managers/piptree.d.ts +0 -2
  173. package/types/managers/piptree.d.ts.map +0 -1
  174. package/types/server/server.d.ts +0 -34
  175. package/types/server/server.d.ts.map +0 -1
  176. package/types/stages/postgen/annotator.d.ts +0 -27
  177. package/types/stages/postgen/annotator.d.ts.map +0 -1
  178. package/types/stages/postgen/postgen.d.ts +0 -51
  179. package/types/stages/postgen/postgen.d.ts.map +0 -1
  180. package/types/stages/pregen/pregen.d.ts +0 -59
  181. package/types/stages/pregen/pregen.d.ts.map +0 -1
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Run structural + compliance validation against a parsed BOM.
3
+ *
4
+ * @param {object} bomJson Parsed CycloneDX JSON BOM.
5
+ * @param {object} [options]
6
+ * @param {boolean} [options.schema] Run JSON-Schema validation (default true).
7
+ * @param {boolean} [options.deep] Run purl/ref/metadata deep checks (default true).
8
+ * @param {Array<string>} [options.benchmarks] Aliases to include in the scorecards (default: all).
9
+ * @param {Array<string>} [options.categories] Restrict compliance rules to these categories.
10
+ * @param {string} [options.minSeverity] Minimum severity for returned findings.
11
+ * @param {boolean} [options.includeManual] Include manual-review findings (default true).
12
+ * @param {boolean} [options.includePass] Include passing findings (default false).
13
+ * @param {string} [options.publicKey] If set, verify the BOM signature.
14
+ * @returns {{
15
+ * schemaValid: boolean,
16
+ * deepValid: boolean,
17
+ * signatureVerified: boolean | null,
18
+ * signatureDetails: object | null,
19
+ * findings: Array<object>,
20
+ * allFindings: Array<object>,
21
+ * benchmarks: Array<object>,
22
+ * summary: object
23
+ * }}
24
+ */
25
+ export function validateBomAdvanced(bomJson: object, options?: {
26
+ schema?: boolean | undefined;
27
+ deep?: boolean | undefined;
28
+ benchmarks?: string[] | undefined;
29
+ categories?: string[] | undefined;
30
+ minSeverity?: string | undefined;
31
+ includeManual?: boolean | undefined;
32
+ includePass?: boolean | undefined;
33
+ publicKey?: string | undefined;
34
+ }): {
35
+ schemaValid: boolean;
36
+ deepValid: boolean;
37
+ signatureVerified: boolean | null;
38
+ signatureDetails: object | null;
39
+ findings: Array<object>;
40
+ allFindings: Array<object>;
41
+ benchmarks: Array<object>;
42
+ summary: object;
43
+ };
44
+ /**
45
+ * Decide whether a report should trigger a non-zero CLI exit.
46
+ *
47
+ * @param {object} report
48
+ * @param {object} opts
49
+ * @param {string} [opts.failSeverity] Severity level at or above which failing findings are considered a failure (default "high").
50
+ * @param {boolean} [opts.strict] When true, failing on any `fail` status regardless of severity, and a failing schema/deep validation also counts.
51
+ * @param {boolean} [opts.requireSignature] Require a valid signature when verification was requested.
52
+ * @returns {{ shouldFail: boolean, reason: string | null }}
53
+ */
54
+ export function shouldFail(report: object, opts?: {
55
+ failSeverity?: string | undefined;
56
+ strict?: boolean | undefined;
57
+ requireSignature?: boolean | undefined;
58
+ }): {
59
+ shouldFail: boolean;
60
+ reason: string | null;
61
+ };
62
+ export namespace SEVERITY_ORDER {
63
+ let info: number;
64
+ let low: number;
65
+ let medium: number;
66
+ let high: number;
67
+ let critical: number;
68
+ }
69
+ export { buildBenchmarkReports, evaluateAll } from "./complianceEngine.js";
70
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/validator/index.js"],"names":[],"mappings":"AAqHA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,6CArBW,MAAM,YAEd;IAA0B,MAAM;IACN,IAAI;IACE,UAAU;IACV,UAAU;IACjB,WAAW;IACV,aAAa;IACb,WAAW;IACZ,SAAS;CAClC,GAAU;IACR,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxB,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB,CA2CH;AAED;;;;;;;;;GASG;AACH,mCAPW,MAAM,SAEd;IAAsB,YAAY;IACX,MAAM;IACN,gBAAgB;CACvC,GAAU;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CA0B1D"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Render a set of findings into CycloneDX annotations.
3
+ *
4
+ * @param {Array<object>} findings Finding objects emitted by the validator or auditBom engine.
5
+ * @param {object} bomJson Full CycloneDX BOM (needed for annotator/subject wiring).
6
+ * @returns {Array<object>} CycloneDX annotation objects.
7
+ */
8
+ export function buildAnnotations(findings: Array<object>, bomJson: object): Array<object>;
9
+ /**
10
+ * Produce a new BOM object with findings embedded as annotations. The caller
11
+ * is responsible for writing the result to disk.
12
+ *
13
+ * @param {object} bomJson
14
+ * @param {Array<object>} findings
15
+ * @returns {object}
16
+ */
17
+ export function renderBom(bomJson: object, findings: Array<object>): object;
18
+ /**
19
+ * Convenience wrapper matching the signature of the other reporters. The
20
+ * second argument expects `{ bomJson }` because annotations are BOM-shaped,
21
+ * not report-shaped.
22
+ *
23
+ * @param {object} report Output of validateBomAdvanced().
24
+ * @param {object} options
25
+ * @param {object} options.bomJson The BOM to annotate.
26
+ * @returns {string} JSON string of the annotated BOM.
27
+ */
28
+ export function render(report: object, options?: {
29
+ bomJson: object;
30
+ }): string;
31
+ //# sourceMappingURL=annotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../../../lib/validator/reporters/annotations.js"],"names":[],"mappings":"AAYA;;;;;;GAMG;AACH,2CAJW,KAAK,CAAC,MAAM,CAAC,WACb,MAAM,GACJ,KAAK,CAAC,MAAM,CAAC,CAqEzB;AAED;;;;;;;GAOG;AACH,mCAJW,MAAM,YACN,KAAK,CAAC,MAAM,CAAC,GACX,MAAM,CAUlB;AAED;;;;;;;;;GASG;AACH,+BALW,MAAM,YAEd;IAAwB,OAAO,EAAvB,MAAM;CACd,GAAU,MAAM,CAMlB"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Produce a human-readable summary of findings.
3
+ *
4
+ * @param {Array<object>} findings
5
+ * @param {object} [options]
6
+ * @returns {string}
7
+ */
8
+ export function formatFindings(findings: Array<object>, options?: object): string;
9
+ /**
10
+ * Produce a scorecard table for benchmark reports.
11
+ *
12
+ * @param {Array<object>} reports
13
+ * @returns {string}
14
+ */
15
+ export function formatBenchmarks(reports: Array<object>): string;
16
+ /**
17
+ * Produce a compact one-line summary for CI logs.
18
+ *
19
+ * @param {object} summary
20
+ * @returns {string}
21
+ */
22
+ export function formatSummary(summary: object): string;
23
+ /**
24
+ * Render the full report as a single string.
25
+ *
26
+ * @param {object} report Output of validateBomAdvanced().
27
+ * @returns {string}
28
+ */
29
+ export function render(report: object): string;
30
+ //# sourceMappingURL=console.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../../../lib/validator/reporters/console.js"],"names":[],"mappings":"AAuBA;;;;;;GAMG;AACH,yCAJW,KAAK,CAAC,MAAM,CAAC,YACb,MAAM,GACJ,MAAM,CAiClB;AAED;;;;;GAKG;AACH,0CAHW,KAAK,CAAC,MAAM,CAAC,GACX,MAAM,CAmClB;AAED;;;;;GAKG;AACH,uCAHW,MAAM,GACJ,MAAM,CAWlB;AAED;;;;;GAKG;AACH,+BAHW,MAAM,GACJ,MAAM,CAuBlB"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Render a validation report using the named reporter.
3
+ *
4
+ * @param {string} name Reporter identifier.
5
+ * @param {object} report Output of validateBomAdvanced().
6
+ * @param {object} [opts] Reporter-specific options.
7
+ * @returns {string}
8
+ */
9
+ export function render(name: string, report: object, opts?: object): string;
10
+ export namespace reporters {
11
+ export { consoleReporter as console };
12
+ export { json };
13
+ export { sarif };
14
+ export { annotations };
15
+ }
16
+ import * as consoleReporter from "./console.js";
17
+ import * as json from "./json.js";
18
+ import * as sarif from "./sarif.js";
19
+ import * as annotations from "./annotations.js";
20
+ export { annotations, consoleReporter as console, json, sarif };
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../lib/validator/reporters/index.js"],"names":[],"mappings":"AAsBA;;;;;;;GAOG;AACH,6BALW,MAAM,UACN,MAAM,SACN,MAAM,GACJ,MAAM,CAUlB;;;;;;;iCA9BgC,cAAc;sBACzB,WAAW;uBACV,YAAY;6BAHN,kBAAkB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * JSON reporter — emits a stable, documented structure for programmatic use.
3
+ * No dependencies.
4
+ */
5
+ /**
6
+ * @param {object} report Output of validateBomAdvanced().
7
+ * @param {object} [_options] Unused
8
+ * @returns {string}
9
+ */
10
+ export function render(report: object, _options?: object): string;
11
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../../lib/validator/reporters/json.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,+BAJW,MAAM,aACN,MAAM,GACJ,MAAM,CA4BlB"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Render a validation report as SARIF.
3
+ *
4
+ * @param {object} report Output of validateBomAdvanced().
5
+ * @param {object} [options]
6
+ * @param {string} [options.toolName] Override driver name.
7
+ * @param {string} [options.toolVersion] Driver version to embed.
8
+ * @param {boolean} [options.includeManual] Include manual-review findings (default false).
9
+ * @returns {string}
10
+ */
11
+ export function render(report: object, options?: {
12
+ toolName?: string | undefined;
13
+ toolVersion?: string | undefined;
14
+ includeManual?: boolean | undefined;
15
+ }): string;
16
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../../../lib/validator/reporters/sarif.js"],"names":[],"mappings":"AAqIA;;;;;;;;;GASG;AACH,+BAPW,MAAM,YAEd;IAAyB,QAAQ;IACR,WAAW;IACV,aAAa;CACvC,GAAU,MAAM,CA0ClB"}
package/lib/helpers/db.js DELETED
@@ -1,162 +0,0 @@
1
- import path from "node:path";
2
-
3
- import sqlite3 from "@appthreat/sqlite3";
4
-
5
- const {
6
- Database,
7
- OPEN_READWRITE,
8
- OPEN_CREATE,
9
- OPEN_NOMUTEX,
10
- OPEN_SHAREDCACHE,
11
- } = sqlite3;
12
-
13
- /**
14
- * A lightweight Model wrapper to mimic Sequelize behavior using raw sqlite3
15
- */
16
- class Model {
17
- constructor(db, tableName) {
18
- this.db = db;
19
- this.tableName = tableName;
20
- }
21
-
22
- /**
23
- * Initialize table
24
- */
25
- async init() {
26
- const sql = `CREATE TABLE IF NOT EXISTS ${this.tableName} (
27
- purl TEXT PRIMARY KEY,
28
- data JSON NOT NULL,
29
- createdAt DATETIME NOT NULL,
30
- updatedAt DATETIME NOT NULL
31
- )`;
32
- return new Promise((resolve, reject) => {
33
- this.db.run(sql, (err) => {
34
- if (err) reject(err);
35
- else resolve();
36
- });
37
- });
38
- }
39
-
40
- /**
41
- * findByPk
42
- * Returns null if not found, or an object { purl, data (parsed object) }
43
- */
44
- async findByPk(purl) {
45
- const sql = `SELECT * FROM ${this.tableName} WHERE purl = ?`;
46
- return new Promise((resolve, reject) => {
47
- this.db.get(sql, [purl], (err, row) => {
48
- if (err) {
49
- reject(err);
50
- } else if (!row) {
51
- resolve(null);
52
- } else {
53
- try {
54
- row.data = JSON.parse(row.data);
55
- } catch (_e) {
56
- // ignore
57
- }
58
- resolve(row);
59
- }
60
- });
61
- });
62
- }
63
-
64
- /**
65
- * findOrCreate
66
- * @param {Object} options { where: { purl }, defaults: { purl, data } }
67
- */
68
- async findOrCreate(options) {
69
- const { where, defaults } = options;
70
- const existing = await this.findByPk(where.purl);
71
-
72
- if (existing) {
73
- return [existing, false];
74
- }
75
-
76
- const insertSql = `INSERT INTO ${this.tableName} (purl, data, createdAt, updatedAt) VALUES (?, ?, ?, ?)`;
77
- const dataStr =
78
- typeof defaults.data === "string"
79
- ? defaults.data
80
- : JSON.stringify(defaults.data);
81
- const now = new Date().toISOString();
82
- return new Promise((resolve, reject) => {
83
- this.db.run(insertSql, [defaults.purl, dataStr, now, now], (err) => {
84
- if (err) reject(err);
85
- else {
86
- const instance = {
87
- purl: defaults.purl,
88
- data: defaults.data,
89
- createdAt: now,
90
- updatedAt: now,
91
- };
92
- resolve([instance, true]);
93
- }
94
- });
95
- });
96
- }
97
-
98
- /**
99
- * findAll to handle the specific LIKE query from evinser.js
100
- * @param {Object} options
101
- */
102
- async findAll(options) {
103
- let sql = `SELECT * FROM ${this.tableName}`;
104
- const params = [];
105
-
106
- if (options?.where?.data) {
107
- if (options.where.data.like) {
108
- sql += " WHERE data LIKE ?";
109
- params.push(options.where.data.like);
110
- }
111
- }
112
-
113
- return new Promise((resolve, reject) => {
114
- this.db.all(sql, params, (err, rows) => {
115
- if (err) {
116
- reject(err);
117
- } else {
118
- const results = rows.map((r) => {
119
- try {
120
- r.data = JSON.parse(r.data);
121
- } catch (_e) {
122
- // ignore
123
- }
124
- return r;
125
- });
126
- resolve(results);
127
- }
128
- });
129
- });
130
- }
131
- }
132
-
133
- export const createOrLoad = async (dbName, dbPath, logging = false) => {
134
- const fullPath = dbPath.includes("memory")
135
- ? dbPath
136
- : path.join(dbPath, dbName);
137
-
138
- const mode = OPEN_READWRITE | OPEN_CREATE | OPEN_NOMUTEX | OPEN_SHAREDCACHE;
139
-
140
- const db = new Database(fullPath, mode, (err) => {
141
- if (err && logging) console.error(err.message);
142
- });
143
-
144
- if (logging) {
145
- db.on("trace", (sql) => console.log(`[sqlite] ${sql}`));
146
- }
147
-
148
- const Namespaces = new Model(db, "Namespaces");
149
- const Usages = new Model(db, "Usages");
150
- const DataFlows = new Model(db, "DataFlows");
151
-
152
- await Namespaces.init();
153
- await Usages.init();
154
- await DataFlows.init();
155
-
156
- return {
157
- sequelize: db,
158
- Namespaces,
159
- Usages,
160
- DataFlows,
161
- };
162
- };
@@ -1,34 +0,0 @@
1
- import process from "node:process";
2
-
3
- const SUSPICIOUS_NODE_OPTIONS_PATTERNS = [
4
- /--require/i,
5
- /--eval/i,
6
- /--import/i,
7
- /--loader/i,
8
- /--inspect/i,
9
- ];
10
-
11
- const DANGEROUS_VARS = [
12
- "NODE_NO_WARNINGS",
13
- "NODE_PENDING_DEPRECATION",
14
- "UV_THREADPOOL_SIZE",
15
- ];
16
-
17
- export function auditEnvironment(env = process.env) {
18
- const warnings = [];
19
- for (const varName of DANGEROUS_VARS) {
20
- if (env[varName]) {
21
- warnings.push(
22
- `Unset ${varName} before running cdxgen on untrusted repos.`,
23
- );
24
- }
25
- }
26
- for (const pattern of SUSPICIOUS_NODE_OPTIONS_PATTERNS) {
27
- if (pattern.test(env.NODE_OPTIONS)) {
28
- warnings.push(
29
- `NODE_OPTIONS contains code execution flag: ${pattern.toString()}.`,
30
- );
31
- }
32
- }
33
- return warnings;
34
- }
@@ -1,290 +0,0 @@
1
- import { strict as assert } from "node:assert";
2
-
3
- import { describe, test } from "poku";
4
-
5
- import { auditEnvironment } from "./env-audit.js";
6
-
7
- const NODE_OPTIONS_ATTACK_VECTORS = [
8
- {
9
- name: "--require flag",
10
- value: "--require ./evil.js",
11
- expectedMatch: true,
12
- },
13
- {
14
- name: "--require with uppercase",
15
- value: "--REQUIRE ./evil.js",
16
- expectedMatch: true,
17
- },
18
- {
19
- name: "-r short flag",
20
- value: "-r ./evil.js",
21
- expectedMatch: false,
22
- },
23
- {
24
- name: "--eval flag",
25
- value: "--eval \"console.log('pwned')\"",
26
- expectedMatch: true,
27
- },
28
- {
29
- name: "--eval with complex payload",
30
- value: "--eval \"require('child_process').execSync('id')\"",
31
- expectedMatch: true,
32
- },
33
- {
34
- name: "-e short flag",
35
- value: "-e \"console.log('test')\"",
36
- expectedMatch: false,
37
- },
38
- {
39
- name: "--import flag (Node 18+)",
40
- value: "--import ./malicious.mjs",
41
- expectedMatch: true,
42
- },
43
- {
44
- name: "--loader flag",
45
- value: "--loader ./hook-loader.js",
46
- expectedMatch: true,
47
- },
48
- {
49
- name: "--inspect flag",
50
- value: "--inspect=0.0.0.0:9229",
51
- expectedMatch: true,
52
- },
53
- {
54
- name: "--inspect-brk flag",
55
- value: "--inspect-brk=9229",
56
- expectedMatch: true,
57
- },
58
- {
59
- name: "--inspect with host",
60
- value: "--inspect 127.0.0.1:9229",
61
- expectedMatch: true,
62
- },
63
- {
64
- name: "safe memory flag",
65
- value: "--max-old-space-size=4096",
66
- expectedMatch: false,
67
- },
68
- {
69
- name: "safe GC flag",
70
- value: "--expose-gc",
71
- expectedMatch: false,
72
- },
73
- {
74
- name: "safe trace flag",
75
- value: "--trace-warnings",
76
- expectedMatch: false,
77
- },
78
- {
79
- name: "multiple flags with one malicious",
80
- value: "--max-old-space-size=4096 --require ./evil.js",
81
- expectedMatch: true,
82
- },
83
- {
84
- name: "empty string",
85
- value: "",
86
- expectedMatch: false,
87
- },
88
- {
89
- name: "whitespace only",
90
- value: " ",
91
- expectedMatch: false,
92
- },
93
- ];
94
-
95
- const DANGEROUS_ENV_VAR_CASES = [
96
- {
97
- name: "NODE_NO_WARNINGS set",
98
- env: { NODE_NO_WARNINGS: "1" },
99
- expectedWarnings: 1,
100
- expectedVar: "NODE_NO_WARNINGS",
101
- },
102
- {
103
- name: "NODE_PENDING_DEPRECATION set",
104
- env: { NODE_PENDING_DEPRECATION: "1" },
105
- expectedWarnings: 1,
106
- expectedVar: "NODE_PENDING_DEPRECATION",
107
- },
108
- {
109
- name: "UV_THREADPOOL_SIZE set",
110
- env: { UV_THREADPOOL_SIZE: "128" },
111
- expectedWarnings: 1,
112
- expectedVar: "UV_THREADPOOL_SIZE",
113
- },
114
- {
115
- name: "all dangerous vars set",
116
- env: {
117
- NODE_NO_WARNINGS: "1",
118
- NODE_PENDING_DEPRECATION: "1",
119
- UV_THREADPOOL_SIZE: "128",
120
- },
121
- expectedWarnings: 3,
122
- expectedVar: null,
123
- },
124
- {
125
- name: "no dangerous vars",
126
- env: { PATH: "/usr/bin", HOME: "/home/user" },
127
- expectedWarnings: 0,
128
- expectedVar: null,
129
- },
130
- {
131
- name: "dangerous var with empty value (falsy)",
132
- env: { NODE_NO_WARNINGS: "" },
133
- expectedWarnings: 0,
134
- expectedVar: null,
135
- },
136
- ];
137
-
138
- const COMBINED_ATTACK_CASES = [
139
- {
140
- name: "NODE_OPTIONS attack + dangerous vars",
141
- env: {
142
- NODE_OPTIONS: "--require ./evil.js",
143
- NODE_NO_WARNINGS: "1",
144
- UV_THREADPOOL_SIZE: "128",
145
- },
146
- minWarnings: 3,
147
- },
148
- {
149
- name: "multiple NODE_OPTIONS patterns",
150
- env: {
151
- NODE_OPTIONS: '--require ./a.js --eval "code" --inspect',
152
- },
153
- minWarnings: 3,
154
- },
155
- {
156
- name: "clean environment",
157
- env: {},
158
- minWarnings: 0,
159
- },
160
- ];
161
-
162
- describe("auditEnvironment - NODE_OPTIONS Detection", () => {
163
- for (const tc of NODE_OPTIONS_ATTACK_VECTORS) {
164
- test(`should detect ${tc.name}`, () => {
165
- const env = { NODE_OPTIONS: tc.value };
166
- const warnings = auditEnvironment(env);
167
-
168
- const hasSuspiciousWarning = warnings.some((w) =>
169
- w.includes("NODE_OPTIONS contains code execution flag"),
170
- );
171
-
172
- if (tc.expectedMatch) {
173
- assert.ok(
174
- hasSuspiciousWarning,
175
- `Expected warning for ${tc.name} but got: ${warnings.join(", ")}`,
176
- );
177
- } else {
178
- assert.ok(
179
- !hasSuspiciousWarning,
180
- `Unexpected warning for ${tc.name}: ${warnings.join(", ")}`,
181
- );
182
- }
183
- });
184
- }
185
- });
186
-
187
- describe("auditEnvironment - Dangerous Env Vars", () => {
188
- for (const tc of DANGEROUS_ENV_VAR_CASES) {
189
- test(`should handle ${tc.name}`, () => {
190
- const warnings = auditEnvironment(tc.env);
191
-
192
- assert.strictEqual(
193
- warnings.length,
194
- tc.expectedWarnings,
195
- `Expected ${tc.expectedWarnings} warnings, got ${warnings.length}: ${warnings.join(", ")}`,
196
- );
197
-
198
- if (tc.expectedVar) {
199
- assert.ok(
200
- warnings.some((w) => w.includes(tc.expectedVar)),
201
- `Expected warning about ${tc.expectedVar} but got: ${warnings.join(", ")}`,
202
- );
203
- }
204
- });
205
- }
206
- });
207
-
208
- describe("auditEnvironment - Combined Attacks", () => {
209
- for (const tc of COMBINED_ATTACK_CASES) {
210
- test(`should handle ${tc.name}`, () => {
211
- const warnings = auditEnvironment(tc.env);
212
-
213
- assert.ok(
214
- warnings.length >= tc.minWarnings,
215
- `Expected at least ${tc.minWarnings} warnings, got ${warnings.length}: ${warnings.join(", ")}`,
216
- );
217
- });
218
- }
219
- });
220
-
221
- describe("auditEnvironment - Edge Cases", () => {
222
- test("should handle undefined NODE_OPTIONS", () => {
223
- const warnings = auditEnvironment({});
224
- const hasSuspiciousWarning = warnings.some((w) =>
225
- w.includes("NODE_OPTIONS contains code execution flag"),
226
- );
227
- assert.ok(!hasSuspiciousWarning);
228
- });
229
-
230
- test("should handle null env (uses process.env)", () => {
231
- const warnings = auditEnvironment();
232
- assert.ok(Array.isArray(warnings));
233
- });
234
-
235
- test("should return empty array for completely clean env", () => {
236
- const warnings = auditEnvironment({
237
- PATH: "/usr/bin",
238
- HOME: "/home/user",
239
- LANG: "en_US.UTF-8",
240
- });
241
- assert.deepStrictEqual(warnings, []);
242
- });
243
-
244
- test("should detect all dangerous vars individually", () => {
245
- const warnings1 = auditEnvironment({ NODE_NO_WARNINGS: "1" });
246
- const warnings2 = auditEnvironment({ NODE_PENDING_DEPRECATION: "1" });
247
- const warnings3 = auditEnvironment({ UV_THREADPOOL_SIZE: "128" });
248
-
249
- assert.strictEqual(warnings1.length, 1);
250
- assert.strictEqual(warnings2.length, 1);
251
- assert.strictEqual(warnings3.length, 1);
252
-
253
- assert.ok(warnings1[0].includes("NODE_NO_WARNINGS"));
254
- assert.ok(warnings2[0].includes("NODE_PENDING_DEPRECATION"));
255
- assert.ok(warnings3[0].includes("UV_THREADPOOL_SIZE"));
256
- });
257
-
258
- test("should be case-sensitive for env var names", () => {
259
- const warnings = auditEnvironment({
260
- node_no_warnings: "1",
261
- Node_Options: "--require ./evil.js",
262
- });
263
- assert.strictEqual(warnings.length, 0);
264
- });
265
- });
266
-
267
- describe("auditEnvironment - Warning Message Format", () => {
268
- test("dangerous var warning should mention unsetting", () => {
269
- const warnings = auditEnvironment({ NODE_NO_WARNINGS: "1" });
270
- assert.ok(warnings[0].includes("Unset"));
271
- assert.ok(warnings[0].includes("NODE_NO_WARNINGS"));
272
- });
273
-
274
- test("NODE_OPTIONS warning should mention the pattern", () => {
275
- const warnings = auditEnvironment({ NODE_OPTIONS: "--require ./evil.js" });
276
- assert.ok(warnings[0].includes("NODE_OPTIONS"));
277
- assert.ok(warnings[0].includes("code execution flag"));
278
- });
279
-
280
- test("warnings should be human-readable strings", () => {
281
- const warnings = auditEnvironment({
282
- NODE_OPTIONS: "--eval test",
283
- NODE_NO_WARNINGS: "1",
284
- });
285
- for (const w of warnings) {
286
- assert.strictEqual(typeof w, "string");
287
- assert.ok(w.length > 0);
288
- }
289
- });
290
- });