@cyclonedx/cdxgen 12.3.3 → 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.
Files changed (157) hide show
  1. package/README.md +64 -22
  2. package/bin/audit.js +21 -7
  3. package/bin/cdxgen.js +238 -116
  4. package/bin/convert.js +28 -13
  5. package/bin/hbom.js +490 -0
  6. package/bin/repl.js +580 -29
  7. package/bin/validate.js +34 -4
  8. package/bin/verify.js +40 -5
  9. package/data/README.md +298 -25
  10. package/data/component-tags.json +6 -0
  11. package/data/crypto-oid.json +16 -0
  12. package/data/predictive-audit-allowlist.json +11 -0
  13. package/data/queries-darwin.json +12 -1
  14. package/data/queries-win.json +7 -1
  15. package/data/queries.json +39 -2
  16. package/data/rules/ai-agent-governance.yaml +16 -0
  17. package/data/rules/asar-archives.yaml +150 -0
  18. package/data/rules/chrome-extensions.yaml +8 -0
  19. package/data/rules/ci-permissions.yaml +42 -18
  20. package/data/rules/container-risk.yaml +14 -7
  21. package/data/rules/dependency-sources.yaml +11 -0
  22. package/data/rules/hbom-compliance.yaml +325 -0
  23. package/data/rules/hbom-performance.yaml +307 -0
  24. package/data/rules/hbom-security.yaml +248 -0
  25. package/data/rules/host-topology.yaml +165 -0
  26. package/data/rules/mcp-servers.yaml +18 -3
  27. package/data/rules/obom-runtime.yaml +907 -22
  28. package/data/rules/package-integrity.yaml +14 -0
  29. package/data/rules/rootfs-hardening.yaml +179 -0
  30. package/data/rules/vscode-extensions.yaml +9 -0
  31. package/lib/audit/index.js +209 -8
  32. package/lib/audit/index.poku.js +332 -0
  33. package/lib/audit/reporters.js +222 -0
  34. package/lib/audit/targets.js +146 -1
  35. package/lib/audit/targets.poku.js +186 -0
  36. package/lib/cli/asar.poku.js +328 -0
  37. package/lib/cli/index.js +506 -88
  38. package/lib/cli/index.poku.js +1352 -212
  39. package/lib/evinser/evinser.js +14 -9
  40. package/lib/helpers/analyzer.js +1406 -29
  41. package/lib/helpers/analyzer.poku.js +342 -0
  42. package/lib/helpers/analyzerScope.js +712 -0
  43. package/lib/helpers/asarutils.js +1556 -0
  44. package/lib/helpers/asarutils.poku.js +443 -0
  45. package/lib/helpers/auditCategories.js +12 -0
  46. package/lib/helpers/auditCategories.poku.js +32 -0
  47. package/lib/helpers/cbomutils.js +271 -1
  48. package/lib/helpers/cbomutils.poku.js +248 -5
  49. package/lib/helpers/display.js +291 -1
  50. package/lib/helpers/display.poku.js +149 -0
  51. package/lib/helpers/evidenceUtils.js +58 -0
  52. package/lib/helpers/evidenceUtils.poku.js +54 -0
  53. package/lib/helpers/exportUtils.js +9 -0
  54. package/lib/helpers/gtfobins.js +142 -8
  55. package/lib/helpers/gtfobins.poku.js +24 -1
  56. package/lib/helpers/hbom.js +710 -0
  57. package/lib/helpers/hbom.poku.js +496 -0
  58. package/lib/helpers/hbomAnalysis.js +268 -0
  59. package/lib/helpers/hbomAnalysis.poku.js +249 -0
  60. package/lib/helpers/hbomLoader.js +35 -0
  61. package/lib/helpers/hostTopology.js +803 -0
  62. package/lib/helpers/hostTopology.poku.js +363 -0
  63. package/lib/helpers/inventoryStats.js +69 -0
  64. package/lib/helpers/inventoryStats.poku.js +86 -0
  65. package/lib/helpers/lolbas.js +19 -1
  66. package/lib/helpers/lolbas.poku.js +23 -0
  67. package/lib/helpers/osqueryTransform.js +47 -0
  68. package/lib/helpers/osqueryTransform.poku.js +47 -0
  69. package/lib/helpers/plugins.js +349 -0
  70. package/lib/helpers/plugins.poku.js +57 -0
  71. package/lib/helpers/protobom.js +156 -45
  72. package/lib/helpers/protobom.poku.js +140 -5
  73. package/lib/helpers/remote/dependency-track.js +36 -3
  74. package/lib/helpers/remote/dependency-track.poku.js +44 -0
  75. package/lib/helpers/source.js +24 -0
  76. package/lib/helpers/source.poku.js +32 -0
  77. package/lib/helpers/utils.js +1438 -93
  78. package/lib/helpers/utils.poku.js +846 -4
  79. package/lib/managers/binary.e2e.poku.js +367 -0
  80. package/lib/managers/binary.js +2293 -353
  81. package/lib/managers/binary.poku.js +1699 -1
  82. package/lib/managers/docker.js +201 -79
  83. package/lib/managers/docker.poku.js +337 -12
  84. package/lib/server/server.js +2 -27
  85. package/lib/stages/postgen/annotator.js +38 -0
  86. package/lib/stages/postgen/annotator.poku.js +107 -1
  87. package/lib/stages/postgen/auditBom.js +121 -18
  88. package/lib/stages/postgen/auditBom.poku.js +1366 -31
  89. package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
  90. package/lib/stages/postgen/postgen.js +192 -1
  91. package/lib/stages/postgen/postgen.poku.js +321 -0
  92. package/lib/stages/postgen/ruleEngine.js +116 -0
  93. package/lib/stages/pregen/envAudit.js +14 -3
  94. package/package.json +23 -21
  95. package/types/bin/hbom.d.ts +3 -0
  96. package/types/bin/hbom.d.ts.map +1 -0
  97. package/types/bin/repl.d.ts.map +1 -1
  98. package/types/lib/audit/index.d.ts +44 -0
  99. package/types/lib/audit/index.d.ts.map +1 -1
  100. package/types/lib/audit/reporters.d.ts +16 -0
  101. package/types/lib/audit/reporters.d.ts.map +1 -1
  102. package/types/lib/audit/targets.d.ts.map +1 -1
  103. package/types/lib/cli/index.d.ts +16 -0
  104. package/types/lib/cli/index.d.ts.map +1 -1
  105. package/types/lib/evinser/evinser.d.ts +4 -0
  106. package/types/lib/evinser/evinser.d.ts.map +1 -1
  107. package/types/lib/helpers/analyzer.d.ts +33 -0
  108. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  109. package/types/lib/helpers/analyzerScope.d.ts +11 -0
  110. package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
  111. package/types/lib/helpers/asarutils.d.ts +34 -0
  112. package/types/lib/helpers/asarutils.d.ts.map +1 -0
  113. package/types/lib/helpers/auditCategories.d.ts +5 -0
  114. package/types/lib/helpers/auditCategories.d.ts.map +1 -1
  115. package/types/lib/helpers/cbomutils.d.ts +3 -2
  116. package/types/lib/helpers/cbomutils.d.ts.map +1 -1
  117. package/types/lib/helpers/display.d.ts.map +1 -1
  118. package/types/lib/helpers/evidenceUtils.d.ts +8 -0
  119. package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
  120. package/types/lib/helpers/exportUtils.d.ts.map +1 -1
  121. package/types/lib/helpers/gtfobins.d.ts +8 -0
  122. package/types/lib/helpers/gtfobins.d.ts.map +1 -1
  123. package/types/lib/helpers/hbom.d.ts +49 -0
  124. package/types/lib/helpers/hbom.d.ts.map +1 -0
  125. package/types/lib/helpers/hbomAnalysis.d.ts +62 -0
  126. package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
  127. package/types/lib/helpers/hbomLoader.d.ts +7 -0
  128. package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
  129. package/types/lib/helpers/hostTopology.d.ts +12 -0
  130. package/types/lib/helpers/hostTopology.d.ts.map +1 -0
  131. package/types/lib/helpers/inventoryStats.d.ts +11 -0
  132. package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
  133. package/types/lib/helpers/lolbas.d.ts.map +1 -1
  134. package/types/lib/helpers/osqueryTransform.d.ts +3 -0
  135. package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
  136. package/types/lib/helpers/plugins.d.ts +58 -0
  137. package/types/lib/helpers/plugins.d.ts.map +1 -0
  138. package/types/lib/helpers/protobom.d.ts +3 -4
  139. package/types/lib/helpers/protobom.d.ts.map +1 -1
  140. package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
  141. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
  142. package/types/lib/helpers/source.d.ts.map +1 -1
  143. package/types/lib/helpers/utils.d.ts +45 -8
  144. package/types/lib/helpers/utils.d.ts.map +1 -1
  145. package/types/lib/managers/binary.d.ts +5 -0
  146. package/types/lib/managers/binary.d.ts.map +1 -1
  147. package/types/lib/managers/docker.d.ts.map +1 -1
  148. package/types/lib/server/server.d.ts +2 -1
  149. package/types/lib/server/server.d.ts.map +1 -1
  150. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  151. package/types/lib/stages/postgen/auditBom.d.ts +26 -1
  152. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  153. package/types/lib/stages/postgen/postgen.d.ts +2 -1
  154. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  155. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  156. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  157. package/data/spdx-model-v3.0.1.jsonld +0 -15999
package/bin/validate.js CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  retrieveCdxgenVersion,
29
29
  safeExistsSync,
30
30
  safeMkdirSync,
31
+ safeWriteSync,
31
32
  } from "../lib/helpers/utils.js";
32
33
  import { getBomWithOras } from "../lib/managers/oci.js";
33
34
  import { shouldFail, validateBomAdvanced } from "../lib/validator/index.js";
@@ -39,7 +40,7 @@ const args = _yargs
39
40
  .option("input", {
40
41
  alias: "i",
41
42
  default: "bom.json",
42
- description: "Input SBOM JSON file or OCI reference.",
43
+ description: "Input SBOM JSON or protobuf file, or an OCI reference.",
43
44
  })
44
45
  .option("platform", {
45
46
  description:
@@ -128,9 +129,18 @@ const args = _yargs
128
129
  .help()
129
130
  .wrap(Math.min(120, yargs().terminalWidth())).argv;
130
131
 
131
- function loadBom(input, platform) {
132
+ async function loadBom(input, platform) {
132
133
  if (safeExistsSync(input)) {
134
+ const normalizedInput = `${input}`.toLowerCase();
133
135
  try {
136
+ if (
137
+ normalizedInput.endsWith(".cdx") ||
138
+ normalizedInput.endsWith(".cdx.bin") ||
139
+ normalizedInput.endsWith(".proto")
140
+ ) {
141
+ const { readBinary } = await import("../lib/helpers/protobom.js");
142
+ return readBinary(input, true);
143
+ }
134
144
  return JSON.parse(fs.readFileSync(input, "utf8"));
135
145
  } catch (err) {
136
146
  console.error(`Failed to parse ${input}: ${err.message}`);
@@ -176,16 +186,36 @@ function writeOrPrint(content, outputPath) {
176
186
  if (parent && !safeExistsSync(parent)) {
177
187
  safeMkdirSync(parent, { recursive: true });
178
188
  }
179
- fs.writeFileSync(outputPath, content);
189
+ safeWriteSync(outputPath, content);
180
190
  }
181
191
 
182
- const bomJson = loadBom(args.input, args.platform);
192
+ function isLocalProtoBomInput(input) {
193
+ if (!safeExistsSync(input)) {
194
+ return false;
195
+ }
196
+ const normalizedInput = `${input}`.toLowerCase();
197
+ return (
198
+ normalizedInput.endsWith(".cdx") ||
199
+ normalizedInput.endsWith(".cdx.bin") ||
200
+ normalizedInput.endsWith(".proto")
201
+ );
202
+ }
203
+
204
+ const bomJson = await loadBom(args.input, args.platform);
183
205
  const publicKeyStr = loadPublicKey(args.publicKey);
206
+ const inputIsLocalProtoBom = isLocalProtoBomInput(args.input);
184
207
  if (!isCycloneDxBom(bomJson)) {
185
208
  console.error(getNonCycloneDxErrorMessage(bomJson, "cdx-validate"));
186
209
  process.exit(1);
187
210
  }
188
211
 
212
+ if (inputIsLocalProtoBom && publicKeyStr) {
213
+ console.error(
214
+ "cdx-validate: protobuf BOM input does not currently preserve JSF signature blocks. Verify signatures against the source JSON BOM instead.",
215
+ );
216
+ process.exit(args.requireSignature ? 4 : 1);
217
+ }
218
+
189
219
  const report = validateBomAdvanced(bomJson, {
190
220
  schema: args.schema,
191
221
  deep: args.deep,
package/bin/verify.js CHANGED
@@ -27,7 +27,8 @@ const args = _yargs
27
27
  .option("input", {
28
28
  alias: "i",
29
29
  default: "bom.json",
30
- description: "Input json to validate. Default bom.json",
30
+ description:
31
+ "Input CycloneDX JSON or protobuf BOM to verify. Default bom.json",
31
32
  })
32
33
  .option("platform", {
33
34
  description: "The platform to validate. No default",
@@ -75,9 +76,23 @@ if (process.env?.CDXGEN_NODE_OPTIONS) {
75
76
  process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ""} ${process.env.CDXGEN_NODE_OPTIONS}`;
76
77
  }
77
78
 
78
- function getBom(args) {
79
- if (fs.existsSync(args.input)) {
80
- return JSON.parse(fs.readFileSync(args.input, "utf8"));
79
+ async function getBom(args) {
80
+ if (safeExistsSync(args.input)) {
81
+ const normalizedInput = `${args.input}`.toLowerCase();
82
+ try {
83
+ if (
84
+ normalizedInput.endsWith(".cdx") ||
85
+ normalizedInput.endsWith(".cdx.bin") ||
86
+ normalizedInput.endsWith(".proto")
87
+ ) {
88
+ const { readBinary } = await import("../lib/helpers/protobom.js");
89
+ return readBinary(args.input, true);
90
+ }
91
+ return JSON.parse(fs.readFileSync(args.input, "utf8"));
92
+ } catch (error) {
93
+ console.log(`Failed to parse '${args.input}': ${error.message}`);
94
+ process.exit(1);
95
+ }
81
96
  }
82
97
  if (
83
98
  args.input.includes(":") ||
@@ -89,7 +104,20 @@ function getBom(args) {
89
104
  return undefined;
90
105
  }
91
106
 
92
- const bomJson = getBom(args);
107
+ function isLocalProtoBomInput(input) {
108
+ if (!safeExistsSync(input)) {
109
+ return false;
110
+ }
111
+ const normalizedInput = `${input}`.toLowerCase();
112
+ return (
113
+ normalizedInput.endsWith(".cdx") ||
114
+ normalizedInput.endsWith(".cdx.bin") ||
115
+ normalizedInput.endsWith(".proto")
116
+ );
117
+ }
118
+
119
+ const bomJson = await getBom(args);
120
+ const inputIsLocalProtoBom = isLocalProtoBomInput(args.input);
93
121
 
94
122
  if (!bomJson) {
95
123
  console.log(`${args.input} is invalid!`);
@@ -100,6 +128,13 @@ if (!isCycloneDxBom(bomJson)) {
100
128
  process.exit(1);
101
129
  }
102
130
 
131
+ if (inputIsLocalProtoBom) {
132
+ console.log(
133
+ "cdx-verify: protobuf BOM input does not currently preserve JSF signature blocks. Verify signatures against the source JSON BOM instead.",
134
+ );
135
+ process.exit(1);
136
+ }
137
+
103
138
  if (bomJson && !safeExistsSync(args.publicKey)) {
104
139
  console.log("Public key for signature verification is missing!");
105
140
  process.exit(1);
package/data/README.md CHANGED
@@ -1,27 +1,300 @@
1
1
  # Introduction
2
2
 
3
- Contents of data directory and their purpose.
4
-
5
- | Filename | Purpose |
6
- | ----------------------- | -------------------------------------------------------------------------------------------------------- |
7
- | bom-1.4.schema.json | CycloneDX 1.4 jsonschema for validation |
8
- | bom-1.5.schema.json | CycloneDX 1.5 jsonschema for validation |
9
- | cosdb-queries.json | osquery useful for identifying OS packages for C |
10
- | cbomosdb-queries.json | osquery for identifying ssl packages in OS |
11
- | jsf-0.82.schema.json | jsonschema for validation |
12
- | known-licenses.json | Hard coded list to correct any license id. Not maintained. |
13
- | lic-mapping.json | Hard coded list to match a license id based on name |
14
- | pypi-pkg-aliases.json | Hard coded list to match a pypi package name from module name |
15
- | python-stdlib.json | Standard libraries that can be filtered out in python |
16
- | queries-win.json | osquery used to generate obom for windows |
17
- | queries.json | osquery used to generate obom for linux |
18
- | queries-darwin.json | osquery used to generate obom for darwin |
19
- | spdx-licenses.json | valid spdx id |
20
- | spdx.schema.json | jsonschema for validation |
21
- | vendor-alias.json | List to correct the group names. Used while parsing .jar files |
22
- | wrapdb-releases.json | Database of all available meson wraps. Generated using contrib/wrapdb.py. |
23
- | frameworks-list.json | List of string fragments to categorize components into frameworks |
24
- | crypto-oid.json | Peter Gutmann's crypto oid [mapping](https://www.cs.auckland.ac.nz/~pgut001). GPL, BSD, or CC BY license |
25
- | glibc-stdlib.json | Standard libraries that can be filtered out in C++ |
26
- | component-tags.json | List of tags to extract from component description text for easy classification. |
27
- | ruby-known-modules.json | Module names for certain known gems. Example: rails |
3
+ This directory contains static knowledge that cdxgen uses at runtime. Some files are passive reference data. Others directly shape behavior, especially query packs, rule files, schemas, aliases, and component-tag metadata.
4
+
5
+ ## Purpose of this directory
6
+
7
+ Treat `data/` as product behavior, not as a convenient dump of reference files. If a file here is stale, incomplete, or incorrectly sourced, it can change runtime output, validation behavior, or audit findings.
8
+
9
+ ## Contribution policy
10
+
11
+ Direct pull requests that only hand-edit curated data in `data/` are not accepted. Start with an issue or a broader change proposal that explains:
12
+
13
+ 1. the upstream source of truth
14
+ 2. whether the file is upstream, derived, or hand-curated
15
+ 3. how it should be refreshed
16
+ 4. what tests or validation prove the update is safe
17
+
18
+ Prefer adding or improving automation under `contrib/` over one-off manual edits.
19
+
20
+ ## Directory contents
21
+
22
+ | Filename | Purpose | Source | Curation / refresh path |
23
+ |---|---|---|---|
24
+ | `bom-1.4.schema.json` | CycloneDX 1.4 JSON schema for legacy compatibility validation | CycloneDX specification schema | upstream-derived compatibility copy; active feature work should target 1.5–1.7 |
25
+ | `bom-1.5.schema.json` | CycloneDX 1.5 JSON schema for validation | CycloneDX specification schema | upstream-derived |
26
+ | `bom-1.6.schema.json` | CycloneDX 1.6 JSON schema for validation | CycloneDX specification schema | upstream-derived |
27
+ | `bom-1.7.schema.json` | CycloneDX 1.7 JSON schema for validation | CycloneDX specification schema | upstream-derived |
28
+ | `cbomosdb-queries.json` | osquery queries for identifying SSL packages in OS contexts | project-maintained query pack | hand-curated with tests; should evolve with query-pack review |
29
+ | `component-tags.json` | tags extracted from component descriptions for classification | project-maintained derived dataset | partially curated; automation opportunities remain |
30
+ | `container-knowledge-index.json` | reference knowledge for container analysis | project-maintained derived dataset | partially curated; automation opportunities remain |
31
+ | `cosdb-queries.json` | osquery queries useful for identifying OS packages for C | project-maintained query pack | hand-curated with tests |
32
+ | `crypto-oid.json` | OID mapping reference used for crypto-aware output | standards and project-maintained mapping inputs | curated compatibility dataset |
33
+ | `cryptography-defs.json` | cryptography inventory definitions | project-maintained definitions | curated; should be kept aligned with analyzer and CBOM logic |
34
+ | `frameworks-list.json` | string fragments used to classify framework components | project-maintained heuristics | hand-curated; good candidate for future automation |
35
+ | `gtfobins-index.json` | GTFOBins reference data used for Linux container and runtime executable enrichment | GTFOBins project data plus project normalization | derived and normalized for cdxgen |
36
+ | `known-licenses.json` | hard-coded license corrections | project-maintained compatibility fixes | hand-curated escape hatch; prefer upstream/source fixes when possible |
37
+ | `lic-mapping.json` | fallback license-name to identifier mapping | project-maintained mapping | hand-curated compatibility layer |
38
+ | `lolbas-index.json` | LOLBAS reference data used for Windows runtime findings | LOLBAS project data plus project normalization | derived and normalized for cdxgen |
39
+ | `predictive-audit-allowlist.json` | allowlist data for audit behavior | project-maintained heuristics | curated; should be reviewed alongside audit targeting logic |
40
+ | `pypi-pkg-aliases.json` | Python package-name alias data | project-maintained alias mapping | hand-curated compatibility layer |
41
+ | `python-stdlib.json` | Python standard-library entries that can be filtered out | Python stdlib references plus project normalization | derived list; automation opportunities remain |
42
+ | `queries.json` | Linux osquery query pack for OBOM and runtime inventory | project-maintained query pack | hand-curated with tests |
43
+ | `queries-win.json` | Windows osquery query pack | project-maintained query pack | hand-curated with tests |
44
+ | `queries-darwin.json` | macOS osquery query pack | project-maintained query pack | hand-curated with tests |
45
+ | `rules/` | built-in BOM audit rule packs in YAML | project-maintained rule packs | hand-authored rules validated by tests; users can also supply their own rule packs |
46
+ | `spdx-licenses.json` | SPDX license identifiers | SPDX License List data | upstream-derived |
47
+ | `spdx-export.schema.json` | SPDX 3.0.1 schema used during export validation | project-derived export schema generated from SPDX model artifacts | derived artifact; there is not a single upstream-published JSON schema that exactly matches this export use case |
48
+ | `spdx.schema.json` | SPDX schema for validation | SPDX JSON schema inputs used by the project | upstream-derived compatibility copy |
49
+ | `vendor-alias.json` | vendor or group-name alias fixes | project-maintained alias mapping | hand-curated compatibility layer; should eventually be reduced as heuristics improve |
50
+ | `wrapdb-releases.json` | Meson WrapDB release data | Meson WrapDB | derived artifact; refresh automation still needs to be formalized and maintained |
51
+
52
+ ## How this directory fits into the architecture
53
+
54
+ ### ASCII view
55
+
56
+ ```text
57
+ runtime code
58
+ |
59
+ +--> lib/cli/* -----------> alias files, framework lists, tag maps
60
+ |
61
+ +--> lib/stages/postgen/* -> rule packs, standards data, schemas
62
+ |
63
+ +--> lib/audit/* ---------> rules/, allowlists, scoring support data
64
+ |
65
+ +--> lib/validator/* -----> CycloneDX and SPDX schemas
66
+ |
67
+ +--> OBOM flows ----------> queries*.json, GTFOBins, LOLBAS, knowledge indexes
68
+ ```
69
+
70
+ ### Mermaid view
71
+
72
+ ```mermaid
73
+ flowchart TD
74
+ A[data/] --> B[schemas]
75
+ A --> C[query packs]
76
+ A --> D[rule files]
77
+ A --> E[alias and mapping files]
78
+ A --> F[knowledge indexes]
79
+ B --> G[validator]
80
+ C --> H[OBOM and runtime inventory]
81
+ D --> I[audit engine]
82
+ E --> J[parsers and metadata helpers]
83
+ F --> K[container and runtime enrichment]
84
+ ```
85
+
86
+ ## Query-pack files
87
+
88
+ The three `queries*.json` files are platform-specific osquery packs. They describe what cdxgen should ask osquery for when generating OS and runtime inventory.
89
+
90
+ ### Query-pack shape
91
+
92
+ | Field | Required | Purpose |
93
+ |---|---|---|
94
+ | `query` | yes | SQL executed against osquery |
95
+ | `description` | yes | human-readable explanation of the collection intent |
96
+ | `purlType` | yes | package URL type used for derived components |
97
+ | `componentType` | no | CycloneDX component type when `library` is not appropriate |
98
+ | `name` | no | component-name override for result sets that do not naturally expose one |
99
+
100
+ ### Example mental model
101
+
102
+ ```text
103
+ queries.json entry
104
+ |
105
+ v
106
+ osquery runs SQL
107
+ |
108
+ v
109
+ rows come back
110
+ |
111
+ v
112
+ cdxgen maps rows into components using purlType and componentType
113
+ ```
114
+
115
+ ### Good query-pack hygiene
116
+
117
+ | Practice | Why it matters |
118
+ |---|---|
119
+ | keep descriptions specific | helps users understand collected categories |
120
+ | choose `componentType` carefully | affects how consumers interpret results |
121
+ | mirror cross-platform entries intentionally | reduces accidental platform drift |
122
+ | keep query scope safe and bounded | avoids expensive or unsafe collection |
123
+
124
+ ## Rule files under `data/rules/`
125
+
126
+ Rule files are YAML packs consumed by the audit flow. Each file groups rules by a shared theme such as container risk, rootfs hardening, OBOM runtime posture, or AI agent governance.
127
+
128
+ ### Rule evaluation flow
129
+
130
+ #### ASCII view
131
+
132
+ ```text
133
+ input BOM
134
+ |
135
+ v
136
+ load YAML rule pack
137
+ |
138
+ v
139
+ for each rule
140
+ |
141
+ +--> evaluate JSONata condition against BOM
142
+ +--> collect matching components
143
+ +--> build location object
144
+ +--> render message template
145
+ +--> attach mitigation, evidence, ATT&CK, and standards metadata
146
+ |
147
+ v
148
+ audit findings
149
+ ```
150
+
151
+ #### Mermaid view
152
+
153
+ ```mermaid
154
+ flowchart TD
155
+ A[BOM input] --> B[load rule YAML]
156
+ B --> C[evaluate condition]
157
+ C --> D{matched components?}
158
+ D -->|no| E[no finding]
159
+ D -->|yes| F[build location and message]
160
+ F --> G[attach mitigation and evidence]
161
+ G --> H[emit finding]
162
+ ```
163
+
164
+ ## Rule schema in practice
165
+
166
+ Each rule is a YAML list item. These fields matter most.
167
+
168
+ | Field | Required | Purpose |
169
+ |---|---|---|
170
+ | `id` | yes | unique stable identifier such as `CTR-001` |
171
+ | `name` | yes | short title used in findings |
172
+ | `description` | yes | why the rule exists and what it detects |
173
+ | `severity` | yes | risk level such as `critical`, `high`, `medium`, `low`, `info` |
174
+ | `category` | yes | thematic category that usually aligns with the file grouping |
175
+ | `dry-run-support` | yes | whether the rule can work on dry-run style BOMs |
176
+ | `condition` | yes | JSONata expression that selects matching components |
177
+ | `location` | yes | JSONata expression that builds a location object for the match |
178
+ | `message` | yes | rendered finding text, including placeholders |
179
+ | `mitigation` | yes | remediation guidance shown with the finding |
180
+ | `evidence` | no | extra structured data carried with the finding |
181
+ | `attack` | no | MITRE ATT&CK mapping data |
182
+ | `standards` | no | mapping of standard names to reference identifiers; surfaced in audit annotations as `cdx:audit:standards:*` metadata |
183
+
184
+ ## Writing `condition` expressions
185
+
186
+ Conditions are written in JSONata and evaluated against the BOM document. In practice, most rules filter the `components` array.
187
+
188
+ ```yaml
189
+ condition: |
190
+ components[
191
+ $prop($, 'cdx:some:property') = 'expected-value'
192
+ and type = 'library'
193
+ ]
194
+ ```
195
+
196
+ ### Helper functions commonly used in rules
197
+
198
+ | Function | Purpose |
199
+ |---|---|
200
+ | `$prop(component, name)` | fetches a CycloneDX property by name |
201
+ | `$nullSafeProp(component, name)` | null-safe property fetch for comparisons |
202
+ | `$listContains(list, value)` | checks list-like property text for a specific entry |
203
+ | `$firstNonEmpty(a, b, ...)` | returns the first non-empty value |
204
+
205
+ ### Thinking about rule conditions
206
+
207
+ A good condition is usually:
208
+
209
+ 1. specific enough to avoid noise
210
+ 2. readable enough for reviewers to reason about
211
+ 3. based on stable properties that cdxgen already emits consistently
212
+
213
+ ## Message rendering
214
+
215
+ The `message` field supports template placeholders using double braces.
216
+
217
+ ```yaml
218
+ message: "Package '{{ name }}' at version '{{ version }}' is affected"
219
+ ```
220
+
221
+ Those expressions are evaluated in the context of the matched component. Keep messages clear and reviewer-friendly. The message should explain the risk without requiring the reader to decode the raw JSONata condition.
222
+
223
+ ## Authoring rules with the REPL
224
+
225
+ Use `cdxi` when you want a tight feedback loop while authoring or debugging a rule. A practical flow is:
226
+
227
+ ```text
228
+ cdxi bom.json
229
+ .query components[type = 'library']
230
+ .query components[$prop($, 'cdx:github:action:isShaPinned') = 'false']
231
+ .auditfindings
232
+ .validate
233
+ ```
234
+
235
+ Why this helps:
236
+
237
+ | REPL command | Use while authoring rules |
238
+ |---|---|
239
+ | `.query <jsonata>` | test the JSONata shape before copying it into a YAML rule |
240
+ | `.inspect <name-or-purl>` | inspect a concrete component when a condition is too broad or too narrow |
241
+ | `.auditfindings` | review existing annotations produced by `--bom-audit` or `cdx-audit` |
242
+ | `.validate` | quickly validate the loaded BOM before concluding the rule is wrong |
243
+
244
+ ## Using custom rule packs
245
+
246
+ Users can maintain their own rule packs outside this repository and supply the directory at runtime.
247
+
248
+ ```bash
249
+ # Apply custom rules during BOM generation
250
+ cdxgen --bom-audit --bom-audit-rules-dir ./my-rules -o bom.json
251
+
252
+ # Apply custom rules with the standalone audit command
253
+ cdx-audit --bom bom.json --direct-bom-audit --rules-dir ./my-rules
254
+ ```
255
+
256
+ This is the preferred path for organization-specific policy rather than submitting narrowly scoped custom rules into `data/rules/`.
257
+
258
+ ## Adding a new rule safely
259
+
260
+ Use this sequence.
261
+
262
+ 1. choose the correct category file under `data/rules/`
263
+ 2. draft the condition against a real BOM sample
264
+ 3. keep the location object small and actionable
265
+ 4. add mitigation text that tells the user what to do next
266
+ 5. add or update tests in `lib/stages/postgen/auditBom.poku.js`
267
+
268
+ ## Choosing between a rule, a query-pack entry, and a helper-data file
269
+
270
+ | If you need to add... | It probably belongs in... |
271
+ |---|---|
272
+ | a new risk detection idea over existing BOM fields | `data/rules/*.yaml` |
273
+ | a new host or runtime collection source | `queries*.json` |
274
+ | a new alias, mapping, or classifier list | another JSON file in `data/` |
275
+ | a new schema or validation artifact | `data/*schema*.json` |
276
+
277
+ ## Automation and maintenance gaps
278
+
279
+ Some files in `data/` are still compatibility layers, hand-curated heuristics, or locally derived artifacts. The goal should be to reduce those hacks over time, not normalize them.
280
+
281
+ Current expectations:
282
+
283
+ 1. open an issue before proposing a new refresh process or replacing a derived artifact
284
+ 2. document the upstream source and whether the file is hand-curated, upstream, or locally derived
285
+ 3. prefer a repeatable refresh script under `contrib/` where practical
286
+ 4. keep tests close to any rule or query-pack change
287
+
288
+ `wrapdb-releases.json` remains a derived artifact, but its refresh path still needs to be formalized and maintained like the rest of the curated datasets. Those gaps should be tracked as issue-first follow-up work rather than solved with silent one-off edits.
289
+
290
+ ## Maintenance advice
291
+
292
+ This directory changes slowly, but small mistakes here can affect a lot of runtime behavior. Treat edits as code, not content.
293
+
294
+ | Habit | Why it helps |
295
+ |---|---|
296
+ | keep examples close to real emitted fields | avoids stale rules |
297
+ | review platform symmetry for query packs | avoids one-OS regressions |
298
+ | test new rules with realistic BOM fixtures | catches false positives early |
299
+ | document new files here | keeps contributors oriented |
300
+ | replace hacks with sourced or scripted refresh paths when possible | keeps long-term maintenance manageable |
@@ -158,6 +158,7 @@
158
158
  "processor",
159
159
  "services_snapshot",
160
160
  "apt_sources",
161
+ "apt_ppa_sources",
161
162
  "behavioral_reverse_shell",
162
163
  "certificates",
163
164
  "chrome_extensions",
@@ -169,6 +170,7 @@
169
170
  "docker_volumes",
170
171
  "etc_hosts",
171
172
  "firefox_addons",
173
+ "gatekeeper",
172
174
  "vscode_extensions",
173
175
  "homebrew_packages",
174
176
  "installed_applications",
@@ -183,13 +185,16 @@
183
185
  "pipes_snapshot",
184
186
  "portage_packages",
185
187
  "process_events",
188
+ "secureboot_certificates",
186
189
  "processes",
187
190
  "python_packages",
191
+ "npm_packages",
188
192
  "rpm_packages",
189
193
  "scheduled_tasks",
190
194
  "services_snapshot",
191
195
  "startup_items",
192
196
  "system_info_snapshot",
197
+ "trusted_gpg_keys",
193
198
  "windows_drivers",
194
199
  "windows_patches",
195
200
  "windows_programs",
@@ -207,6 +212,7 @@
207
212
  "npm_packages",
208
213
  "opera_extensions",
209
214
  "pipes_snapshot",
215
+ "process_open_handles_snapshot",
210
216
  "process_open_sockets",
211
217
  "safari_extensions",
212
218
  "scheduled_tasks",
@@ -1023,6 +1023,22 @@
1023
1023
  "oid": "1.3.101.113",
1024
1024
  "description": "EdDSA 448 signature algorithm"
1025
1025
  },
1026
+ "Ed25519": {
1027
+ "oid": "1.3.101.112",
1028
+ "description": "EdDSA 25519 signature algorithm"
1029
+ },
1030
+ "ed25519": {
1031
+ "oid": "1.3.101.112",
1032
+ "description": "EdDSA 25519 signature algorithm"
1033
+ },
1034
+ "Ed448": {
1035
+ "oid": "1.3.101.113",
1036
+ "description": "EdDSA 448 signature algorithm"
1037
+ },
1038
+ "ed448": {
1039
+ "oid": "1.3.101.113",
1040
+ "description": "EdDSA 448 signature algorithm"
1041
+ },
1026
1042
  "curveEd25519ph": {
1027
1043
  "oid": "1.3.101.114",
1028
1044
  "description": "EdDSA 25519 pre-hash signature algorithm"
@@ -0,0 +1,11 @@
1
+ [
2
+ "pkg:npm/%40babel",
3
+ "pkg:npm/%40eslint",
4
+ "pkg:npm/%40istanbuljs",
5
+ "pkg:npm/%40jest",
6
+ "pkg:npm/%40npmcli",
7
+ "pkg:npm/%40rollup",
8
+ "pkg:npm/%40types",
9
+ "pkg:npm/%40typescript-eslint",
10
+ "pkg:npm/npm"
11
+ ]
@@ -35,6 +35,12 @@
35
35
  "purlType": "swid",
36
36
  "componentType": "application"
37
37
  },
38
+ "gatekeeper": {
39
+ "query": "SELECT 'gatekeeper' as name, COALESCE(NULLIF(version, ''), opaque_version) as version, opaque_version as description, assessments_enabled, dev_id_enabled FROM gatekeeper;",
40
+ "description": "macOS Gatekeeper policy status, including assessment enforcement and identified-developer allowance.",
41
+ "purlType": "swid",
42
+ "componentType": "data"
43
+ },
38
44
  "system_extensions": {
39
45
  "query": "select * from system_extensions;",
40
46
  "description": "macOS (>= 10.15) system extension table.",
@@ -71,6 +77,11 @@
71
77
  "purlType": "swid",
72
78
  "componentType": "application"
73
79
  },
80
+ "npm_packages": {
81
+ "query": "SELECT * FROM npm_packages;",
82
+ "description": "Node packages installed on the system, including recursively discovered modern package manager layouts.",
83
+ "purlType": "npm"
84
+ },
74
85
  "launchd_services": {
75
86
  "query": "SELECT name, label, path, program, run_at_load, keep_alive, disabled, username, groupname, stdout_path, stderr_path, start_interval, program_arguments, watch_paths, queue_directories, start_on_mount, working_directory, process_type FROM launchd;",
76
87
  "description": "LaunchAgents and LaunchDaemons configuration used for macOS persistence.",
@@ -108,7 +119,7 @@
108
119
  "componentType": "data"
109
120
  },
110
121
  "package_bom": {
111
- "query": "SELECT * FROM package_bom;",
122
+ "query": "SELECT * FROM package_bom WHERE path IN (SELECT REPLACE(package_receipts.path, '.plist', '.bom') FROM package_receipts JOIN file ON file.path = REPLACE(package_receipts.path, '.plist', '.bom') WHERE package_receipts.path LIKE '%.plist' AND file.size <= 52428800);",
112
123
  "description": "macOS package bill of materials (BOM) file list.",
113
124
  "purlType": "swid",
114
125
  "componentType": "application"
@@ -36,7 +36,7 @@
36
36
  "purlType": "swid"
37
37
  },
38
38
  "ie_extensions": {
39
- "query": "select ie_extensions.* from users join ie_extensions using (uid);",
39
+ "query": "select * from ie_extensions;",
40
40
  "description": "Retrieves the list of extensions for IE in the target system.",
41
41
  "purlType": "swid"
42
42
  },
@@ -112,6 +112,12 @@
112
112
  "purlType": "swid",
113
113
  "componentType": "data"
114
114
  },
115
+ "process_open_handles_snapshot": {
116
+ "query": "SELECT processes.name, process_open_handles.type as version, process_open_handles.name as description, processes.path, processes.cmdline, processes.pid, process_open_handles.value, process_open_handles.type, process_open_handles.name as handle_name, process_open_handles.access, process_open_handles.attributes, process_open_handles.count, process_open_handles.raw_pointer_count, process_open_handles.error_stage, process_open_handles.error_code FROM processes JOIN process_open_handles USING (pid) WHERE process_open_handles.name != '' AND processes.name IN ('powershell.exe', 'pwsh.exe', 'cmd.exe', 'wscript.exe', 'cscript.exe', 'mshta.exe', 'rundll32.exe', 'regsvr32.exe', 'wmic.exe', 'certutil.exe', 'bitsadmin.exe') AND ((process_open_handles.type = 'File' AND (lower(process_open_handles.name) LIKE '%\\appdata\\local\\temp\\%' OR lower(process_open_handles.name) LIKE '%\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\startup\\%' OR lower(process_open_handles.name) LIKE '%\\programdata\\microsoft\\windows\\start menu\\programs\\startup\\%' OR lower(process_open_handles.name) LIKE '%\\windows\\tasks\\%' OR lower(process_open_handles.name) LIKE '%\\system32\\tasks\\%' OR lower(process_open_handles.name) LIKE '%\\wbem\\repository\\%')) OR (process_open_handles.type = 'Key' AND (lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows\\currentversion\\run%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows\\currentversion\\runonce%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows nt\\currentversion\\winlogon%' OR lower(process_open_handles.name) LIKE '%\\system\\currentcontrolset\\services\\%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\windows nt\\currentversion\\schedule\\taskcache\\%' OR lower(process_open_handles.name) LIKE '%\\software\\microsoft\\wbem\\cimom%')));",
117
+ "description": "Open handles owned by high-signal scripting and proxy-execution processes, filtered to persistence-oriented file and registry locations on Windows endpoints.",
118
+ "purlType": "swid",
119
+ "componentType": "data"
120
+ },
115
121
  "services_snapshot": {
116
122
  "query": "SELECT * FROM services;",
117
123
  "description": "Services snapshot query.",