@cdxgen/cdxgen 0.0.1 → 13.0.1

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 (722) hide show
  1. package/README.md +921 -87
  2. package/bin/audit.js +239 -0
  3. package/bin/cdxgen.js +2335 -0
  4. package/bin/convert.js +220 -0
  5. package/bin/evinse.js +353 -0
  6. package/bin/hbom.js +504 -0
  7. package/bin/repl.js +2224 -0
  8. package/bin/sign.js +195 -0
  9. package/bin/tracebom.js +303 -0
  10. package/bin/validate.js +268 -0
  11. package/bin/verify.js +189 -0
  12. package/data/README.md +307 -0
  13. package/data/bom-1.4.schema.json +1605 -0
  14. package/data/bom-1.5.schema.json +3660 -0
  15. package/data/bom-1.6.schema.json +5511 -0
  16. package/data/bom-1.7.schema.json +6700 -0
  17. package/data/cbomosdb-queries.json +68 -0
  18. package/data/component-tags.json +339 -0
  19. package/data/container-knowledge-index.json +125 -0
  20. package/data/cosdb-queries.json +17 -0
  21. package/data/crypto-oid.json +1998 -0
  22. package/data/cryptography-defs.json +3793 -0
  23. package/data/cryptography-defs.schema.json +576 -0
  24. package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
  25. package/data/frameworks-list.json +219 -0
  26. package/data/glibc-stdlib.json +117 -0
  27. package/data/gtfobins-index.json +6296 -0
  28. package/data/helpers/init.gradle +71 -0
  29. package/data/jsf-0.82.schema.json +211 -0
  30. package/data/known-licenses.json +82 -0
  31. package/data/lic-mapping.json +338 -0
  32. package/data/license-aliases.json +6624 -0
  33. package/data/license-db.json +39059 -0
  34. package/data/license-deprecations.json +302 -0
  35. package/data/lolbas-index.json +150 -0
  36. package/data/predictive-audit-allowlist.json +11 -0
  37. package/data/pypi-pkg-aliases.json +1199 -0
  38. package/data/python-stdlib.json +308 -0
  39. package/data/queries-darwin.json +193 -0
  40. package/data/queries-win.json +257 -0
  41. package/data/queries.json +268 -0
  42. package/data/ruby-known-modules.json +281 -0
  43. package/data/rules/ai-agent-governance.yaml +323 -0
  44. package/data/rules/ai-bom.yaml +268 -0
  45. package/data/rules/ai-oversight.yaml +186 -0
  46. package/data/rules/ai-provenance.yaml +92 -0
  47. package/data/rules/asar-archives.yaml +150 -0
  48. package/data/rules/cbom-security.yaml +165 -0
  49. package/data/rules/chrome-extensions.yaml +248 -0
  50. package/data/rules/ci-permissions.yaml +802 -0
  51. package/data/rules/container-risk.yaml +353 -0
  52. package/data/rules/dependency-sources.yaml +236 -0
  53. package/data/rules/golem-go.yaml +229 -0
  54. package/data/rules/hbom-compliance.yaml +325 -0
  55. package/data/rules/hbom-performance.yaml +307 -0
  56. package/data/rules/hbom-security.yaml +248 -0
  57. package/data/rules/host-topology.yaml +165 -0
  58. package/data/rules/mcp-servers.yaml +388 -0
  59. package/data/rules/obom-runtime.yaml +1776 -0
  60. package/data/rules/package-integrity.yaml +364 -0
  61. package/data/rules/rootfs-hardening.yaml +179 -0
  62. package/data/rules/vscode-extensions.yaml +237 -0
  63. package/data/spdx-export.schema.json +6794 -0
  64. package/data/spdx-license-list.json +7449 -0
  65. package/data/spdx-licenses.json +759 -0
  66. package/data/spdx.schema.json +819 -0
  67. package/data/templates/README.md +3 -0
  68. package/data/templates/asvs-4.0.3.cdx.json +2943 -0
  69. package/data/templates/asvs-5.0.cdx.json +3046 -0
  70. package/data/templates/bsimm-v13.cdx.json +1008 -0
  71. package/data/templates/masvs-2.0.0.cdx.json +225 -0
  72. package/data/templates/nist-ssdf-1.1.cdx.json +828 -0
  73. package/data/templates/pcissc-secure-slc-1.1.cdx.json +1027 -0
  74. package/data/templates/scvs-1.0.0.cdx.json +813 -0
  75. package/data/templates/ssaf-DRAFT-2023-11.cdx.json +127 -0
  76. package/data/vendor-alias.json +41967 -0
  77. package/data/wrapdb-releases.json +4227 -0
  78. package/index.cjs +15 -0
  79. package/lib/audit/index.js +2800 -0
  80. package/lib/audit/progress.js +114 -0
  81. package/lib/audit/reporters.js +937 -0
  82. package/lib/audit/scoring.js +560 -0
  83. package/lib/audit/targets.js +798 -0
  84. package/lib/cli/bomAssembly.js +1882 -0
  85. package/lib/cli/cliOptions.js +543 -0
  86. package/lib/cli/index.js +2759 -0
  87. package/lib/cli/jsBom.js +2087 -0
  88. package/lib/cli/jvmBom.js +1858 -0
  89. package/lib/cli/managedBom.js +2083 -0
  90. package/lib/cli/nativeBom.js +2125 -0
  91. package/lib/core/activity.js +1087 -0
  92. package/lib/core/env.js +719 -0
  93. package/lib/core/fs.js +1058 -0
  94. package/lib/core/httpClient.js +730 -0
  95. package/lib/core/logger.js +280 -0
  96. package/lib/core/parallel.js +323 -0
  97. package/lib/core/paths.js +70 -0
  98. package/lib/core/projectConfig.js +122 -0
  99. package/lib/core/propertySanitizer.js +174 -0
  100. package/lib/core/spdx.js +5 -0
  101. package/lib/core/state.js +59 -0
  102. package/lib/core/text.js +207 -0
  103. package/lib/core/ui.js +920 -0
  104. package/lib/core/urls.js +84 -0
  105. package/lib/ecosystems/asarutils.js +1636 -0
  106. package/lib/ecosystems/bunutils.js +402 -0
  107. package/lib/ecosystems/caxa.js +77 -0
  108. package/lib/ecosystems/chromextutils.js +1174 -0
  109. package/lib/ecosystems/cmakeResolver.js +587 -0
  110. package/lib/ecosystems/cppEvidence.js +305 -0
  111. package/lib/ecosystems/denoutils.js +1094 -0
  112. package/lib/ecosystems/dotnetutils.js +132 -0
  113. package/lib/ecosystems/ecosystems.js +2772 -0
  114. package/lib/ecosystems/golem.js +1807 -0
  115. package/lib/ecosystems/gradleutils.js +1048 -0
  116. package/lib/ecosystems/jsEvidence.js +317 -0
  117. package/lib/ecosystems/npmutils.js +586 -0
  118. package/lib/ecosystems/parsers-bazel.js +875 -0
  119. package/lib/ecosystems/parsers-dotnet.js +1430 -0
  120. package/lib/ecosystems/parsers-gleam.js +302 -0
  121. package/lib/ecosystems/parsers-go.js +818 -0
  122. package/lib/ecosystems/parsers-js.js +4222 -0
  123. package/lib/ecosystems/parsers-jvm.js +948 -0
  124. package/lib/ecosystems/parsers-misc.js +3191 -0
  125. package/lib/ecosystems/parsers-python.js +2070 -0
  126. package/lib/ecosystems/parsers-rust.js +1294 -0
  127. package/lib/ecosystems/parsers-zig.js +861 -0
  128. package/lib/ecosystems/pep770.js +341 -0
  129. package/lib/ecosystems/pylockutils.js +427 -0
  130. package/lib/ecosystems/pythonutils.js +1281 -0
  131. package/lib/ecosystems/registryProvenance.js +1003 -0
  132. package/lib/ecosystems/remote/huggingface.js +1343 -0
  133. package/lib/ecosystems/rubyutils.js +1629 -0
  134. package/lib/ecosystems/rusi.js +820 -0
  135. package/lib/ecosystems/sbtutils.js +972 -0
  136. package/lib/ecosystems/tea.js +607 -0
  137. package/lib/ecosystems/utils.js +583 -0
  138. package/lib/ecosystems/zigResolver.js +410 -0
  139. package/lib/evinser/db.js +145 -0
  140. package/lib/evinser/evinser.js +2362 -0
  141. package/lib/evinser/scalasem.js +65 -0
  142. package/lib/evinser/swiftsem.js +767 -0
  143. package/lib/helpers/annotationFormatter.js +84 -0
  144. package/lib/helpers/bomSigner.js +312 -0
  145. package/lib/helpers/exportUtils.js +160 -0
  146. package/lib/helpers/remote/dependency-track.js +117 -0
  147. package/lib/helpers/versutils.js +202 -0
  148. package/lib/helpers/vsixutils.js +1069 -0
  149. package/lib/inventory/agentFormulationParser.js +322 -0
  150. package/lib/inventory/aiCollector.js +2140 -0
  151. package/lib/inventory/aiInventory.js +414 -0
  152. package/lib/inventory/aiModelVariants.js +121 -0
  153. package/lib/inventory/aiOversightCollector.js +661 -0
  154. package/lib/inventory/aiProvenanceCollector.js +822 -0
  155. package/lib/inventory/analyzer.js +6089 -0
  156. package/lib/inventory/analyzerScope.js +807 -0
  157. package/lib/inventory/astWorker.js +20 -0
  158. package/lib/inventory/atomUtils.js +1092 -0
  159. package/lib/inventory/auditCategories.js +192 -0
  160. package/lib/inventory/bomUtils.js +369 -0
  161. package/lib/inventory/cacheCommands.js +182 -0
  162. package/lib/inventory/cacheDir.js +104 -0
  163. package/lib/inventory/cbomutils.js +590 -0
  164. package/lib/inventory/cdxrs.js +434 -0
  165. package/lib/inventory/ciParsers/azurePipelines.js +295 -0
  166. package/lib/inventory/ciParsers/circleCi.js +286 -0
  167. package/lib/inventory/ciParsers/common.js +24 -0
  168. package/lib/inventory/ciParsers/githubActions.js +2434 -0
  169. package/lib/inventory/ciParsers/gitlabCi.js +213 -0
  170. package/lib/inventory/ciParsers/jenkins.js +180 -0
  171. package/lib/inventory/citations.js +234 -0
  172. package/lib/inventory/communityAiConfigParser.js +756 -0
  173. package/lib/inventory/containerRisk.js +204 -0
  174. package/lib/inventory/cryptoAlgorithmFamily.js +258 -0
  175. package/lib/inventory/deps.js +807 -0
  176. package/lib/inventory/depsUtils.js +588 -0
  177. package/lib/inventory/display.js +2128 -0
  178. package/lib/inventory/dosai.js +601 -0
  179. package/lib/inventory/dosaiParsers.js +154 -0
  180. package/lib/inventory/dynamic.js +145 -0
  181. package/lib/inventory/envcontext.js +1793 -0
  182. package/lib/inventory/evidenceUtils.js +774 -0
  183. package/lib/inventory/fetchBatch.js +779 -0
  184. package/lib/inventory/fetchRate.js +255 -0
  185. package/lib/inventory/forgeEnricher.js +300 -0
  186. package/lib/inventory/formulationParsers.js +422 -0
  187. package/lib/inventory/gtfobins.js +339 -0
  188. package/lib/inventory/hbom.js +719 -0
  189. package/lib/inventory/hbomAnalysis.js +310 -0
  190. package/lib/inventory/hbomLoader.js +35 -0
  191. package/lib/inventory/hostTopology.js +835 -0
  192. package/lib/inventory/inventoryStats.js +100 -0
  193. package/lib/inventory/jsonLike.js +121 -0
  194. package/lib/inventory/licenseEnhancer.js +918 -0
  195. package/lib/inventory/lolbas.js +285 -0
  196. package/lib/inventory/mcp.js +253 -0
  197. package/lib/inventory/mcpConfigParser.js +683 -0
  198. package/lib/inventory/mcpDiscovery.js +112 -0
  199. package/lib/inventory/mcpPinning.js +209 -0
  200. package/lib/inventory/osPackageResolver.js +493 -0
  201. package/lib/inventory/osinfo.js +383 -0
  202. package/lib/inventory/osqueryTransform.js +274 -0
  203. package/lib/inventory/plugins.js +466 -0
  204. package/lib/inventory/protobom.js +231 -0
  205. package/lib/inventory/protobomLoader.js +43 -0
  206. package/lib/inventory/provenanceUtils.js +224 -0
  207. package/lib/inventory/purl.js +749 -0
  208. package/lib/inventory/rustFormulationParser.js +339 -0
  209. package/lib/inventory/sbomDocument.js +340 -0
  210. package/lib/inventory/source.js +1488 -0
  211. package/lib/inventory/spdx.js +361 -0
  212. package/lib/inventory/spdxExpression.js +512 -0
  213. package/lib/inventory/spdxUtils.js +107 -0
  214. package/lib/inventory/table.js +267 -0
  215. package/lib/inventory/traceRunner.js +439 -0
  216. package/lib/inventory/unicodeScan.js +147 -0
  217. package/lib/managers/binary.js +3459 -0
  218. package/lib/managers/containerutils.js +125 -0
  219. package/lib/managers/docker.js +2145 -0
  220. package/lib/managers/dockerConnection.js +162 -0
  221. package/lib/managers/oci.js +704 -0
  222. package/lib/managers/piptree.js +267 -0
  223. package/lib/parsers/cmakeCache.js +199 -0
  224. package/lib/parsers/gguf.js +492 -0
  225. package/lib/parsers/gitAiNotes.js +233 -0
  226. package/lib/parsers/gitmodules.js +239 -0
  227. package/lib/parsers/htmlExtract.js +610 -0
  228. package/lib/parsers/huggingfaceManifest.js +551 -0
  229. package/lib/parsers/huggingfaceUtils.js +506 -0
  230. package/lib/parsers/iri.js +618 -0
  231. package/lib/parsers/npmrc.js +99 -0
  232. package/lib/parsers/ollama.js +101 -0
  233. package/lib/parsers/xml.js +841 -0
  234. package/lib/server/openapi.yaml +433 -0
  235. package/lib/server/server.js +616 -0
  236. package/lib/stages/postgen/annotator.js +977 -0
  237. package/lib/stages/postgen/auditBom.js +468 -0
  238. package/lib/stages/postgen/postgen.js +1239 -0
  239. package/lib/stages/postgen/ruleEngine.js +731 -0
  240. package/lib/stages/postgen/sortBom.js +195 -0
  241. package/lib/stages/postgen/spdxConverter.js +796 -0
  242. package/lib/stages/postgen/specVersionCompat.js +703 -0
  243. package/lib/stages/pregen/envAudit.js +388 -0
  244. package/lib/stages/pregen/pregen.js +637 -0
  245. package/lib/third-party/README.md +9 -0
  246. package/lib/third-party/arborist/CHANGELOG.md +1109 -0
  247. package/lib/third-party/arborist/LICENSE.md +20 -0
  248. package/lib/third-party/arborist/README.md +315 -0
  249. package/lib/third-party/arborist/lib/arborist/index.js +258 -0
  250. package/lib/third-party/arborist/lib/arborist/load-actual.js +605 -0
  251. package/lib/third-party/arborist/lib/arborist/load-virtual.js +300 -0
  252. package/lib/third-party/arborist/lib/bin-links.js +120 -0
  253. package/lib/third-party/arborist/lib/calc-dep-flags.js +130 -0
  254. package/lib/third-party/arborist/lib/case-insensitive-map.js +51 -0
  255. package/lib/third-party/arborist/lib/consistent-resolve.js +42 -0
  256. package/lib/third-party/arborist/lib/debug.js +50 -0
  257. package/lib/third-party/arborist/lib/dep-valid.js +190 -0
  258. package/lib/third-party/arborist/lib/edge.js +417 -0
  259. package/lib/third-party/arborist/lib/from-path.js +36 -0
  260. package/lib/third-party/arborist/lib/gather-dep-set.js +43 -0
  261. package/lib/third-party/arborist/lib/index.js +22 -0
  262. package/lib/third-party/arborist/lib/inventory.js +138 -0
  263. package/lib/third-party/arborist/lib/link.js +169 -0
  264. package/lib/third-party/arborist/lib/node.js +1673 -0
  265. package/lib/third-party/arborist/lib/npm-extension.js +45 -0
  266. package/lib/third-party/arborist/lib/override-resolves.js +11 -0
  267. package/lib/third-party/arborist/lib/override-set.js +319 -0
  268. package/lib/third-party/arborist/lib/package-extensions.js +289 -0
  269. package/lib/third-party/arborist/lib/printable.js +210 -0
  270. package/lib/third-party/arborist/lib/proc-log.js +30 -0
  271. package/lib/third-party/arborist/lib/realpath.js +100 -0
  272. package/lib/third-party/arborist/lib/relpath.js +4 -0
  273. package/lib/third-party/arborist/lib/shrinkwrap.js +1291 -0
  274. package/lib/third-party/arborist/lib/spec-from-lock.js +34 -0
  275. package/lib/third-party/arborist/lib/tree-check.js +165 -0
  276. package/lib/third-party/arborist/lib/validate-npm-package-name.js +107 -0
  277. package/lib/third-party/arborist/lib/version-from-tgz.js +51 -0
  278. package/lib/third-party/arborist/lib/yarn-lock.js +397 -0
  279. package/lib/validator/bomValidator.js +985 -0
  280. package/lib/validator/complianceEngine.js +241 -0
  281. package/lib/validator/complianceRules.js +1680 -0
  282. package/lib/validator/generated/runtime.mjs +17 -0
  283. package/lib/validator/generated/validate-1.6.mjs +21258 -0
  284. package/lib/validator/generated/validate-1.7.mjs +24803 -0
  285. package/lib/validator/generated/validate-2.0.mjs +22931 -0
  286. package/lib/validator/index.js +246 -0
  287. package/lib/validator/reporters/annotations.js +142 -0
  288. package/lib/validator/reporters/console.js +160 -0
  289. package/lib/validator/reporters/index.js +41 -0
  290. package/lib/validator/reporters/json.js +37 -0
  291. package/lib/validator/reporters/sarif.js +184 -0
  292. package/package.json +209 -26
  293. package/types/bin/audit.d.ts +3 -0
  294. package/types/bin/audit.d.ts.map +1 -0
  295. package/types/bin/cdxgen.d.ts +3 -0
  296. package/types/bin/cdxgen.d.ts.map +1 -0
  297. package/types/bin/convert.d.ts +3 -0
  298. package/types/bin/convert.d.ts.map +1 -0
  299. package/types/bin/evinse.d.ts +3 -0
  300. package/types/bin/evinse.d.ts.map +1 -0
  301. package/types/bin/hbom.d.ts +3 -0
  302. package/types/bin/hbom.d.ts.map +1 -0
  303. package/types/bin/repl.d.ts +3 -0
  304. package/types/bin/repl.d.ts.map +1 -0
  305. package/types/bin/sign.d.ts +3 -0
  306. package/types/bin/sign.d.ts.map +1 -0
  307. package/types/bin/tracebom.d.ts +3 -0
  308. package/types/bin/tracebom.d.ts.map +1 -0
  309. package/types/bin/validate.d.ts +14 -0
  310. package/types/bin/validate.d.ts.map +1 -0
  311. package/types/bin/verify.d.ts +3 -0
  312. package/types/bin/verify.d.ts.map +1 -0
  313. package/types/lib/audit/index.d.ts +153 -0
  314. package/types/lib/audit/index.d.ts.map +1 -0
  315. package/types/lib/audit/progress.d.ts +31 -0
  316. package/types/lib/audit/progress.d.ts.map +1 -0
  317. package/types/lib/audit/reporters.d.ts +62 -0
  318. package/types/lib/audit/reporters.d.ts.map +1 -0
  319. package/types/lib/audit/scoring.d.ts +36 -0
  320. package/types/lib/audit/scoring.d.ts.map +1 -0
  321. package/types/lib/audit/targets.d.ts +77 -0
  322. package/types/lib/audit/targets.d.ts.map +1 -0
  323. package/types/lib/cli/bomAssembly.d.ts +329 -0
  324. package/types/lib/cli/bomAssembly.d.ts.map +1 -0
  325. package/types/lib/cli/cliOptions.d.ts +156 -0
  326. package/types/lib/cli/cliOptions.d.ts.map +1 -0
  327. package/types/lib/cli/index.d.ts +107 -0
  328. package/types/lib/cli/index.d.ts.map +1 -0
  329. package/types/lib/cli/jsBom.d.ts +94 -0
  330. package/types/lib/cli/jsBom.d.ts.map +1 -0
  331. package/types/lib/cli/jvmBom.d.ts +54 -0
  332. package/types/lib/cli/jvmBom.d.ts.map +1 -0
  333. package/types/lib/cli/managedBom.d.ts +105 -0
  334. package/types/lib/cli/managedBom.d.ts.map +1 -0
  335. package/types/lib/cli/nativeBom.d.ts +143 -0
  336. package/types/lib/cli/nativeBom.d.ts.map +1 -0
  337. package/types/lib/core/activity.d.ts +178 -0
  338. package/types/lib/core/activity.d.ts.map +1 -0
  339. package/types/lib/core/env.d.ts +192 -0
  340. package/types/lib/core/env.d.ts.map +1 -0
  341. package/types/lib/core/fs.d.ts +158 -0
  342. package/types/lib/core/fs.d.ts.map +1 -0
  343. package/types/lib/core/httpClient.d.ts +149 -0
  344. package/types/lib/core/httpClient.d.ts.map +1 -0
  345. package/types/lib/core/logger.d.ts +50 -0
  346. package/types/lib/core/logger.d.ts.map +1 -0
  347. package/types/lib/core/parallel.d.ts +95 -0
  348. package/types/lib/core/parallel.d.ts.map +1 -0
  349. package/types/lib/core/paths.d.ts +36 -0
  350. package/types/lib/core/paths.d.ts.map +1 -0
  351. package/types/lib/core/projectConfig.d.ts +23 -0
  352. package/types/lib/core/projectConfig.d.ts.map +1 -0
  353. package/types/lib/core/propertySanitizer.d.ts +23 -0
  354. package/types/lib/core/propertySanitizer.d.ts.map +1 -0
  355. package/types/lib/core/spdx.d.ts +5 -0
  356. package/types/lib/core/spdx.d.ts.map +1 -0
  357. package/types/lib/core/state.d.ts +20 -0
  358. package/types/lib/core/state.d.ts.map +1 -0
  359. package/types/lib/core/text.d.ts +78 -0
  360. package/types/lib/core/text.d.ts.map +1 -0
  361. package/types/lib/core/ui.d.ts +87 -0
  362. package/types/lib/core/ui.d.ts.map +1 -0
  363. package/types/lib/core/urls.d.ts +43 -0
  364. package/types/lib/core/urls.d.ts.map +1 -0
  365. package/types/lib/ecosystems/asarutils.d.ts +71 -0
  366. package/types/lib/ecosystems/asarutils.d.ts.map +1 -0
  367. package/types/lib/ecosystems/bunutils.d.ts +38 -0
  368. package/types/lib/ecosystems/bunutils.d.ts.map +1 -0
  369. package/types/lib/ecosystems/caxa.d.ts +8 -0
  370. package/types/lib/ecosystems/caxa.d.ts.map +1 -0
  371. package/types/lib/ecosystems/chromextutils.d.ts +97 -0
  372. package/types/lib/ecosystems/chromextutils.d.ts.map +1 -0
  373. package/types/lib/ecosystems/cmakeResolver.d.ts +176 -0
  374. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -0
  375. package/types/lib/ecosystems/cppEvidence.d.ts +35 -0
  376. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -0
  377. package/types/lib/ecosystems/denoutils.d.ts +76 -0
  378. package/types/lib/ecosystems/denoutils.d.ts.map +1 -0
  379. package/types/lib/ecosystems/dotnetutils.d.ts +45 -0
  380. package/types/lib/ecosystems/dotnetutils.d.ts.map +1 -0
  381. package/types/lib/ecosystems/ecosystems.d.ts +279 -0
  382. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -0
  383. package/types/lib/ecosystems/golem.d.ts +60 -0
  384. package/types/lib/ecosystems/golem.d.ts.map +1 -0
  385. package/types/lib/ecosystems/gradleutils.d.ts +139 -0
  386. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -0
  387. package/types/lib/ecosystems/jsEvidence.d.ts +17 -0
  388. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -0
  389. package/types/lib/ecosystems/npmutils.d.ts +183 -0
  390. package/types/lib/ecosystems/npmutils.d.ts.map +1 -0
  391. package/types/lib/ecosystems/parsers-bazel.d.ts +36 -0
  392. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -0
  393. package/types/lib/ecosystems/parsers-dotnet.d.ts +116 -0
  394. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -0
  395. package/types/lib/ecosystems/parsers-gleam.d.ts +33 -0
  396. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -0
  397. package/types/lib/ecosystems/parsers-go.d.ts +92 -0
  398. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -0
  399. package/types/lib/ecosystems/parsers-js.d.ts +242 -0
  400. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -0
  401. package/types/lib/ecosystems/parsers-jvm.d.ts +100 -0
  402. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -0
  403. package/types/lib/ecosystems/parsers-misc.d.ts +450 -0
  404. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -0
  405. package/types/lib/ecosystems/parsers-python.d.ts +145 -0
  406. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -0
  407. package/types/lib/ecosystems/parsers-rust.d.ts +56 -0
  408. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -0
  409. package/types/lib/ecosystems/parsers-zig.d.ts +83 -0
  410. package/types/lib/ecosystems/parsers-zig.d.ts.map +1 -0
  411. package/types/lib/ecosystems/pep770.d.ts +38 -0
  412. package/types/lib/ecosystems/pep770.d.ts.map +1 -0
  413. package/types/lib/ecosystems/pylockutils.d.ts +68 -0
  414. package/types/lib/ecosystems/pylockutils.d.ts.map +1 -0
  415. package/types/lib/ecosystems/pythonutils.d.ts +70 -0
  416. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -0
  417. package/types/lib/ecosystems/registryProvenance.d.ts +26 -0
  418. package/types/lib/ecosystems/registryProvenance.d.ts.map +1 -0
  419. package/types/lib/ecosystems/remote/huggingface.d.ts +31 -0
  420. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -0
  421. package/types/lib/ecosystems/rubyutils.d.ts +182 -0
  422. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -0
  423. package/types/lib/ecosystems/rusi.d.ts +40 -0
  424. package/types/lib/ecosystems/rusi.d.ts.map +1 -0
  425. package/types/lib/ecosystems/sbtutils.d.ts +179 -0
  426. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -0
  427. package/types/lib/ecosystems/tea.d.ts +180 -0
  428. package/types/lib/ecosystems/tea.d.ts.map +1 -0
  429. package/types/lib/ecosystems/utils.d.ts +41 -0
  430. package/types/lib/ecosystems/utils.d.ts.map +1 -0
  431. package/types/lib/ecosystems/zigResolver.d.ts +70 -0
  432. package/types/lib/ecosystems/zigResolver.d.ts.map +1 -0
  433. package/types/lib/evinser/db.d.ts +17 -0
  434. package/types/lib/evinser/db.d.ts.map +1 -0
  435. package/types/lib/evinser/evinser.d.ts +354 -0
  436. package/types/lib/evinser/evinser.d.ts.map +1 -0
  437. package/types/lib/evinser/scalasem.d.ts +15 -0
  438. package/types/lib/evinser/scalasem.d.ts.map +1 -0
  439. package/types/lib/evinser/swiftsem.d.ts +103 -0
  440. package/types/lib/evinser/swiftsem.d.ts.map +1 -0
  441. package/types/lib/helpers/annotationFormatter.d.ts +23 -0
  442. package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
  443. package/types/lib/helpers/bomSigner.d.ts +28 -0
  444. package/types/lib/helpers/bomSigner.d.ts.map +1 -0
  445. package/types/lib/helpers/exportUtils.d.ts +52 -0
  446. package/types/lib/helpers/exportUtils.d.ts.map +1 -0
  447. package/types/lib/helpers/remote/dependency-track.d.ts +23 -0
  448. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
  449. package/types/lib/helpers/versutils.d.ts +8 -0
  450. package/types/lib/helpers/versutils.d.ts.map +1 -0
  451. package/types/lib/helpers/vsixutils.d.ts +130 -0
  452. package/types/lib/helpers/vsixutils.d.ts.map +1 -0
  453. package/types/lib/inventory/agentFormulationParser.d.ts +21 -0
  454. package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -0
  455. package/types/lib/inventory/aiCollector.d.ts +61 -0
  456. package/types/lib/inventory/aiCollector.d.ts.map +1 -0
  457. package/types/lib/inventory/aiInventory.d.ts +103 -0
  458. package/types/lib/inventory/aiInventory.d.ts.map +1 -0
  459. package/types/lib/inventory/aiModelVariants.d.ts +31 -0
  460. package/types/lib/inventory/aiModelVariants.d.ts.map +1 -0
  461. package/types/lib/inventory/aiOversightCollector.d.ts +28 -0
  462. package/types/lib/inventory/aiOversightCollector.d.ts.map +1 -0
  463. package/types/lib/inventory/aiProvenanceCollector.d.ts +13 -0
  464. package/types/lib/inventory/aiProvenanceCollector.d.ts.map +1 -0
  465. package/types/lib/inventory/analyzer.d.ts +157 -0
  466. package/types/lib/inventory/analyzer.d.ts.map +1 -0
  467. package/types/lib/inventory/analyzerScope.d.ts +106 -0
  468. package/types/lib/inventory/analyzerScope.d.ts.map +1 -0
  469. package/types/lib/inventory/astWorker.d.ts +9 -0
  470. package/types/lib/inventory/astWorker.d.ts.map +1 -0
  471. package/types/lib/inventory/atomUtils.d.ts +159 -0
  472. package/types/lib/inventory/atomUtils.d.ts.map +1 -0
  473. package/types/lib/inventory/auditCategories.d.ts +80 -0
  474. package/types/lib/inventory/auditCategories.d.ts.map +1 -0
  475. package/types/lib/inventory/bomUtils.d.ts +145 -0
  476. package/types/lib/inventory/bomUtils.d.ts.map +1 -0
  477. package/types/lib/inventory/cacheCommands.d.ts +28 -0
  478. package/types/lib/inventory/cacheCommands.d.ts.map +1 -0
  479. package/types/lib/inventory/cacheDir.d.ts +55 -0
  480. package/types/lib/inventory/cacheDir.d.ts.map +1 -0
  481. package/types/lib/inventory/cbomutils.d.ts +37 -0
  482. package/types/lib/inventory/cbomutils.d.ts.map +1 -0
  483. package/types/lib/inventory/cdxrs.d.ts +90 -0
  484. package/types/lib/inventory/cdxrs.d.ts.map +1 -0
  485. package/types/lib/inventory/ciParsers/azurePipelines.d.ts +27 -0
  486. package/types/lib/inventory/ciParsers/azurePipelines.d.ts.map +1 -0
  487. package/types/lib/inventory/ciParsers/circleCi.d.ts +27 -0
  488. package/types/lib/inventory/ciParsers/circleCi.d.ts.map +1 -0
  489. package/types/lib/inventory/ciParsers/common.d.ts +11 -0
  490. package/types/lib/inventory/ciParsers/common.d.ts.map +1 -0
  491. package/types/lib/inventory/ciParsers/githubActions.d.ts +38 -0
  492. package/types/lib/inventory/ciParsers/githubActions.d.ts.map +1 -0
  493. package/types/lib/inventory/ciParsers/gitlabCi.d.ts +26 -0
  494. package/types/lib/inventory/ciParsers/gitlabCi.d.ts.map +1 -0
  495. package/types/lib/inventory/ciParsers/jenkins.d.ts +26 -0
  496. package/types/lib/inventory/ciParsers/jenkins.d.ts.map +1 -0
  497. package/types/lib/inventory/citations.d.ts +90 -0
  498. package/types/lib/inventory/citations.d.ts.map +1 -0
  499. package/types/lib/inventory/communityAiConfigParser.d.ts +14 -0
  500. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -0
  501. package/types/lib/inventory/containerRisk.d.ts +20 -0
  502. package/types/lib/inventory/containerRisk.d.ts.map +1 -0
  503. package/types/lib/inventory/cryptoAlgorithmFamily.d.ts +37 -0
  504. package/types/lib/inventory/cryptoAlgorithmFamily.d.ts.map +1 -0
  505. package/types/lib/inventory/deps.d.ts +140 -0
  506. package/types/lib/inventory/deps.d.ts.map +1 -0
  507. package/types/lib/inventory/depsUtils.d.ts +74 -0
  508. package/types/lib/inventory/depsUtils.d.ts.map +1 -0
  509. package/types/lib/inventory/display.d.ts +227 -0
  510. package/types/lib/inventory/display.d.ts.map +1 -0
  511. package/types/lib/inventory/dosai.d.ts +130 -0
  512. package/types/lib/inventory/dosai.d.ts.map +1 -0
  513. package/types/lib/inventory/dosaiParsers.d.ts +59 -0
  514. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -0
  515. package/types/lib/inventory/dynamic.d.ts +25 -0
  516. package/types/lib/inventory/dynamic.d.ts.map +1 -0
  517. package/types/lib/inventory/envcontext.d.ts +377 -0
  518. package/types/lib/inventory/envcontext.d.ts.map +1 -0
  519. package/types/lib/inventory/evidenceUtils.d.ts +74 -0
  520. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -0
  521. package/types/lib/inventory/fetchBatch.d.ts +127 -0
  522. package/types/lib/inventory/fetchBatch.d.ts.map +1 -0
  523. package/types/lib/inventory/fetchRate.d.ts +118 -0
  524. package/types/lib/inventory/fetchRate.d.ts.map +1 -0
  525. package/types/lib/inventory/forgeEnricher.d.ts +31 -0
  526. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -0
  527. package/types/lib/inventory/formulationParsers.d.ts +50 -0
  528. package/types/lib/inventory/formulationParsers.d.ts.map +1 -0
  529. package/types/lib/inventory/gtfobins.d.ts +27 -0
  530. package/types/lib/inventory/gtfobins.d.ts.map +1 -0
  531. package/types/lib/inventory/hbom.d.ts +58 -0
  532. package/types/lib/inventory/hbom.d.ts.map +1 -0
  533. package/types/lib/inventory/hbomAnalysis.d.ts +56 -0
  534. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -0
  535. package/types/lib/inventory/hbomLoader.d.ts +7 -0
  536. package/types/lib/inventory/hbomLoader.d.ts.map +1 -0
  537. package/types/lib/inventory/hostTopology.d.ts +47 -0
  538. package/types/lib/inventory/hostTopology.d.ts.map +1 -0
  539. package/types/lib/inventory/inventoryStats.d.ts +42 -0
  540. package/types/lib/inventory/inventoryStats.d.ts.map +1 -0
  541. package/types/lib/inventory/jsonLike.d.ts +23 -0
  542. package/types/lib/inventory/jsonLike.d.ts.map +1 -0
  543. package/types/lib/inventory/licenseEnhancer.d.ts +70 -0
  544. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -0
  545. package/types/lib/inventory/lolbas.d.ts +16 -0
  546. package/types/lib/inventory/lolbas.d.ts.map +1 -0
  547. package/types/lib/inventory/mcp.d.ts +29 -0
  548. package/types/lib/inventory/mcp.d.ts.map +1 -0
  549. package/types/lib/inventory/mcpConfigParser.d.ts +20 -0
  550. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -0
  551. package/types/lib/inventory/mcpDiscovery.d.ts +33 -0
  552. package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -0
  553. package/types/lib/inventory/mcpPinning.d.ts +11 -0
  554. package/types/lib/inventory/mcpPinning.d.ts.map +1 -0
  555. package/types/lib/inventory/osPackageResolver.d.ts +49 -0
  556. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -0
  557. package/types/lib/inventory/osinfo.d.ts +201 -0
  558. package/types/lib/inventory/osinfo.d.ts.map +1 -0
  559. package/types/lib/inventory/osqueryTransform.d.ts +84 -0
  560. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -0
  561. package/types/lib/inventory/plugins.d.ts +58 -0
  562. package/types/lib/inventory/plugins.d.ts.map +1 -0
  563. package/types/lib/inventory/protobom.d.ts +71 -0
  564. package/types/lib/inventory/protobom.d.ts.map +1 -0
  565. package/types/lib/inventory/protobomLoader.d.ts +17 -0
  566. package/types/lib/inventory/protobomLoader.d.ts.map +1 -0
  567. package/types/lib/inventory/provenanceUtils.d.ts +98 -0
  568. package/types/lib/inventory/provenanceUtils.d.ts.map +1 -0
  569. package/types/lib/inventory/purl.d.ts +313 -0
  570. package/types/lib/inventory/purl.d.ts.map +1 -0
  571. package/types/lib/inventory/rustFormulationParser.d.ts +17 -0
  572. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -0
  573. package/types/lib/inventory/sbomDocument.d.ts +59 -0
  574. package/types/lib/inventory/sbomDocument.d.ts.map +1 -0
  575. package/types/lib/inventory/source.d.ts +163 -0
  576. package/types/lib/inventory/source.d.ts.map +1 -0
  577. package/types/lib/inventory/spdx.d.ts +66 -0
  578. package/types/lib/inventory/spdx.d.ts.map +1 -0
  579. package/types/lib/inventory/spdxExpression.d.ts +58 -0
  580. package/types/lib/inventory/spdxExpression.d.ts.map +1 -0
  581. package/types/lib/inventory/spdxUtils.d.ts +12 -0
  582. package/types/lib/inventory/spdxUtils.d.ts.map +1 -0
  583. package/types/lib/inventory/table.d.ts +22 -0
  584. package/types/lib/inventory/table.d.ts.map +1 -0
  585. package/types/lib/inventory/traceRunner.d.ts +80 -0
  586. package/types/lib/inventory/traceRunner.d.ts.map +1 -0
  587. package/types/lib/inventory/unicodeScan.d.ts +46 -0
  588. package/types/lib/inventory/unicodeScan.d.ts.map +1 -0
  589. package/types/lib/managers/binary.d.ts +147 -0
  590. package/types/lib/managers/binary.d.ts.map +1 -0
  591. package/types/lib/managers/containerutils.d.ts +30 -0
  592. package/types/lib/managers/containerutils.d.ts.map +1 -0
  593. package/types/lib/managers/docker.d.ts +157 -0
  594. package/types/lib/managers/docker.d.ts.map +1 -0
  595. package/types/lib/managers/dockerConnection.d.ts +42 -0
  596. package/types/lib/managers/dockerConnection.d.ts.map +1 -0
  597. package/types/lib/managers/oci.d.ts +21 -0
  598. package/types/lib/managers/oci.d.ts.map +1 -0
  599. package/types/lib/managers/piptree.d.ts +13 -0
  600. package/types/lib/managers/piptree.d.ts.map +1 -0
  601. package/types/lib/parsers/cmakeCache.d.ts +70 -0
  602. package/types/lib/parsers/cmakeCache.d.ts.map +1 -0
  603. package/types/lib/parsers/gguf.d.ts +39 -0
  604. package/types/lib/parsers/gguf.d.ts.map +1 -0
  605. package/types/lib/parsers/gitAiNotes.d.ts +15 -0
  606. package/types/lib/parsers/gitAiNotes.d.ts.map +1 -0
  607. package/types/lib/parsers/gitmodules.d.ts +88 -0
  608. package/types/lib/parsers/gitmodules.d.ts.map +1 -0
  609. package/types/lib/parsers/htmlExtract.d.ts +34 -0
  610. package/types/lib/parsers/htmlExtract.d.ts.map +1 -0
  611. package/types/lib/parsers/huggingfaceManifest.d.ts +153 -0
  612. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -0
  613. package/types/lib/parsers/huggingfaceUtils.d.ts +155 -0
  614. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -0
  615. package/types/lib/parsers/iri.d.ts +68 -0
  616. package/types/lib/parsers/iri.d.ts.map +1 -0
  617. package/types/lib/parsers/npmrc.d.ts +33 -0
  618. package/types/lib/parsers/npmrc.d.ts.map +1 -0
  619. package/types/lib/parsers/ollama.d.ts +22 -0
  620. package/types/lib/parsers/ollama.d.ts.map +1 -0
  621. package/types/lib/parsers/xml.d.ts +47 -0
  622. package/types/lib/parsers/xml.d.ts.map +1 -0
  623. package/types/lib/server/server.d.ts +51 -0
  624. package/types/lib/server/server.d.ts.map +1 -0
  625. package/types/lib/stages/postgen/annotator.d.ts +36 -0
  626. package/types/lib/stages/postgen/annotator.d.ts.map +1 -0
  627. package/types/lib/stages/postgen/auditBom.d.ts +92 -0
  628. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
  629. package/types/lib/stages/postgen/postgen.d.ts +59 -0
  630. package/types/lib/stages/postgen/postgen.d.ts.map +1 -0
  631. package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
  632. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
  633. package/types/lib/stages/postgen/sortBom.d.ts +34 -0
  634. package/types/lib/stages/postgen/sortBom.d.ts.map +1 -0
  635. package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
  636. package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
  637. package/types/lib/stages/postgen/specVersionCompat.d.ts +71 -0
  638. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -0
  639. package/types/lib/stages/pregen/envAudit.d.ts +14 -0
  640. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
  641. package/types/lib/stages/pregen/pregen.d.ts +59 -0
  642. package/types/lib/stages/pregen/pregen.d.ts.map +1 -0
  643. package/types/lib/third-party/arborist/lib/arborist/index.d.ts +47 -0
  644. package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -0
  645. package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +4 -0
  646. package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +1 -0
  647. package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +4 -0
  648. package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +1 -0
  649. package/types/lib/third-party/arborist/lib/bin-links.d.ts +18 -0
  650. package/types/lib/third-party/arborist/lib/bin-links.d.ts.map +1 -0
  651. package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts +3 -0
  652. package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts.map +1 -0
  653. package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +9 -0
  654. package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -0
  655. package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts +3 -0
  656. package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts.map +1 -0
  657. package/types/lib/third-party/arborist/lib/debug.d.ts +3 -0
  658. package/types/lib/third-party/arborist/lib/debug.d.ts.map +1 -0
  659. package/types/lib/third-party/arborist/lib/dep-valid.d.ts +3 -0
  660. package/types/lib/third-party/arborist/lib/dep-valid.d.ts.map +1 -0
  661. package/types/lib/third-party/arborist/lib/edge.d.ts +46 -0
  662. package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -0
  663. package/types/lib/third-party/arborist/lib/from-path.d.ts +3 -0
  664. package/types/lib/third-party/arborist/lib/from-path.d.ts.map +1 -0
  665. package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +3 -0
  666. package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -0
  667. package/types/lib/third-party/arborist/lib/index.d.ts +3 -0
  668. package/types/lib/third-party/arborist/lib/index.d.ts.map +1 -0
  669. package/types/lib/third-party/arborist/lib/inventory.d.ts +14 -0
  670. package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -0
  671. package/types/lib/third-party/arborist/lib/link.d.ts +18 -0
  672. package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -0
  673. package/types/lib/third-party/arborist/lib/node.d.ts +112 -0
  674. package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -0
  675. package/types/lib/third-party/arborist/lib/npm-extension.d.ts +18 -0
  676. package/types/lib/third-party/arborist/lib/npm-extension.d.ts.map +1 -0
  677. package/types/lib/third-party/arborist/lib/override-resolves.d.ts +3 -0
  678. package/types/lib/third-party/arborist/lib/override-resolves.d.ts.map +1 -0
  679. package/types/lib/third-party/arborist/lib/override-set.d.ts +27 -0
  680. package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -0
  681. package/types/lib/third-party/arborist/lib/package-extensions.d.ts +36 -0
  682. package/types/lib/third-party/arborist/lib/package-extensions.d.ts.map +1 -0
  683. package/types/lib/third-party/arborist/lib/printable.d.ts +3 -0
  684. package/types/lib/third-party/arborist/lib/printable.d.ts.map +1 -0
  685. package/types/lib/third-party/arborist/lib/proc-log.d.ts +20 -0
  686. package/types/lib/third-party/arborist/lib/proc-log.d.ts.map +1 -0
  687. package/types/lib/third-party/arborist/lib/realpath.d.ts +3 -0
  688. package/types/lib/third-party/arborist/lib/realpath.d.ts.map +1 -0
  689. package/types/lib/third-party/arborist/lib/relpath.d.ts +3 -0
  690. package/types/lib/third-party/arborist/lib/relpath.d.ts.map +1 -0
  691. package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +54 -0
  692. package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -0
  693. package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts +3 -0
  694. package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts.map +1 -0
  695. package/types/lib/third-party/arborist/lib/tree-check.d.ts +3 -0
  696. package/types/lib/third-party/arborist/lib/tree-check.d.ts.map +1 -0
  697. package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts +13 -0
  698. package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts.map +1 -0
  699. package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +6 -0
  700. package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -0
  701. package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +35 -0
  702. package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -0
  703. package/types/lib/validator/bomValidator.d.ts +40 -0
  704. package/types/lib/validator/bomValidator.d.ts.map +1 -0
  705. package/types/lib/validator/complianceEngine.d.ts +72 -0
  706. package/types/lib/validator/complianceEngine.d.ts.map +1 -0
  707. package/types/lib/validator/complianceRules.d.ts +61 -0
  708. package/types/lib/validator/complianceRules.d.ts.map +1 -0
  709. package/types/lib/validator/index.d.ts +101 -0
  710. package/types/lib/validator/index.d.ts.map +1 -0
  711. package/types/lib/validator/reporters/annotations.d.ts +37 -0
  712. package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
  713. package/types/lib/validator/reporters/console.d.ts +34 -0
  714. package/types/lib/validator/reporters/console.d.ts.map +1 -0
  715. package/types/lib/validator/reporters/index.d.ts +30 -0
  716. package/types/lib/validator/reporters/index.d.ts.map +1 -0
  717. package/types/lib/validator/reporters/json.d.ts +11 -0
  718. package/types/lib/validator/reporters/json.d.ts.map +1 -0
  719. package/types/lib/validator/reporters/sarif.d.ts +22 -0
  720. package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
  721. package/mod.d.ts +0 -7
  722. package/mod.js +0 -22
@@ -0,0 +1,2434 @@
1
+ import { randomUUID as uuidv4 } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import path from "node:path";
4
+
5
+ import { build } from "@cdxgen/cdx-purl";
6
+ import { parse as _load } from "yaml";
7
+
8
+ import { scanTextForHiddenUnicode } from "../unicodeScan.js";
9
+ import { disambiguateSteps } from "./common.js";
10
+
11
+ /**
12
+ * Known GitHub Actions permission scopes that grant write access.
13
+ * @type {string[]}
14
+ */
15
+ const WRITE_SCOPES = [
16
+ "actions",
17
+ "artifact-metadata",
18
+ "attestations",
19
+ "checks",
20
+ "contents",
21
+ "deployments",
22
+ "discussions",
23
+ "id-token",
24
+ "issues",
25
+ "models",
26
+ "packages",
27
+ "pages",
28
+ "pull-requests",
29
+ "security-events",
30
+ "statuses",
31
+ ];
32
+
33
+ /**
34
+ * Workflow triggers considered high-risk because they can execute code in a
35
+ * privileged context or expose secrets to untrusted input.
36
+ * @type {string[]}
37
+ */
38
+ const HIGH_RISK_TRIGGERS = [
39
+ "pull_request_target",
40
+ "issue_comment",
41
+ "workflow_run",
42
+ ];
43
+
44
+ const LOW_RISK_INTERPOLATION_PATTERNS = [
45
+ /^github\.sha$/,
46
+ /^github\.event\.pull_request\.(?:head|base)\.sha$/,
47
+ /^github\.event\.workflow_run\.head_sha$/,
48
+ /^github\.event\.pull_request\.number$/,
49
+ /^github\.event\.issue\.number$/,
50
+ /^github\.run_attempt$/,
51
+ /^github\.run_id$/,
52
+ /^github\.run_number$/,
53
+ ];
54
+
55
+ const LEGACY_PUBLISH_TOKEN_ENV_NAMES = new Set([
56
+ "NPM_CONFIG_TOKEN",
57
+ "TWINE_PASSWORD",
58
+ ]);
59
+
60
+ const SECRET_LIKE_ENV_NAME_PATTERN =
61
+ /token|secret|password|credential|auth|api[_-]?key|access[_-]?key|client[_-]?secret/i;
62
+
63
+ const SENSITIVE_ENV_VALUE_PATTERN =
64
+ /secrets\.[A-Za-z0-9_]+|github\.token|ACTIONS_ID_TOKEN_REQUEST_(?:TOKEN|URL)/i;
65
+
66
+ const SHELL_VARIABLE_REFERENCE_PATTERN =
67
+ /\$[A-Za-z_][A-Za-z0-9_]*\b|\$\{[A-Za-z_][A-Za-z0-9_]*}|%[A-Za-z_][A-Za-z0-9_]*%|\$env:[A-Za-z_][A-Za-z0-9_]*\b/i;
68
+
69
+ const IMPLICIT_SENSITIVE_ENV_NAMES = [
70
+ "ACTIONS_ID_TOKEN_REQUEST_TOKEN",
71
+ "ACTIONS_ID_TOKEN_REQUEST_URL",
72
+ "ACTIONS_RUNTIME_TOKEN",
73
+ "GITHUB_TOKEN",
74
+ ];
75
+
76
+ const OUTBOUND_NETWORK_TOOLS = [
77
+ ["curl", /\bcurl\b/i],
78
+ ["wget", /\bwget\b/i],
79
+ ["invoke-webrequest", /\b(?:invoke-webrequest|iwr)\b/i],
80
+ ["invoke-restmethod", /\b(?:invoke-restmethod|irm)\b/i],
81
+ ["nc", /\b(?:nc|ncat|netcat)\b/i],
82
+ ["scp", /\bscp\b/i],
83
+ ["rsync", /\brsync\b/i],
84
+ ["ftp", /\b(?:ftp|sftp)\b/i],
85
+ ];
86
+
87
+ const KNOWN_DISPATCH_ACTIONS = [
88
+ {
89
+ kind: "repository_dispatch",
90
+ mechanism: "repository-dispatch-action",
91
+ pattern: /^peter-evans\/repository-dispatch(?:@|$)/i,
92
+ repoKeys: ["repository"],
93
+ targetKeys: ["event-type"],
94
+ },
95
+ {
96
+ kind: "workflow_dispatch",
97
+ mechanism: "workflow-dispatch-action",
98
+ pattern:
99
+ /^(?:benc-uk\/workflow-dispatch|lasith-kg\/dispatch-workflow|convictional\/trigger-workflow-and-wait-for-workflow)(?:@|$)/i,
100
+ repoKeys: ["repo", "repository"],
101
+ targetKeys: ["workflow", "workflow_id", "event-type", "ref"],
102
+ },
103
+ ];
104
+
105
+ const CARGO_TOOLCHAIN_ACTION_PATTERNS = [
106
+ /^dtolnay\/rust-toolchain(?:@|$)/i,
107
+ /^actions-rs\/toolchain(?:@|$)/i,
108
+ /^moonrepo\/setup-rust(?:@|$)/i,
109
+ ];
110
+
111
+ const CARGO_CACHE_ACTION_PATTERNS = [/^swatinem\/rust-cache(?:@|$)/i];
112
+
113
+ const CARGO_TOOL_INSTALL_ACTION_PATTERNS = [/^taiki-e\/install-action(?:@|$)/i];
114
+
115
+ const DEPENDENCY_CACHE_SETUP_ACTIONS = [
116
+ {
117
+ pattern: /^actions\/setup-node(?:@|$)/i,
118
+ ecosystem: "npm",
119
+ inputNames: ["package-manager-cache", "cache"],
120
+ },
121
+ {
122
+ pattern: /^actions\/setup-python(?:@|$)/i,
123
+ ecosystem: "pypi",
124
+ inputNames: ["cache"],
125
+ },
126
+ {
127
+ pattern: /^actions\/setup-go(?:@|$)/i,
128
+ ecosystem: "go",
129
+ inputNames: ["cache"],
130
+ },
131
+ {
132
+ pattern: /^actions\/setup-java(?:@|$)/i,
133
+ ecosystem: "java",
134
+ inputNames: ["cache"],
135
+ },
136
+ {
137
+ pattern: /^moonrepo\/setup-rust(?:@|$)/i,
138
+ ecosystem: "cargo",
139
+ inputNames: ["cache"],
140
+ },
141
+ ];
142
+
143
+ const FORK_CONTEXT_PATTERNS = [
144
+ [
145
+ "github.event.pull_request.head.repo.fork",
146
+ /github\.event\.pull_request\.head\.repo\.fork/i,
147
+ ],
148
+ [
149
+ "github.event.pull_request.head.repo.full_name",
150
+ /github\.event\.pull_request\.head\.repo\.full_name/i,
151
+ ],
152
+ [
153
+ "github.event.pull_request.head.repo.clone_url",
154
+ /github\.event\.pull_request\.head\.repo\.clone_url/i,
155
+ ],
156
+ [
157
+ "github.event.workflow_run.head_repository.fork",
158
+ /github\.event\.workflow_run\.head_repository\.fork/i,
159
+ ],
160
+ [
161
+ "github.event.workflow_run.head_repository.full_name",
162
+ /github\.event\.workflow_run\.head_repository\.full_name/i,
163
+ ],
164
+ [
165
+ "github.event.pull_request.head.ref",
166
+ /github\.event\.pull_request\.head\.ref/i,
167
+ ],
168
+ ["github.head_ref", /github\.head_ref/i],
169
+ ];
170
+
171
+ const UNTRUSTED_CHECKOUT_CONTEXT_PATTERNS = [
172
+ [
173
+ "github.event.pull_request.head.sha",
174
+ /github\.event\.pull_request\.head\.sha/i,
175
+ ],
176
+ [
177
+ "github.event.pull_request.head.ref",
178
+ /github\.event\.pull_request\.head\.ref/i,
179
+ ],
180
+ [
181
+ "github.event.pull_request.head.label",
182
+ /github\.event\.pull_request\.head\.label/i,
183
+ ],
184
+ ["github.head_ref", /github\.head_ref/i],
185
+ [
186
+ "github.event.workflow_run.head_sha",
187
+ /github\.event\.workflow_run\.head_sha/i,
188
+ ],
189
+ [
190
+ "github.event.workflow_run.head_branch",
191
+ /github\.event\.workflow_run\.head_branch/i,
192
+ ],
193
+ ];
194
+
195
+ /**
196
+ * Analyse a workflow-level or job-level permissions map for any write grants.
197
+ *
198
+ * Accepts the raw `permissions` value from a workflow YAML which can be an
199
+ * object mapping scope names to `"read"` / `"write"`, or the shorthand
200
+ * strings `"write-all"` / `"read-all"`.
201
+ *
202
+ * @param {Object|string|undefined} permissions - The permissions map or shorthand string.
203
+ * @returns {boolean} `true` when at least one scope has write access.
204
+ */
205
+ function analyzePermissions(permissions) {
206
+ if (!permissions) {
207
+ return false;
208
+ }
209
+ if (typeof permissions === "string") {
210
+ return permissions === "write-all";
211
+ }
212
+ if (typeof permissions !== "object") {
213
+ return false;
214
+ }
215
+ for (const scope of WRITE_SCOPES) {
216
+ if (permissions[scope] === "write") {
217
+ return true;
218
+ }
219
+ }
220
+ return false;
221
+ }
222
+
223
+ function extractWriteScopes(permissions) {
224
+ if (!permissions) {
225
+ return [];
226
+ }
227
+ if (typeof permissions === "string") {
228
+ return permissions === "write-all" ? ["all"] : [];
229
+ }
230
+ if (typeof permissions !== "object") {
231
+ return [];
232
+ }
233
+ const scopes = [];
234
+ for (const scope of WRITE_SCOPES) {
235
+ if (permissions[scope] === "write") {
236
+ scopes.push(scope);
237
+ }
238
+ }
239
+ return scopes;
240
+ }
241
+
242
+ function hasIdTokenWritePermission(permissions) {
243
+ if (!permissions) {
244
+ return false;
245
+ }
246
+ if (typeof permissions === "string") {
247
+ return permissions === "write-all";
248
+ }
249
+ if (typeof permissions !== "object") {
250
+ return false;
251
+ }
252
+ return permissions["id-token"] === "write";
253
+ }
254
+
255
+ function getPropertyValueFromProperties(properties, propName) {
256
+ return properties.find((property) => property.name === propName)?.value;
257
+ }
258
+
259
+ function appendSensitiveOperationProperties(properties) {
260
+ const sensitiveOperations = new Set();
261
+ if (
262
+ getPropertyValueFromProperties(
263
+ properties,
264
+ "cdx:github:step:referencesSensitiveContext",
265
+ ) === "true"
266
+ ) {
267
+ sensitiveOperations.add("references-sensitive-context");
268
+ }
269
+ if (
270
+ getPropertyValueFromProperties(
271
+ properties,
272
+ "cdx:github:step:dispatchesWorkflow",
273
+ ) === "true"
274
+ ) {
275
+ sensitiveOperations.add("dispatches-workflow");
276
+ }
277
+ if (
278
+ getPropertyValueFromProperties(
279
+ properties,
280
+ "cdx:github:step:mutatesRunnerState",
281
+ ) === "true"
282
+ ) {
283
+ sensitiveOperations.add("mutates-runner-state");
284
+ }
285
+ if (
286
+ getPropertyValueFromProperties(
287
+ properties,
288
+ "cdx:github:step:usesLegacyPublishToken",
289
+ ) === "true"
290
+ ) {
291
+ sensitiveOperations.add("legacy-publish-token");
292
+ }
293
+ if (
294
+ getPropertyValueFromProperties(
295
+ properties,
296
+ "cdx:github:step:hasOutboundNetworkCommand",
297
+ ) === "true" &&
298
+ getPropertyValueFromProperties(
299
+ properties,
300
+ "cdx:github:step:referencesSensitiveContext",
301
+ ) === "true"
302
+ ) {
303
+ sensitiveOperations.add("outbound-network-with-sensitive-context");
304
+ }
305
+ const actionUses = getPropertyValueFromProperties(
306
+ properties,
307
+ "cdx:github:action:uses",
308
+ );
309
+ const persistCredentials = getPropertyValueFromProperties(
310
+ properties,
311
+ "cdx:github:checkout:persistCredentials",
312
+ );
313
+ if (
314
+ actionUses?.includes("actions/checkout") &&
315
+ persistCredentials !== "false"
316
+ ) {
317
+ sensitiveOperations.add("checkout-persist-credentials");
318
+ }
319
+ if (!sensitiveOperations.size) {
320
+ return;
321
+ }
322
+ properties.push({
323
+ name: "cdx:github:step:hasSensitiveOperations",
324
+ value: "true",
325
+ });
326
+ properties.push({
327
+ name: "cdx:github:step:sensitiveOperations",
328
+ value: Array.from(sensitiveOperations).join(","),
329
+ });
330
+ }
331
+
332
+ function normalizeRunnerLabels(runsOn) {
333
+ if (!runsOn) {
334
+ return [];
335
+ }
336
+ if (Array.isArray(runsOn)) {
337
+ return runsOn.map((label) => String(label).trim()).filter(Boolean);
338
+ }
339
+ if (typeof runsOn === "string") {
340
+ return runsOn
341
+ .split(",")
342
+ .map((label) => label.trim())
343
+ .filter(Boolean);
344
+ }
345
+ if (typeof runsOn === "object") {
346
+ return normalizeRunnerLabels(runsOn.labels);
347
+ }
348
+ return [];
349
+ }
350
+
351
+ function normalizeRunnerValue(runsOn) {
352
+ const labels = normalizeRunnerLabels(runsOn);
353
+ if (runsOn && typeof runsOn === "object" && !Array.isArray(runsOn)) {
354
+ const group = runsOn.group ? String(runsOn.group).trim() : "";
355
+ return [group, ...labels].filter(Boolean).join(",") || "unknown";
356
+ }
357
+ return labels.join(",") || "unknown";
358
+ }
359
+
360
+ function isSelfHostedRunner(runsOn) {
361
+ return normalizeRunnerLabels(runsOn).some((label) =>
362
+ label.toLowerCase().includes("self-hosted"),
363
+ );
364
+ }
365
+
366
+ /**
367
+ * Detect if a step uses `actions/checkout` and extract the
368
+ * `persist-credentials` setting (defaults to `true` when absent).
369
+ *
370
+ * @param {Object} step - A single workflow step object.
371
+ * @returns {Array<{name: string, value: string}>} Property entries to append.
372
+ */
373
+ function analyzeCheckoutStep(step) {
374
+ const props = [];
375
+ if (step.uses?.includes("actions/checkout")) {
376
+ const persistCreds = step.with?.["persist-credentials"] ?? true;
377
+ const checkoutRef = step.with?.ref;
378
+ const checkoutRepository = step.with?.repository;
379
+ props.push({
380
+ name: "cdx:github:checkout:persistCredentials",
381
+ value: String(persistCreds),
382
+ });
383
+ if (checkoutRef) {
384
+ props.push({ name: "cdx:github:checkout:ref", value: checkoutRef });
385
+ }
386
+ if (checkoutRepository) {
387
+ props.push({
388
+ name: "cdx:github:checkout:repository",
389
+ value: checkoutRepository,
390
+ });
391
+ }
392
+ const untrustedCheckoutContexts = [
393
+ ...detectCheckoutUntrustedContexts(checkoutRef),
394
+ ...detectCheckoutUntrustedContexts(checkoutRepository),
395
+ ];
396
+ if (untrustedCheckoutContexts.length) {
397
+ props.push({
398
+ name: "cdx:github:checkout:checksOutUntrustedRef",
399
+ value: "true",
400
+ });
401
+ props.push({
402
+ name: "cdx:github:checkout:untrustedRefContexts",
403
+ value: [...new Set(untrustedCheckoutContexts)].join(","),
404
+ });
405
+ }
406
+ const forkContextRefs = [
407
+ ...detectForkContextReferences(checkoutRef),
408
+ ...detectForkContextReferences(checkoutRepository),
409
+ ];
410
+ if (forkContextRefs.length) {
411
+ props.push({
412
+ name: "cdx:github:checkout:referencesForkContext",
413
+ value: "true",
414
+ });
415
+ props.push({
416
+ name: "cdx:github:checkout:forkContextRefs",
417
+ value: [...new Set(forkContextRefs)].join(","),
418
+ });
419
+ }
420
+ }
421
+ return props;
422
+ }
423
+
424
+ function detectCheckoutUntrustedContexts(textValue) {
425
+ if (!textValue || typeof textValue !== "string") {
426
+ return [];
427
+ }
428
+ const refs = [];
429
+ UNTRUSTED_CHECKOUT_CONTEXT_PATTERNS.forEach(([name, pattern]) => {
430
+ if (pattern.test(textValue)) {
431
+ refs.push(name);
432
+ }
433
+ });
434
+ return refs;
435
+ }
436
+
437
+ /**
438
+ * Detect `actions/cache` usage and extract key, path, and restore-keys
439
+ * metadata from the step's `with` block.
440
+ *
441
+ * @param {Object} step - A single workflow step object.
442
+ * @returns {Array<{name: string, value: string}>} Property entries to append.
443
+ */
444
+ function analyzeCacheStep(step) {
445
+ const props = [];
446
+ if (step.uses?.includes("actions/cache")) {
447
+ const cacheKey = step.with?.key;
448
+ if (step.with?.key) {
449
+ props.push({ name: "cdx:github:cache:key", value: cacheKey });
450
+ if (/hashFiles\s*\(/i.test(cacheKey)) {
451
+ props.push({
452
+ name: "cdx:github:cache:keyUsesHashFiles",
453
+ value: "true",
454
+ });
455
+ }
456
+ }
457
+ if (step.with?.path) {
458
+ props.push({ name: "cdx:github:cache:path", value: step.with.path });
459
+ }
460
+ if (step.with?.["restore-keys"]) {
461
+ let keys = step.with["restore-keys"];
462
+ if (Array.isArray(keys)) {
463
+ keys = keys.join(",");
464
+ } else if (typeof keys === "string" && keys.includes("\n")) {
465
+ keys = keys
466
+ .split("\n")
467
+ .map((k) => k.trim())
468
+ .filter((k) => k)
469
+ .join(",");
470
+ }
471
+ props.push({ name: "cdx:github:cache:restoreKeys", value: keys });
472
+ props.push({ name: "cdx:github:cache:hasRestoreKeys", value: "true" });
473
+ }
474
+ }
475
+ return props;
476
+ }
477
+
478
+ function analyzeCargoActionStep(step) {
479
+ const props = [];
480
+ if (!step?.uses || typeof step.uses !== "string") {
481
+ return props;
482
+ }
483
+ const cargoRoles = new Set();
484
+ if (
485
+ CARGO_TOOLCHAIN_ACTION_PATTERNS.some((pattern) => pattern.test(step.uses))
486
+ ) {
487
+ cargoRoles.add("toolchain");
488
+ }
489
+ if (CARGO_CACHE_ACTION_PATTERNS.some((pattern) => pattern.test(step.uses))) {
490
+ cargoRoles.add("cache");
491
+ }
492
+ if (
493
+ CARGO_TOOL_INSTALL_ACTION_PATTERNS.some((pattern) =>
494
+ pattern.test(step.uses),
495
+ )
496
+ ) {
497
+ cargoRoles.add("tool-install");
498
+ }
499
+ if (
500
+ step.uses.includes("actions/cache") &&
501
+ typeof step.with?.path === "string" &&
502
+ /(?:^|[\\/])\.cargo(?:[\\/]|$)|cargo[\\/](?:registry|git)/i.test(
503
+ step.with.path,
504
+ )
505
+ ) {
506
+ cargoRoles.add("cache");
507
+ }
508
+ if (!cargoRoles.size) {
509
+ return props;
510
+ }
511
+ props.push({
512
+ name: "cdx:github:action:ecosystem",
513
+ value: "cargo",
514
+ });
515
+ props.push({
516
+ name: "cdx:github:action:role",
517
+ value: [...cargoRoles].join(","),
518
+ });
519
+ return props;
520
+ }
521
+
522
+ function isExplicitFalseLikeValue(value) {
523
+ if (value === false) {
524
+ return true;
525
+ }
526
+ if (typeof value !== "string") {
527
+ return false;
528
+ }
529
+ return ["0", "false", "no", "off", "disabled"].includes(
530
+ value.trim().toLowerCase(),
531
+ );
532
+ }
533
+
534
+ function analyzeSetupActionCacheStep(step) {
535
+ const props = [];
536
+ if (!step?.uses || typeof step.uses !== "string") {
537
+ return props;
538
+ }
539
+ const setupAction = DEPENDENCY_CACHE_SETUP_ACTIONS.find((candidate) =>
540
+ candidate.pattern.test(step.uses),
541
+ );
542
+ if (!setupAction || !step.with || typeof step.with !== "object") {
543
+ return props;
544
+ }
545
+ const disableInputName = setupAction.inputNames.find(
546
+ (inputName) =>
547
+ Object.hasOwn(step.with, inputName) &&
548
+ isExplicitFalseLikeValue(step.with[inputName]),
549
+ );
550
+ if (!disableInputName) {
551
+ return props;
552
+ }
553
+ props.push({
554
+ name: "cdx:github:action:disablesBuildCache",
555
+ value: "true",
556
+ });
557
+ props.push({
558
+ name: "cdx:github:action:buildCacheEcosystem",
559
+ value: setupAction.ecosystem,
560
+ });
561
+ props.push({
562
+ name: "cdx:github:action:buildCacheDisableInput",
563
+ value: disableInputName,
564
+ });
565
+ props.push({
566
+ name: "cdx:github:action:buildCacheDisableValue",
567
+ value: String(step.with[disableInputName]),
568
+ });
569
+ return props;
570
+ }
571
+
572
+ function analyzeCargoRunStep(normalizedRun) {
573
+ const props = [];
574
+ if (!normalizedRun || typeof normalizedRun !== "string") {
575
+ return props;
576
+ }
577
+ const cargoSubcommands = new Set();
578
+ for (const match of normalizedRun.matchAll(/\bcargo\s+([a-z][\w-]*)/gi)) {
579
+ if (match[1]) {
580
+ cargoSubcommands.add(match[1].toLowerCase());
581
+ }
582
+ }
583
+ if (!cargoSubcommands.size) {
584
+ return props;
585
+ }
586
+ props.push({
587
+ name: "cdx:github:step:usesCargo",
588
+ value: "true",
589
+ });
590
+ props.push({
591
+ name: "cdx:github:step:cargoSubcommands",
592
+ value: [...cargoSubcommands].join(","),
593
+ });
594
+ if (/\s--workspace\b|\s--all\b|\s--all-targets\b/i.test(normalizedRun)) {
595
+ props.push({
596
+ name: "cdx:github:step:cargoWorkspaceScope",
597
+ value: "true",
598
+ });
599
+ }
600
+ return props;
601
+ }
602
+
603
+ /**
604
+ * Detect untrusted expression interpolation in `run:` blocks.
605
+ *
606
+ * Scans the raw shell string for `${{ … }}` patterns and flags any that
607
+ * reference user-controlled contexts such as `github.event.pull_request.*`,
608
+ * `github.event.issue.*`, `github.event.comment.*`, `github.head_ref`, or
609
+ * `inputs.*`.
610
+ *
611
+ * @param {string|undefined} runValue - The raw `run:` block string.
612
+ * @returns {{ hasInterpolation: boolean, vars: string[] }}
613
+ */
614
+ function detectUntrustedInterpolation(runValue) {
615
+ if (!runValue) return { hasInterpolation: false, vars: [] };
616
+ // Capture expression content inside ${{ … }}, allowing nested single braces
617
+ // (e.g. the || operator in `${{ a || b }}` where } appears inside the expr).
618
+ const pattern = /\$\{\{\s*([^}]+(?:}[^}])*)}}/g;
619
+ const matches = [...runValue.matchAll(pattern)];
620
+ const untrustedVars = new Set();
621
+
622
+ for (const match of matches) {
623
+ const expr = match[1].trim();
624
+ if (LOW_RISK_INTERPOLATION_PATTERNS.some((pattern) => pattern.test(expr))) {
625
+ continue;
626
+ }
627
+ if (
628
+ expr.startsWith("github.event.pull_request.title") ||
629
+ expr.startsWith("github.event.pull_request.body") ||
630
+ expr.startsWith("github.event.pull_request.head.ref") ||
631
+ expr.startsWith("github.event.pull_request.head.label") ||
632
+ expr.startsWith("github.event.issue.title") ||
633
+ expr.startsWith("github.event.issue.body") ||
634
+ expr.startsWith("github.event.comment.body") ||
635
+ expr.startsWith("github.event.review.body") ||
636
+ expr.startsWith("github.event.review_comment.body") ||
637
+ expr.startsWith("github.head_ref") ||
638
+ expr.startsWith("inputs.")
639
+ ) {
640
+ untrustedVars.add(expr);
641
+ }
642
+ }
643
+
644
+ return {
645
+ hasInterpolation: untrustedVars.size > 0,
646
+ vars: Array.from(untrustedVars),
647
+ };
648
+ }
649
+
650
+ function isLegacyPublishTokenEnvName(envName) {
651
+ if (!envName || typeof envName !== "string") {
652
+ return false;
653
+ }
654
+ return (
655
+ envName.endsWith("_TOKEN") ||
656
+ envName.startsWith("POETRY_PYPI_TOKEN") ||
657
+ LEGACY_PUBLISH_TOKEN_ENV_NAMES.has(envName)
658
+ );
659
+ }
660
+
661
+ function detectPublishEcosystem(runValue) {
662
+ if (!runValue || typeof runValue !== "string") {
663
+ return undefined;
664
+ }
665
+ if (/\b(?:npm|pnpm|yarn|bun)\s+publish\b/i.test(runValue)) {
666
+ return "npm";
667
+ }
668
+ if (
669
+ /\btwine\s+upload\b/i.test(runValue) ||
670
+ /\bpoetry\s+publish\b/i.test(runValue) ||
671
+ /\bflit\s+publish\b/i.test(runValue)
672
+ ) {
673
+ return "pypi";
674
+ }
675
+ return undefined;
676
+ }
677
+
678
+ function normalizeRunValueEntry(entry) {
679
+ if (
680
+ typeof entry === "string" ||
681
+ typeof entry === "number" ||
682
+ typeof entry === "boolean"
683
+ ) {
684
+ return String(entry);
685
+ }
686
+ return "";
687
+ }
688
+
689
+ function normalizeRunValue(runValue) {
690
+ if (typeof runValue === "string") {
691
+ return runValue;
692
+ }
693
+ if (typeof runValue === "number" || typeof runValue === "boolean") {
694
+ return String(runValue);
695
+ }
696
+ if (Array.isArray(runValue)) {
697
+ const normalizedEntries = runValue
698
+ .map((entry) => normalizeRunValueEntry(entry))
699
+ .filter(Boolean);
700
+ return normalizedEntries.length ? normalizedEntries.join("\n") : undefined;
701
+ }
702
+ return undefined;
703
+ }
704
+
705
+ function analyzeLegacyPublishStep(step, effectiveEnv) {
706
+ const props = [];
707
+ const normalizedRun = normalizeRunValue(step?.run);
708
+ const publishEcosystem = detectPublishEcosystem(normalizedRun);
709
+ if (!publishEcosystem) {
710
+ return props;
711
+ }
712
+ const tokenSources = [];
713
+ if (normalizedRun && /\B--token(?:=|\s+\S+)/i.test(normalizedRun)) {
714
+ tokenSources.push("cli-flag");
715
+ }
716
+ const legacyEnvNames = Object.keys(effectiveEnv || {}).filter(
717
+ isLegacyPublishTokenEnvName,
718
+ );
719
+ legacyEnvNames.forEach((envName) => {
720
+ tokenSources.push(`env:${envName}`);
721
+ });
722
+ props.push({
723
+ name: "cdx:github:step:isPublishCommand",
724
+ value: "true",
725
+ });
726
+ props.push({
727
+ name: "cdx:github:step:publishEcosystem",
728
+ value: publishEcosystem,
729
+ });
730
+ if (!tokenSources.length) {
731
+ return props;
732
+ }
733
+ props.push({
734
+ name: "cdx:github:step:usesLegacyPublishToken",
735
+ value: "true",
736
+ });
737
+ props.push({
738
+ name: "cdx:github:step:legacyPublishTokenSources",
739
+ value: tokenSources.join(","),
740
+ });
741
+ return props;
742
+ }
743
+
744
+ function detectRunnerStateMutation(runValue) {
745
+ if (!runValue || typeof runValue !== "string") {
746
+ return { hasMutation: false, targets: [] };
747
+ }
748
+ const targets = new Set();
749
+ const patterns = [
750
+ [
751
+ "GITHUB_ENV",
752
+ /(?:>>?|1>>?)\s*["']?(?:\$GITHUB_ENV|\$\{GITHUB_ENV}|%GITHUB_ENV%|\$env:GITHUB_ENV)["']?/i,
753
+ ],
754
+ [
755
+ "GITHUB_PATH",
756
+ /(?:>>?|1>>?)\s*["']?(?:\$GITHUB_PATH|\$\{GITHUB_PATH}|%GITHUB_PATH%|\$env:GITHUB_PATH)["']?/i,
757
+ ],
758
+ [
759
+ "GITHUB_OUTPUT",
760
+ /(?:>>?|1>>?)\s*["']?(?:\$GITHUB_OUTPUT|\$\{GITHUB_OUTPUT}|%GITHUB_OUTPUT%|\$env:GITHUB_OUTPUT)["']?/i,
761
+ ],
762
+ ];
763
+ patterns.forEach(([target, pattern]) => {
764
+ if (pattern.test(runValue)) {
765
+ targets.add(target);
766
+ }
767
+ });
768
+ if (/::set-output\b/i.test(runValue)) {
769
+ targets.add("GITHUB_OUTPUT");
770
+ }
771
+ return {
772
+ hasMutation: targets.size > 0,
773
+ targets: Array.from(targets),
774
+ };
775
+ }
776
+
777
+ function detectOutboundNetworkCommand(runValue) {
778
+ if (!runValue || typeof runValue !== "string") {
779
+ return { hasOutboundCommand: false, tools: [] };
780
+ }
781
+ const tools = [];
782
+ OUTBOUND_NETWORK_TOOLS.forEach(([name, pattern]) => {
783
+ if (pattern.test(runValue)) {
784
+ tools.push(name);
785
+ }
786
+ });
787
+ return {
788
+ hasOutboundCommand: tools.length > 0,
789
+ tools,
790
+ };
791
+ }
792
+
793
+ function collectSensitiveEnvBindings(effectiveEnv) {
794
+ const sensitiveRefs = [];
795
+ Object.entries(effectiveEnv || {}).forEach(([envName, envValue]) => {
796
+ if (isSensitiveEnvBinding(envName, envValue)) {
797
+ sensitiveRefs.push(`env:${envName}`);
798
+ }
799
+ });
800
+ return sensitiveRefs;
801
+ }
802
+
803
+ function isSensitiveEnvBinding(envName, envValue) {
804
+ if (!envName || typeof envName !== "string") {
805
+ return false;
806
+ }
807
+ if (IMPLICIT_SENSITIVE_ENV_NAMES.includes(envName)) {
808
+ return true;
809
+ }
810
+ if (SECRET_LIKE_ENV_NAME_PATTERN.test(envName)) {
811
+ return true;
812
+ }
813
+ if (typeof envValue !== "string") {
814
+ return false;
815
+ }
816
+ return SENSITIVE_ENV_VALUE_PATTERN.test(envValue);
817
+ }
818
+
819
+ function detectSensitiveContextReferences(runValue, effectiveEnv) {
820
+ if (!runValue || typeof runValue !== "string") {
821
+ return [];
822
+ }
823
+ const sensitiveRefs = new Set();
824
+ Object.entries(effectiveEnv || {}).forEach(([envName, envValue]) => {
825
+ if (!isSensitiveEnvBinding(envName, envValue)) {
826
+ return;
827
+ }
828
+ const envPattern = new RegExp(
829
+ `(?:\\$${envName}\\b|\\$\\{${envName}\\}|%${envName}%|\\$env:${envName}\\b|process\\.env\\.${envName}\\b|process\\.env\\[['"]${envName}['"]])`,
830
+ "i",
831
+ );
832
+ if (envPattern.test(runValue)) {
833
+ sensitiveRefs.add(`env:${envName}`);
834
+ }
835
+ });
836
+ const contextPatterns = [
837
+ ["context:github.token", /github\.token/i],
838
+ ["context:secrets", /secrets\.[A-Za-z0-9_]+/i],
839
+ [
840
+ "context:github-token-input",
841
+ /github-token|process\.env\.GITHUB_TOKEN|process\.env\[['"]GITHUB_TOKEN['"]]/i,
842
+ ],
843
+ [
844
+ "context:actions-id-token",
845
+ /ACTIONS_ID_TOKEN_REQUEST_(?:TOKEN|URL)|id-token/i,
846
+ ],
847
+ ];
848
+ contextPatterns.forEach(([name, pattern]) => {
849
+ if (pattern.test(runValue)) {
850
+ sensitiveRefs.add(name);
851
+ }
852
+ });
853
+ return Array.from(sensitiveRefs);
854
+ }
855
+
856
+ function detectOutboundExfiltrationIndicators(runValue, sensitiveContextRefs) {
857
+ if (
858
+ !runValue ||
859
+ typeof runValue !== "string" ||
860
+ !Array.isArray(sensitiveContextRefs) ||
861
+ !sensitiveContextRefs.length
862
+ ) {
863
+ return [];
864
+ }
865
+ const indicators = new Set();
866
+ if (
867
+ /(?:^|\s)(?:--header|-H)\s+[^\n]*(?:authorization|x-(?:api-key|auth-token|github-token)|private-token|token:)/i.test(
868
+ runValue,
869
+ ) &&
870
+ SHELL_VARIABLE_REFERENCE_PATTERN.test(runValue)
871
+ ) {
872
+ indicators.add("auth-header");
873
+ }
874
+ if (
875
+ /\b(?:--data(?:-raw|-binary|-urlencode)?|--body|--form|--upload-file|-InFile|-Body|-Form)\b|(?:^|\s)-[dFT]\b/i.test(
876
+ runValue,
877
+ )
878
+ ) {
879
+ indicators.add("request-payload");
880
+ }
881
+ if (
882
+ /(?:^|\s)(?:-X|--request)\s*(?:POST|PUT|PATCH)\b|\b-Method\s+(?:Post|Put|Patch)\b/i.test(
883
+ runValue,
884
+ )
885
+ ) {
886
+ indicators.add("state-changing-method");
887
+ }
888
+ if (
889
+ /\?[^\n"'\s]*(?:token|sig|signature|auth|secret|key)=/i.test(runValue) &&
890
+ SHELL_VARIABLE_REFERENCE_PATTERN.test(runValue)
891
+ ) {
892
+ indicators.add("query-parameter");
893
+ }
894
+ if (/\b(?:scp|rsync)\b/i.test(runValue)) {
895
+ indicators.add("file-transfer");
896
+ }
897
+ if (
898
+ /\b(?:nc|ncat|netcat)\b[^\n]*(?:<|<<)/i.test(runValue) ||
899
+ /\|\s*(?:nc|ncat|netcat)\b/i.test(runValue)
900
+ ) {
901
+ indicators.add("stream-transfer");
902
+ }
903
+ if (
904
+ /\b(?:base64|openssl\s+enc)\b[^\n|]*\|\s*(?:curl|wget|nc|ncat|netcat)\b/i.test(
905
+ runValue,
906
+ )
907
+ ) {
908
+ indicators.add("encoded-payload");
909
+ }
910
+ if (
911
+ sensitiveContextRefs.some(
912
+ (ref) =>
913
+ ref === "context:actions-id-token" ||
914
+ ref === "context:github.token" ||
915
+ ref.startsWith("context:secrets"),
916
+ )
917
+ ) {
918
+ indicators.add("platform-credential");
919
+ }
920
+ return Array.from(indicators);
921
+ }
922
+
923
+ function detectForkContextReferences(textValue) {
924
+ if (!textValue || typeof textValue !== "string") {
925
+ return [];
926
+ }
927
+ const refs = [];
928
+ FORK_CONTEXT_PATTERNS.forEach(([name, pattern]) => {
929
+ if (pattern.test(textValue)) {
930
+ refs.push(name);
931
+ }
932
+ });
933
+ return refs;
934
+ }
935
+
936
+ function addDispatchTarget(targets, prefix, value) {
937
+ if (!value || typeof value !== "string") {
938
+ return;
939
+ }
940
+ const normalizedValue = value.trim();
941
+ if (!normalizedValue) {
942
+ return;
943
+ }
944
+ targets.add(`${prefix}:${normalizedValue}`);
945
+ }
946
+
947
+ function normalizeDispatchTargetPrefix(key) {
948
+ if (!key) {
949
+ return "unknown";
950
+ }
951
+ if (["repository", "repo"].includes(key)) {
952
+ return "repo";
953
+ }
954
+ if (["workflow", "workflow_id"].includes(key)) {
955
+ return "workflow";
956
+ }
957
+ if (key === "event-type") {
958
+ return "event";
959
+ }
960
+ return key.replace(/_/g, "-");
961
+ }
962
+
963
+ function detectWorkflowDispatchInvocations(textValue) {
964
+ const kinds = new Set();
965
+ const mechanisms = new Set();
966
+ const targets = new Set();
967
+ if (!textValue || typeof textValue !== "string") {
968
+ return {
969
+ hasDispatch: false,
970
+ kinds: [],
971
+ mechanisms: [],
972
+ targets: [],
973
+ usesExplicitRepositoryTarget: false,
974
+ };
975
+ }
976
+ const ghWorkflowRunMatch = textValue.match(
977
+ /\bgh\s+workflow\s+run\s+([^\s"'`]+)/i,
978
+ );
979
+ if (ghWorkflowRunMatch) {
980
+ kinds.add("workflow_dispatch");
981
+ mechanisms.add("gh-workflow-run");
982
+ addDispatchTarget(targets, "workflow", ghWorkflowRunMatch[1]);
983
+ }
984
+ const ghRepoMatch = textValue.match(
985
+ /\b--repo\s+([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)/i,
986
+ );
987
+ if (ghRepoMatch) {
988
+ addDispatchTarget(targets, "repo", ghRepoMatch[1]);
989
+ }
990
+ for (const match of textValue.matchAll(
991
+ /\/repos\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)\/actions\/workflows\/([^/\s"'`]+)\/dispatches\b/gi,
992
+ )) {
993
+ kinds.add("workflow_dispatch");
994
+ mechanisms.add("github-api-workflow-dispatch");
995
+ addDispatchTarget(targets, "repo", match[1]);
996
+ addDispatchTarget(targets, "workflow", match[2]);
997
+ }
998
+ for (const match of textValue.matchAll(
999
+ /\/repos\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)\/dispatches\b/gi,
1000
+ )) {
1001
+ kinds.add("repository_dispatch");
1002
+ mechanisms.add("github-api-repository-dispatch");
1003
+ addDispatchTarget(targets, "repo", match[1]);
1004
+ }
1005
+ if (
1006
+ /\b(?:github|octokit)\.rest\.actions\.createWorkflowDispatch\b/i.test(
1007
+ textValue,
1008
+ )
1009
+ ) {
1010
+ kinds.add("workflow_dispatch");
1011
+ mechanisms.add("github-script-workflow-dispatch");
1012
+ }
1013
+ if (
1014
+ /\b(?:github|octokit)\.rest\.repos\.createDispatchEvent\b/i.test(textValue)
1015
+ ) {
1016
+ kinds.add("repository_dispatch");
1017
+ mechanisms.add("github-script-repository-dispatch");
1018
+ }
1019
+ if (
1020
+ /\b(?:github|octokit)\.request\s*\(\s*["'`](?:POST\s+)?\/repos\/\{owner}\/\{repo}\/actions\/workflows\/\{workflow_id}\/dispatches/i.test(
1021
+ textValue,
1022
+ )
1023
+ ) {
1024
+ kinds.add("workflow_dispatch");
1025
+ mechanisms.add("octokit-request-workflow-dispatch");
1026
+ }
1027
+ if (
1028
+ /\b(?:github|octokit)\.request\s*\(\s*["'`](?:POST\s+)?\/repos\/\{owner}\/\{repo}\/dispatches/i.test(
1029
+ textValue,
1030
+ )
1031
+ ) {
1032
+ kinds.add("repository_dispatch");
1033
+ mechanisms.add("octokit-request-repository-dispatch");
1034
+ }
1035
+ const ownerMatch = textValue.match(/\bowner\s*:\s*["'`]([^"'`]+)["'`]/i);
1036
+ const repoMatch = textValue.match(/\brepo\s*:\s*["'`]([^"'`]+)["'`]/i);
1037
+ const workflowMatch = textValue.match(
1038
+ /\bworkflow(?:_id)?\s*:\s*["'`]([^"'`]+)["'`]/i,
1039
+ );
1040
+ const eventTypeMatch = textValue.match(
1041
+ /\bevent_type\s*:\s*["'`]([^"'`]+)["'`]/i,
1042
+ );
1043
+ const refMatch = textValue.match(/\bref\s*:\s*["'`]([^"'`]+)["'`]/i);
1044
+ if (ownerMatch && repoMatch) {
1045
+ addDispatchTarget(targets, "repo", `${ownerMatch[1]}/${repoMatch[1]}`);
1046
+ }
1047
+ if (workflowMatch) {
1048
+ addDispatchTarget(targets, "workflow", workflowMatch[1]);
1049
+ }
1050
+ if (eventTypeMatch) {
1051
+ addDispatchTarget(targets, "event", eventTypeMatch[1]);
1052
+ }
1053
+ if (refMatch) {
1054
+ addDispatchTarget(targets, "ref", refMatch[1]);
1055
+ }
1056
+ const targetList = Array.from(targets);
1057
+ return {
1058
+ hasDispatch: kinds.size > 0,
1059
+ kinds: Array.from(kinds),
1060
+ mechanisms: Array.from(mechanisms),
1061
+ targets: targetList,
1062
+ usesExplicitRepositoryTarget: targetList.some((target) =>
1063
+ target.startsWith("repo:"),
1064
+ ),
1065
+ };
1066
+ }
1067
+
1068
+ function analyzeDispatchActionStep(step) {
1069
+ const props = [];
1070
+ if (!step?.uses || typeof step.uses !== "string") {
1071
+ return props;
1072
+ }
1073
+ const dispatchAction = KNOWN_DISPATCH_ACTIONS.find((candidate) =>
1074
+ candidate.pattern.test(step.uses),
1075
+ );
1076
+ if (!dispatchAction) {
1077
+ return props;
1078
+ }
1079
+ const targets = new Set();
1080
+ dispatchAction.repoKeys.forEach((key) => {
1081
+ addDispatchTarget(
1082
+ targets,
1083
+ normalizeDispatchTargetPrefix(key),
1084
+ step.with?.[key],
1085
+ );
1086
+ });
1087
+ dispatchAction.targetKeys.forEach((key) => {
1088
+ addDispatchTarget(
1089
+ targets,
1090
+ normalizeDispatchTargetPrefix(key),
1091
+ step.with?.[key],
1092
+ );
1093
+ });
1094
+ props.push({ name: "cdx:github:step:dispatchesWorkflow", value: "true" });
1095
+ props.push({
1096
+ name: "cdx:github:step:dispatchKinds",
1097
+ value: dispatchAction.kind,
1098
+ });
1099
+ props.push({
1100
+ name: "cdx:github:step:dispatchMechanisms",
1101
+ value: dispatchAction.mechanism,
1102
+ });
1103
+ if (targets.size) {
1104
+ props.push({
1105
+ name: "cdx:github:step:dispatchTargets",
1106
+ value: Array.from(targets).join(","),
1107
+ });
1108
+ }
1109
+ if (Array.from(targets).some((target) => target.startsWith("repo:"))) {
1110
+ props.push({
1111
+ name: "cdx:github:step:dispatchUsesExplicitRepositoryTarget",
1112
+ value: "true",
1113
+ });
1114
+ }
1115
+ return props;
1116
+ }
1117
+
1118
+ function appendDispatchProperties(properties, dispatchInfo) {
1119
+ if (!dispatchInfo?.hasDispatch) {
1120
+ return;
1121
+ }
1122
+ properties.push({
1123
+ name: "cdx:github:step:dispatchesWorkflow",
1124
+ value: "true",
1125
+ });
1126
+ properties.push({
1127
+ name: "cdx:github:step:dispatchKinds",
1128
+ value: dispatchInfo.kinds.join(","),
1129
+ });
1130
+ properties.push({
1131
+ name: "cdx:github:step:dispatchMechanisms",
1132
+ value: dispatchInfo.mechanisms.join(","),
1133
+ });
1134
+ if (dispatchInfo.targets.length) {
1135
+ properties.push({
1136
+ name: "cdx:github:step:dispatchTargets",
1137
+ value: dispatchInfo.targets.join(","),
1138
+ });
1139
+ }
1140
+ if (dispatchInfo.usesExplicitRepositoryTarget) {
1141
+ properties.push({
1142
+ name: "cdx:github:step:dispatchUsesExplicitRepositoryTarget",
1143
+ value: "true",
1144
+ });
1145
+ }
1146
+ }
1147
+
1148
+ function appendHiddenUnicodeProperties(properties, scan, prefix) {
1149
+ if (!scan?.hasHiddenUnicode) {
1150
+ return;
1151
+ }
1152
+ properties.push({
1153
+ name: `${prefix}:hasHiddenUnicode`,
1154
+ value: "true",
1155
+ });
1156
+ properties.push({
1157
+ name: `${prefix}:hiddenUnicodeCodePoints`,
1158
+ value: scan.codePoints.join(","),
1159
+ });
1160
+ properties.push({
1161
+ name: `${prefix}:hiddenUnicodeLineNumbers`,
1162
+ value: scan.lineNumbers.join(","),
1163
+ });
1164
+ if (scan.inComments) {
1165
+ properties.push({
1166
+ name: `${prefix}:hiddenUnicodeInComments`,
1167
+ value: "true",
1168
+ });
1169
+ properties.push({
1170
+ name: `${prefix}:hiddenUnicodeCommentCodePoints`,
1171
+ value: scan.commentCodePoints.join(","),
1172
+ });
1173
+ }
1174
+ }
1175
+
1176
+ /**
1177
+ * Classify a GitHub Actions version reference as `"sha"`, `"tag"`, or `"branch"`.
1178
+ *
1179
+ * @param {string|undefined} versionRef - The part after `@` in `uses: owner/action@ref`.
1180
+ * @returns {"sha"|"tag"|"branch"|"unknown"} The pinning category.
1181
+ */
1182
+ function getVersionPinningType(versionRef) {
1183
+ if (!versionRef) {
1184
+ return "unknown";
1185
+ }
1186
+ if (/^[a-f0-9]{40}$/.test(versionRef)) {
1187
+ return "sha";
1188
+ }
1189
+ if (
1190
+ versionRef === "main" ||
1191
+ versionRef === "master" ||
1192
+ versionRef.includes("/")
1193
+ ) {
1194
+ return "branch";
1195
+ }
1196
+ return "tag";
1197
+ }
1198
+
1199
+ /**
1200
+ * Normalise the `on:` trigger value from a workflow YAML into a
1201
+ * comma-separated string of trigger names.
1202
+ *
1203
+ * GitHub Actions supports three forms:
1204
+ * - string: `on: push`
1205
+ * - array: `on: [push, pull_request]`
1206
+ * - object: `on: { push: { branches: [main] } }`
1207
+ *
1208
+ * @param {string|string[]|Object|undefined} triggers - Raw `on` value.
1209
+ * @returns {string} Comma-separated trigger names, or empty string.
1210
+ */
1211
+ function normalizeTriggers(triggers) {
1212
+ if (!triggers) return "";
1213
+ if (typeof triggers === "string") return triggers;
1214
+ if (Array.isArray(triggers)) return triggers.join(",");
1215
+ return Object.keys(triggers).join(",");
1216
+ }
1217
+
1218
+ function extractWorkflowDispatchInputs(triggers) {
1219
+ if (!triggers || typeof triggers !== "object") {
1220
+ return [];
1221
+ }
1222
+ if (!triggers.workflow_dispatch?.inputs) {
1223
+ return [];
1224
+ }
1225
+ return Object.keys(triggers.workflow_dispatch.inputs);
1226
+ }
1227
+
1228
+ function extractRepositoryDispatchTypes(triggers) {
1229
+ if (!triggers || typeof triggers !== "object") {
1230
+ return [];
1231
+ }
1232
+ const repositoryDispatch = triggers.repository_dispatch;
1233
+ if (!repositoryDispatch || typeof repositoryDispatch !== "object") {
1234
+ return [];
1235
+ }
1236
+ if (!Array.isArray(repositoryDispatch.types)) {
1237
+ return [];
1238
+ }
1239
+ return repositoryDispatch.types
1240
+ .map((eventType) => String(eventType || "").trim())
1241
+ .filter(Boolean);
1242
+ }
1243
+
1244
+ function normalizeTriggerNames(triggers) {
1245
+ const csv = normalizeTriggers(triggers);
1246
+ if (!csv) {
1247
+ return [];
1248
+ }
1249
+ return csv
1250
+ .split(",")
1251
+ .map((trigger) => trigger.trim())
1252
+ .filter(Boolean);
1253
+ }
1254
+
1255
+ function extractWorkflowCallMetadata(triggers) {
1256
+ if (!triggers || typeof triggers !== "object") {
1257
+ return { inputs: [], outputs: [], secrets: [] };
1258
+ }
1259
+ const workflowCall = triggers.workflow_call;
1260
+ if (!workflowCall || typeof workflowCall !== "object") {
1261
+ return { inputs: [], outputs: [], secrets: [] };
1262
+ }
1263
+ return {
1264
+ inputs: Object.keys(workflowCall.inputs || {}),
1265
+ outputs: Object.keys(workflowCall.outputs || {}),
1266
+ secrets: Object.keys(workflowCall.secrets || {}),
1267
+ };
1268
+ }
1269
+
1270
+ /**
1271
+ * Determine whether the given trigger value includes at least one high-risk
1272
+ * trigger (`pull_request_target`, `issue_comment`, or `workflow_run`).
1273
+ *
1274
+ * @param {string|string[]|Object|undefined} triggers - Raw `on` value.
1275
+ * @returns {boolean}
1276
+ */
1277
+ function hasHighRiskTrigger(triggers) {
1278
+ const csv = normalizeTriggers(triggers);
1279
+ if (!csv) return false;
1280
+ return csv.split(",").some((t) => HIGH_RISK_TRIGGERS.includes(t.trim()));
1281
+ }
1282
+
1283
+ /**
1284
+ * Build the set of common workflow-context properties that are duplicated
1285
+ * onto every component (action or run-step) so that policy rules written
1286
+ * against `components[…]` can evaluate workflow-level attributes without
1287
+ * traversing the formulation tree.
1288
+ *
1289
+ * @param {Object} ctx
1290
+ * @param {boolean} ctx.hasWritePermissions - Whether workflow OR job has write perms.
1291
+ * @param {boolean} ctx.hasIdTokenWrite - Whether `id-token: write` is granted.
1292
+ * @param {string} ctx.triggers - Comma-separated trigger names.
1293
+ * @param {boolean} ctx.isHighRisk - Whether any trigger is high-risk.
1294
+ * @param {string} concurrencyGroup - Workflow concurrency group.
1295
+ * @returns {Array<{name: string, value: string}>}
1296
+ */
1297
+ function buildWorkflowContextProperties({
1298
+ hasExplicitPermissionsBlock,
1299
+ hasAnyExplicitPermissionsBlock,
1300
+ hasWritePermissions,
1301
+ hasIdTokenWrite,
1302
+ triggers,
1303
+ triggerNames,
1304
+ isHighRisk,
1305
+ concurrencyGroup,
1306
+ writeScopes,
1307
+ dispatchInputs,
1308
+ repositoryDispatchTypes,
1309
+ workflowReceiverAliases,
1310
+ workflowCallMetadata,
1311
+ }) {
1312
+ const props = [];
1313
+ props.push({
1314
+ name: "cdx:github:workflow:hasExplicitPermissionsBlock",
1315
+ value: String(Boolean(hasExplicitPermissionsBlock)),
1316
+ });
1317
+ props.push({
1318
+ name: "cdx:github:workflow:hasAnyExplicitPermissionsBlock",
1319
+ value: String(Boolean(hasAnyExplicitPermissionsBlock)),
1320
+ });
1321
+ if (hasWritePermissions) {
1322
+ props.push({
1323
+ name: "cdx:github:workflow:hasWritePermissions",
1324
+ value: "true",
1325
+ });
1326
+ }
1327
+ if (hasIdTokenWrite) {
1328
+ props.push({
1329
+ name: "cdx:github:workflow:hasIdTokenWrite",
1330
+ value: "true",
1331
+ });
1332
+ }
1333
+ if (writeScopes?.length) {
1334
+ props.push({
1335
+ name: "cdx:github:workflow:writeScopes",
1336
+ value: [...new Set(writeScopes)].join(","),
1337
+ });
1338
+ }
1339
+ if (triggers) {
1340
+ props.push({ name: "cdx:github:workflow:triggers", value: triggers });
1341
+ }
1342
+ const triggerSet = new Set(triggerNames || normalizeTriggerNames(triggers));
1343
+ const triggerFlags = [
1344
+ ["pull_request", "cdx:github:workflow:hasPullRequestTrigger"],
1345
+ ["pull_request_target", "cdx:github:workflow:hasPullRequestTargetTrigger"],
1346
+ ["issue_comment", "cdx:github:workflow:hasIssueCommentTrigger"],
1347
+ ["repository_dispatch", "cdx:github:workflow:hasRepositoryDispatchTrigger"],
1348
+ ["workflow_run", "cdx:github:workflow:hasWorkflowRunTrigger"],
1349
+ ["workflow_dispatch", "cdx:github:workflow:hasWorkflowDispatchTrigger"],
1350
+ ["workflow_call", "cdx:github:workflow:hasWorkflowCallTrigger"],
1351
+ ];
1352
+ triggerFlags.forEach(([triggerName, propName]) => {
1353
+ if (triggerSet.has(triggerName)) {
1354
+ props.push({ name: propName, value: "true" });
1355
+ }
1356
+ });
1357
+ if (isHighRisk) {
1358
+ props.push({
1359
+ name: "cdx:github:workflow:hasHighRiskTrigger",
1360
+ value: "true",
1361
+ });
1362
+ }
1363
+ if (concurrencyGroup) {
1364
+ props.push({
1365
+ name: "cdx:github:workflow:concurrencyGroup",
1366
+ value: concurrencyGroup,
1367
+ });
1368
+ }
1369
+ if (dispatchInputs?.length) {
1370
+ props.push({
1371
+ name: "cdx:github:workflow:hasWorkflowDispatchInputs",
1372
+ value: "true",
1373
+ });
1374
+ props.push({
1375
+ name: "cdx:github:workflow:workflowDispatchInputs",
1376
+ value: dispatchInputs.join(","),
1377
+ });
1378
+ }
1379
+ if (repositoryDispatchTypes?.length) {
1380
+ props.push({
1381
+ name: "cdx:github:workflow:repositoryDispatchTypes",
1382
+ value: repositoryDispatchTypes.join(","),
1383
+ });
1384
+ }
1385
+ if (workflowReceiverAliases?.length) {
1386
+ props.push({
1387
+ name: "cdx:github:workflow:workflowDispatchReceiverAliases",
1388
+ value: workflowReceiverAliases.join(","),
1389
+ });
1390
+ }
1391
+ if (workflowCallMetadata?.inputs?.length) {
1392
+ props.push({
1393
+ name: "cdx:github:workflow:workflowCallInputs",
1394
+ value: workflowCallMetadata.inputs.join(","),
1395
+ });
1396
+ }
1397
+ if (workflowCallMetadata?.secrets?.length) {
1398
+ props.push({
1399
+ name: "cdx:github:workflow:workflowCallSecrets",
1400
+ value: workflowCallMetadata.secrets.join(","),
1401
+ });
1402
+ }
1403
+ if (workflowCallMetadata?.outputs?.length) {
1404
+ props.push({
1405
+ name: "cdx:github:workflow:workflowCallOutputs",
1406
+ value: workflowCallMetadata.outputs.join(","),
1407
+ });
1408
+ }
1409
+ if (
1410
+ workflowCallMetadata?.inputs?.length ||
1411
+ workflowCallMetadata?.secrets?.length ||
1412
+ workflowCallMetadata?.outputs?.length
1413
+ ) {
1414
+ props.push({
1415
+ name: "cdx:github:workflow:isWorkflowCallProducer",
1416
+ value: "true",
1417
+ });
1418
+ }
1419
+ return props;
1420
+ }
1421
+
1422
+ function buildJobContextProperties({
1423
+ hasExplicitPermissionsBlock,
1424
+ hasWritePermissions,
1425
+ hasIdTokenWrite,
1426
+ isSelfHosted,
1427
+ writeScopes,
1428
+ condition,
1429
+ }) {
1430
+ const props = [];
1431
+ props.push({
1432
+ name: "cdx:github:job:hasExplicitPermissionsBlock",
1433
+ value: String(Boolean(hasExplicitPermissionsBlock)),
1434
+ });
1435
+ if (hasWritePermissions) {
1436
+ props.push({
1437
+ name: "cdx:github:job:hasWritePermissions",
1438
+ value: "true",
1439
+ });
1440
+ }
1441
+ if (hasIdTokenWrite) {
1442
+ props.push({
1443
+ name: "cdx:github:job:hasIdTokenWrite",
1444
+ value: "true",
1445
+ });
1446
+ }
1447
+ if (isSelfHosted) {
1448
+ props.push({
1449
+ name: "cdx:github:job:isSelfHosted",
1450
+ value: "true",
1451
+ });
1452
+ }
1453
+ if (writeScopes?.length) {
1454
+ props.push({
1455
+ name: "cdx:github:job:writeScopes",
1456
+ value: [...new Set(writeScopes)].join(","),
1457
+ });
1458
+ }
1459
+ if (condition) {
1460
+ props.push({ name: "cdx:github:job:if", value: condition });
1461
+ }
1462
+ return props;
1463
+ }
1464
+
1465
+ /**
1466
+ * @param {string} filePath workflow file path
1467
+ * @returns {string} workflow name derived from the file stem
1468
+ */
1469
+ function deriveWorkflowNameFromPath(filePath) {
1470
+ const pathImpl = filePath.includes("\\") ? path.win32 : path.posix;
1471
+ return pathImpl.parse(pathImpl.basename(filePath)).name;
1472
+ }
1473
+
1474
+ function deriveWorkflowReceiverAliases(filePath, workflowName) {
1475
+ const aliases = new Set();
1476
+ if (workflowName) {
1477
+ aliases.add(String(workflowName).trim());
1478
+ }
1479
+ if (filePath) {
1480
+ const normalizedPath = String(filePath).replace(/\\/g, "/");
1481
+ const fileName = normalizedPath.split("/").pop() || normalizedPath;
1482
+ const fileStem = fileName.replace(/\.ya?ml$/i, "");
1483
+ aliases.add(fileName);
1484
+ aliases.add(fileStem);
1485
+ aliases.add(normalizedPath);
1486
+ }
1487
+ return Array.from(aliases)
1488
+ .map((alias) => alias.trim())
1489
+ .filter(Boolean);
1490
+ }
1491
+
1492
+ function getPropertyValue(obj, propName) {
1493
+ return obj?.properties?.find((property) => property.name === propName)?.value;
1494
+ }
1495
+
1496
+ function upsertCsvProperty(properties, name, values) {
1497
+ const normalizedValues = [...new Set((values || []).filter(Boolean))];
1498
+ if (!normalizedValues.length) {
1499
+ return;
1500
+ }
1501
+ const existingProperty = properties.find(
1502
+ (property) => property.name === name,
1503
+ );
1504
+ if (!existingProperty) {
1505
+ properties.push({ name, value: normalizedValues.join(",") });
1506
+ return;
1507
+ }
1508
+ existingProperty.value = [
1509
+ ...new Set([
1510
+ ...String(existingProperty.value || "")
1511
+ .split(",")
1512
+ .map((value) => value.trim())
1513
+ .filter(Boolean),
1514
+ ...normalizedValues,
1515
+ ]),
1516
+ ].join(",");
1517
+ }
1518
+
1519
+ function upsertBooleanProperty(properties, name) {
1520
+ const existingProperty = properties.find(
1521
+ (property) => property.name === name,
1522
+ );
1523
+ if (existingProperty) {
1524
+ existingProperty.value = "true";
1525
+ return;
1526
+ }
1527
+ properties.push({ name, value: "true" });
1528
+ }
1529
+
1530
+ function parseDispatchTargets(value) {
1531
+ return String(value || "")
1532
+ .split(",")
1533
+ .map((target) => target.trim())
1534
+ .filter(Boolean)
1535
+ .map((target) => {
1536
+ const separatorIndex = target.indexOf(":");
1537
+ if (separatorIndex === -1) {
1538
+ return { type: "unknown", value: target };
1539
+ }
1540
+ return {
1541
+ type: target.slice(0, separatorIndex),
1542
+ value: target.slice(separatorIndex + 1),
1543
+ };
1544
+ });
1545
+ }
1546
+
1547
+ function normalizeDispatchTargetValue(value) {
1548
+ return String(value || "")
1549
+ .trim()
1550
+ .toLowerCase();
1551
+ }
1552
+
1553
+ function buildLocalDispatchReceiverIndexes(workflows) {
1554
+ const workflowDispatchAliasIndex = new Map();
1555
+ const repositoryDispatchTypeIndex = new Map();
1556
+ (workflows || []).forEach((workflow) => {
1557
+ if (
1558
+ getPropertyValue(
1559
+ workflow,
1560
+ "cdx:github:workflow:hasWorkflowDispatchTrigger",
1561
+ ) === "true"
1562
+ ) {
1563
+ const aliases = String(
1564
+ getPropertyValue(
1565
+ workflow,
1566
+ "cdx:github:workflow:workflowDispatchReceiverAliases",
1567
+ ) || "",
1568
+ )
1569
+ .split(",")
1570
+ .map((alias) => alias.trim())
1571
+ .filter(Boolean);
1572
+ aliases.forEach((alias) => {
1573
+ const normalizedAlias = normalizeDispatchTargetValue(alias);
1574
+ if (!workflowDispatchAliasIndex.has(normalizedAlias)) {
1575
+ workflowDispatchAliasIndex.set(normalizedAlias, []);
1576
+ }
1577
+ workflowDispatchAliasIndex.get(normalizedAlias).push(workflow);
1578
+ });
1579
+ }
1580
+ if (
1581
+ getPropertyValue(
1582
+ workflow,
1583
+ "cdx:github:workflow:hasRepositoryDispatchTrigger",
1584
+ ) === "true"
1585
+ ) {
1586
+ const eventTypes = String(
1587
+ getPropertyValue(
1588
+ workflow,
1589
+ "cdx:github:workflow:repositoryDispatchTypes",
1590
+ ) || "",
1591
+ )
1592
+ .split(",")
1593
+ .map((eventType) => eventType.trim())
1594
+ .filter(Boolean);
1595
+ eventTypes.forEach((eventType) => {
1596
+ const normalizedEventType = normalizeDispatchTargetValue(eventType);
1597
+ if (!repositoryDispatchTypeIndex.has(normalizedEventType)) {
1598
+ repositoryDispatchTypeIndex.set(normalizedEventType, []);
1599
+ }
1600
+ repositoryDispatchTypeIndex.get(normalizedEventType).push(workflow);
1601
+ });
1602
+ }
1603
+ });
1604
+ return {
1605
+ repositoryDispatchTypeIndex,
1606
+ workflowDispatchAliasIndex,
1607
+ };
1608
+ }
1609
+
1610
+ function enrichLocalDispatchRelationships(workflows, components) {
1611
+ const { repositoryDispatchTypeIndex, workflowDispatchAliasIndex } =
1612
+ buildLocalDispatchReceiverIndexes(workflows);
1613
+ (components || []).forEach((component) => {
1614
+ if (
1615
+ getPropertyValue(component, "cdx:github:step:dispatchesWorkflow") !==
1616
+ "true"
1617
+ ) {
1618
+ return;
1619
+ }
1620
+ const dispatchTargets = parseDispatchTargets(
1621
+ getPropertyValue(component, "cdx:github:step:dispatchTargets"),
1622
+ );
1623
+ if (dispatchTargets.some((target) => target.type === "repo")) {
1624
+ return;
1625
+ }
1626
+ const matchedWorkflows = [];
1627
+ const matchBases = [];
1628
+ dispatchTargets.forEach((target) => {
1629
+ if (target.type === "workflow") {
1630
+ const candidates =
1631
+ workflowDispatchAliasIndex.get(
1632
+ normalizeDispatchTargetValue(target.value),
1633
+ ) || [];
1634
+ if (candidates.length === 1) {
1635
+ matchedWorkflows.push(candidates[0]);
1636
+ matchBases.push(`workflow:${target.value}`);
1637
+ }
1638
+ }
1639
+ if (target.type === "event") {
1640
+ const candidates =
1641
+ repositoryDispatchTypeIndex.get(
1642
+ normalizeDispatchTargetValue(target.value),
1643
+ ) || [];
1644
+ if (candidates.length === 1) {
1645
+ matchedWorkflows.push(candidates[0]);
1646
+ matchBases.push(`repository_dispatch:${target.value}`);
1647
+ }
1648
+ }
1649
+ });
1650
+ const uniqueMatchedWorkflows = [...new Set(matchedWorkflows)];
1651
+ if (!uniqueMatchedWorkflows.length) {
1652
+ return;
1653
+ }
1654
+ const receiverWorkflowFiles = uniqueMatchedWorkflows
1655
+ .map((workflow) => getPropertyValue(workflow, "cdx:github:workflow:file"))
1656
+ .filter(Boolean);
1657
+ const receiverWorkflowNames = uniqueMatchedWorkflows
1658
+ .map((workflow) => getPropertyValue(workflow, "cdx:github:workflow:name"))
1659
+ .filter(Boolean);
1660
+ upsertBooleanProperty(
1661
+ component.properties,
1662
+ "cdx:github:step:hasLocalDispatchReceiver",
1663
+ );
1664
+ upsertCsvProperty(
1665
+ component.properties,
1666
+ "cdx:github:step:dispatchReceiverWorkflowFiles",
1667
+ receiverWorkflowFiles,
1668
+ );
1669
+ upsertCsvProperty(
1670
+ component.properties,
1671
+ "cdx:github:step:dispatchReceiverWorkflowNames",
1672
+ receiverWorkflowNames,
1673
+ );
1674
+ upsertCsvProperty(
1675
+ component.properties,
1676
+ "cdx:github:step:dispatchReceiverMatchBasis",
1677
+ matchBases,
1678
+ );
1679
+ upsertCsvProperty(
1680
+ component.properties,
1681
+ "cdx:github:step:dispatchReceiverConfidence",
1682
+ ["high"],
1683
+ );
1684
+ uniqueMatchedWorkflows.forEach((workflow) => {
1685
+ const senderWorkflowFile = getPropertyValue(
1686
+ component,
1687
+ "cdx:github:workflow:file",
1688
+ );
1689
+ const senderWorkflowName = getPropertyValue(
1690
+ component,
1691
+ "cdx:github:workflow:name",
1692
+ );
1693
+ upsertBooleanProperty(
1694
+ workflow.properties,
1695
+ "cdx:github:workflow:hasLocalDispatchSender",
1696
+ );
1697
+ upsertCsvProperty(
1698
+ workflow.properties,
1699
+ "cdx:github:workflow:dispatchSenderWorkflowFiles",
1700
+ [senderWorkflowFile],
1701
+ );
1702
+ upsertCsvProperty(
1703
+ workflow.properties,
1704
+ "cdx:github:workflow:dispatchSenderWorkflowNames",
1705
+ [senderWorkflowName],
1706
+ );
1707
+ upsertCsvProperty(
1708
+ workflow.properties,
1709
+ "cdx:github:workflow:dispatchSenderMatchBasis",
1710
+ matchBases,
1711
+ );
1712
+ });
1713
+ });
1714
+ }
1715
+
1716
+ function buildReusableWorkflowComponent(
1717
+ job,
1718
+ jobName,
1719
+ filePath,
1720
+ workflowName,
1721
+ jobRunner,
1722
+ jobContextProperties,
1723
+ workflowContextProperties,
1724
+ options,
1725
+ ) {
1726
+ const uses = job?.uses;
1727
+ if (!uses || typeof uses !== "string") {
1728
+ return undefined;
1729
+ }
1730
+ let group;
1731
+ let name = uses;
1732
+ let purl;
1733
+ let versionRef;
1734
+ let versionPinningType = "unknown";
1735
+ let isShaPinned = false;
1736
+ const isExternal = !uses.startsWith("./");
1737
+
1738
+ if (isExternal) {
1739
+ const tmpA = uses.split("@");
1740
+ const workflowRef = tmpA[0];
1741
+ versionRef = tmpA[1];
1742
+ versionPinningType = getVersionPinningType(versionRef);
1743
+ isShaPinned = versionPinningType === "sha";
1744
+ if (workflowRef.includes("/.github/workflows/")) {
1745
+ const [repoPath, workflowPath] = workflowRef.split("/.github/workflows/");
1746
+ group = repoPath;
1747
+ name = workflowPath;
1748
+ } else {
1749
+ const refParts = workflowRef.split("/");
1750
+ name = refParts.pop() || workflowRef;
1751
+ group = refParts.join("/");
1752
+ }
1753
+ if (versionRef) {
1754
+ purl = build({
1755
+ type: "github",
1756
+ namespace: group || undefined || null,
1757
+ name: name,
1758
+ version: versionRef || null,
1759
+ });
1760
+ }
1761
+ } else {
1762
+ const pathImpl = uses.includes("\\") ? path.win32 : path.posix;
1763
+ name = pathImpl.basename(uses);
1764
+ }
1765
+
1766
+ const componentRef = purl || `github-workflow:${uses}`;
1767
+ const properties = [
1768
+ { name: "internal:SrcFile", value: filePath },
1769
+ { name: "cdx:github:workflow:name", value: workflowName },
1770
+ { name: "cdx:github:workflow:file", value: filePath },
1771
+ { name: "cdx:github:job:name", value: jobName },
1772
+ {
1773
+ name: "cdx:github:job:runner",
1774
+ value: normalizeRunnerValue(jobRunner),
1775
+ },
1776
+ { name: "cdx:github:reusableWorkflow:uses", value: uses },
1777
+ {
1778
+ name: "cdx:github:reusableWorkflow:isExternal",
1779
+ value: String(isExternal),
1780
+ },
1781
+ {
1782
+ name: "cdx:github:reusableWorkflow:versionPinningType",
1783
+ value: versionPinningType,
1784
+ },
1785
+ {
1786
+ name: "cdx:github:reusableWorkflow:isShaPinned",
1787
+ value: String(isShaPinned),
1788
+ },
1789
+ ];
1790
+ if (versionRef) {
1791
+ properties.push({
1792
+ name: "cdx:github:reusableWorkflow:ref",
1793
+ value: versionRef,
1794
+ });
1795
+ }
1796
+ if (job.secrets === "inherit") {
1797
+ properties.push({
1798
+ name: "cdx:github:reusableWorkflow:secretsInherit",
1799
+ value: "true",
1800
+ });
1801
+ }
1802
+ if (job.with && typeof job.with === "object") {
1803
+ const withKeys = Object.keys(job.with);
1804
+ if (withKeys.length) {
1805
+ properties.push({
1806
+ name: "cdx:github:reusableWorkflow:withKeys",
1807
+ value: withKeys.join(","),
1808
+ });
1809
+ }
1810
+ }
1811
+ properties.push(...jobContextProperties);
1812
+ properties.push(...workflowContextProperties);
1813
+ const component = {
1814
+ "bom-ref": componentRef,
1815
+ type: "application",
1816
+ group,
1817
+ name,
1818
+ version: versionRef,
1819
+ purl,
1820
+ properties,
1821
+ scope: isExternal ? "required" : "excluded",
1822
+ tags: ["reusable-workflow"],
1823
+ };
1824
+ if (options?.specVersion >= 1.7 && isExternal) {
1825
+ component.isExternal = true;
1826
+ }
1827
+ return component;
1828
+ }
1829
+
1830
+ /**
1831
+ * Parse a single GitHub Actions workflow file into workflow, component, and dependency data.
1832
+ *
1833
+ * @param {string} f Absolute path to a workflow YAML file
1834
+ * @param {Object} options CLI options
1835
+ * @returns {{ workflows: Object[], components: Object[], dependencies: Object[] }}
1836
+ */
1837
+
1838
+ export function parseWorkflowFile(f, options) {
1839
+ const workflows = [];
1840
+ const components = [];
1841
+ const dependencies = [];
1842
+
1843
+ let raw;
1844
+ try {
1845
+ raw = readFileSync(f, { encoding: "utf-8" });
1846
+ } catch (_e) {
1847
+ return { workflows, components, dependencies };
1848
+ }
1849
+
1850
+ let yamlObj;
1851
+ const hiddenUnicodeScan = scanTextForHiddenUnicode(raw, { syntax: "yaml" });
1852
+ try {
1853
+ yamlObj = _load(raw);
1854
+ } catch (_e) {
1855
+ return { workflows, components, dependencies };
1856
+ }
1857
+
1858
+ if (!yamlObj?.jobs) {
1859
+ return { workflows, components, dependencies };
1860
+ }
1861
+ const workflowName = yamlObj.name || deriveWorkflowNameFromPath(f);
1862
+ const workflowTriggers = yamlObj.on || yamlObj.true;
1863
+ const workflowHasExplicitPermissionsBlock = Object.hasOwn(
1864
+ yamlObj,
1865
+ "permissions",
1866
+ );
1867
+ const workflowPermissions = workflowHasExplicitPermissionsBlock
1868
+ ? yamlObj.permissions || {}
1869
+ : {};
1870
+ const workflowEnv = yamlObj.env || {};
1871
+ const workflowHasWritePermissions = analyzePermissions(workflowPermissions);
1872
+ const workflowWriteScopes = new Set(extractWriteScopes(workflowPermissions));
1873
+ const workflowConcurrency = yamlObj.concurrency || {};
1874
+ const workflowHasIdTokenWrite =
1875
+ hasIdTokenWritePermission(workflowPermissions);
1876
+ const triggers = normalizeTriggers(workflowTriggers);
1877
+ const triggerNames = normalizeTriggerNames(workflowTriggers);
1878
+ const isHighRisk = hasHighRiskTrigger(workflowTriggers);
1879
+ const workflowDispatchInputs =
1880
+ extractWorkflowDispatchInputs(workflowTriggers);
1881
+ const repositoryDispatchTypes =
1882
+ extractRepositoryDispatchTypes(workflowTriggers);
1883
+ const workflowCallMetadata = extractWorkflowCallMetadata(workflowTriggers);
1884
+ const workflowReceiverAliases = deriveWorkflowReceiverAliases(
1885
+ f,
1886
+ workflowName,
1887
+ );
1888
+
1889
+ const workflowRef = uuidv4();
1890
+ const tasks = [];
1891
+ const workflowDependsOn = [];
1892
+ let anyJobHasExplicitPermissionsBlock = false;
1893
+ let anyJobHasWritePermissions = false;
1894
+ let anyJobHasIdTokenWrite = false;
1895
+
1896
+ for (const jobName of Object.keys(yamlObj.jobs)) {
1897
+ const job = yamlObj.jobs[jobName];
1898
+ const jobRef = uuidv4();
1899
+ const steps = [];
1900
+ const jobDependsOn = [];
1901
+
1902
+ // Job needs (dependency links)
1903
+ let jobNeeds = job.needs || [];
1904
+ if (!Array.isArray(jobNeeds)) {
1905
+ jobNeeds = [jobNeeds];
1906
+ }
1907
+
1908
+ const jobRunner = job["runs-on"] || "unknown";
1909
+ const jobEnvironment = job.environment?.name || job.environment || "";
1910
+ const jobEnv = job.env || {};
1911
+ const jobTimeout = job["timeout-minutes"] || null;
1912
+ const jobHasExplicitPermissionsBlock = Object.hasOwn(job, "permissions");
1913
+ const jobPermissions = jobHasExplicitPermissionsBlock
1914
+ ? job.permissions || {}
1915
+ : {};
1916
+ const jobHasWritePermissions = analyzePermissions(jobPermissions);
1917
+ const jobWriteScopes = extractWriteScopes(jobPermissions);
1918
+ const jobHasIdTokenWrite = hasIdTokenWritePermission(jobPermissions);
1919
+ const jobServices = job.services ? Object.keys(job.services) : [];
1920
+ const jobIsSelfHosted = isSelfHostedRunner(jobRunner);
1921
+ const effectiveWritePerms =
1922
+ workflowHasWritePermissions || jobHasWritePermissions;
1923
+ const effectiveIdTokenWrite = workflowHasIdTokenWrite || jobHasIdTokenWrite;
1924
+ const effectiveWriteScopes = [
1925
+ ...workflowWriteScopes,
1926
+ ...jobWriteScopes,
1927
+ ].filter(Boolean);
1928
+ anyJobHasExplicitPermissionsBlock ||= jobHasExplicitPermissionsBlock;
1929
+ anyJobHasWritePermissions ||= jobHasWritePermissions;
1930
+ anyJobHasIdTokenWrite ||= jobHasIdTokenWrite;
1931
+ jobWriteScopes.forEach((scope) => {
1932
+ workflowWriteScopes.add(scope);
1933
+ });
1934
+
1935
+ // Shared workflow-context properties for this job's components
1936
+ const sharedCtxProps = buildWorkflowContextProperties({
1937
+ hasExplicitPermissionsBlock: workflowHasExplicitPermissionsBlock,
1938
+ hasAnyExplicitPermissionsBlock:
1939
+ workflowHasExplicitPermissionsBlock || jobHasExplicitPermissionsBlock,
1940
+ hasWritePermissions: effectiveWritePerms,
1941
+ hasIdTokenWrite: effectiveIdTokenWrite,
1942
+ triggers,
1943
+ triggerNames,
1944
+ isHighRisk,
1945
+ writeScopes: effectiveWriteScopes,
1946
+ dispatchInputs: workflowDispatchInputs,
1947
+ repositoryDispatchTypes,
1948
+ workflowReceiverAliases,
1949
+ workflowCallMetadata,
1950
+ });
1951
+ const sharedJobCtxProps = buildJobContextProperties({
1952
+ hasExplicitPermissionsBlock: jobHasExplicitPermissionsBlock,
1953
+ hasWritePermissions: jobHasWritePermissions,
1954
+ hasIdTokenWrite: jobHasIdTokenWrite,
1955
+ isSelfHosted: jobIsSelfHosted,
1956
+ writeScopes: jobWriteScopes,
1957
+ condition: job.if,
1958
+ });
1959
+
1960
+ const jobProperties = [
1961
+ { name: "cdx:github:job:name", value: jobName },
1962
+ {
1963
+ name: "cdx:github:job:runner",
1964
+ value: normalizeRunnerValue(jobRunner),
1965
+ },
1966
+ ];
1967
+ if (jobEnvironment) {
1968
+ jobProperties.push({
1969
+ name: "cdx:github:job:environment",
1970
+ value: jobEnvironment,
1971
+ });
1972
+ }
1973
+ if (jobTimeout) {
1974
+ jobProperties.push({
1975
+ name: "cdx:github:job:timeoutMinutes",
1976
+ value: jobTimeout.toString(),
1977
+ });
1978
+ }
1979
+ if (jobServices.length) {
1980
+ jobProperties.push({
1981
+ name: "cdx:github:job:services",
1982
+ value: jobServices.join(","),
1983
+ });
1984
+ }
1985
+ if (jobNeeds.length) {
1986
+ jobProperties.push({
1987
+ name: "cdx:github:job:needs",
1988
+ value: jobNeeds.join(","),
1989
+ });
1990
+ }
1991
+ if (job.uses) {
1992
+ jobProperties.push({ name: "cdx:github:job:uses", value: job.uses });
1993
+ jobProperties.push({
1994
+ name: "cdx:github:job:isReusableWorkflowCall",
1995
+ value: "true",
1996
+ });
1997
+ }
1998
+ jobProperties.push(...sharedJobCtxProps);
1999
+ jobProperties.push(...sharedCtxProps);
2000
+
2001
+ const reusableWorkflowComponent = buildReusableWorkflowComponent(
2002
+ job,
2003
+ jobName,
2004
+ f,
2005
+ workflowName,
2006
+ jobRunner,
2007
+ sharedJobCtxProps,
2008
+ sharedCtxProps,
2009
+ options,
2010
+ );
2011
+ if (reusableWorkflowComponent) {
2012
+ components.push(reusableWorkflowComponent);
2013
+ jobDependsOn.push(reusableWorkflowComponent["bom-ref"]);
2014
+ steps.push({
2015
+ name: job.uses,
2016
+ commands: [{ executed: job.uses }],
2017
+ });
2018
+ }
2019
+
2020
+ for (const step of job.steps || []) {
2021
+ const stepName = step.name || step.uses || "unnamed step";
2022
+ const commands = [];
2023
+ let actionProperties = [];
2024
+ const effectiveEnv = { ...workflowEnv, ...jobEnv, ...(step.env || {}) };
2025
+ if (step.uses) {
2026
+ commands.push({ executed: step.uses });
2027
+ // Collect action references as components
2028
+ const tmpA = step.uses.split("@");
2029
+ if (tmpA.length === 2) {
2030
+ const groupName = tmpA[0];
2031
+ const tagOrCommit = tmpA[1];
2032
+ const versionPinningType = getVersionPinningType(tagOrCommit);
2033
+ const isShaPinned = versionPinningType === "sha";
2034
+
2035
+ const tmpB = groupName.split("/");
2036
+ const name = tmpB.length >= 2 ? tmpB.pop() : tmpB[0];
2037
+ const group = tmpB.join("/");
2038
+ const purl = build({
2039
+ type: "github",
2040
+ namespace: group || undefined || null,
2041
+ name: name,
2042
+ version: tagOrCommit || null,
2043
+ });
2044
+
2045
+ actionProperties = [
2046
+ ...actionProperties,
2047
+ { name: "internal:SrcFile", value: f },
2048
+ { name: "cdx:github:workflow:name", value: workflowName },
2049
+ { name: "cdx:github:workflow:file", value: f },
2050
+ { name: "cdx:github:job:name", value: jobName },
2051
+ {
2052
+ name: "cdx:github:job:runner",
2053
+ value: normalizeRunnerValue(jobRunner),
2054
+ },
2055
+ { name: "cdx:github:action:uses", value: step.uses },
2056
+ {
2057
+ name: "cdx:github:action:versionPinningType",
2058
+ value: versionPinningType,
2059
+ },
2060
+ {
2061
+ name: "cdx:github:action:isShaPinned",
2062
+ value: isShaPinned.toString(),
2063
+ },
2064
+ ];
2065
+ if (step.name) {
2066
+ actionProperties.push({
2067
+ name: "cdx:github:step:name",
2068
+ value: step.name,
2069
+ });
2070
+ }
2071
+ if (step.if) {
2072
+ actionProperties.push({
2073
+ name: "cdx:github:step:condition",
2074
+ value: step.if,
2075
+ });
2076
+ actionProperties.push({
2077
+ name: "cdx:github:step:if",
2078
+ value: step.if,
2079
+ });
2080
+ }
2081
+ if (step["continue-on-error"]) {
2082
+ actionProperties.push({
2083
+ name: "cdx:github:step:continueOnError",
2084
+ value: "true",
2085
+ });
2086
+ }
2087
+ if (step.timeout) {
2088
+ actionProperties.push({
2089
+ name: "cdx:github:step:timeout",
2090
+ value: step.timeout.toString(),
2091
+ });
2092
+ }
2093
+ const isOfficial =
2094
+ group?.startsWith("github/") || group === "actions";
2095
+ const isVerified = group?.startsWith("github/");
2096
+ actionProperties.push({
2097
+ name: "cdx:actions:isOfficial",
2098
+ value: String(isOfficial),
2099
+ });
2100
+ actionProperties.push({
2101
+ name: "cdx:actions:isVerified",
2102
+ value: String(isVerified),
2103
+ });
2104
+ actionProperties.push(...analyzeCheckoutStep(step));
2105
+ actionProperties.push(...analyzeCacheStep(step));
2106
+ actionProperties.push(...analyzeCargoActionStep(step));
2107
+ actionProperties.push(...analyzeSetupActionCacheStep(step));
2108
+ actionProperties.push(...analyzeDispatchActionStep(step));
2109
+ if (
2110
+ step.uses?.includes("actions/github-script") &&
2111
+ typeof step.with?.script === "string"
2112
+ ) {
2113
+ const scriptDispatchInfo = detectWorkflowDispatchInvocations(
2114
+ step.with.script,
2115
+ );
2116
+ appendDispatchProperties(actionProperties, scriptDispatchInfo);
2117
+ const githubScriptSensitiveRefs = [
2118
+ ...detectSensitiveContextReferences(
2119
+ step.with.script,
2120
+ effectiveEnv,
2121
+ ),
2122
+ ...collectSensitiveEnvBindings(effectiveEnv),
2123
+ ];
2124
+ if (step.with["github-token"]) {
2125
+ githubScriptSensitiveRefs.push("input:github-token");
2126
+ }
2127
+ if (githubScriptSensitiveRefs.length) {
2128
+ actionProperties.push({
2129
+ name: "cdx:github:step:referencesSensitiveContext",
2130
+ value: "true",
2131
+ });
2132
+ actionProperties.push({
2133
+ name: "cdx:github:step:sensitiveContextRefs",
2134
+ value: [...new Set(githubScriptSensitiveRefs)].join(","),
2135
+ });
2136
+ }
2137
+ const forkContextRefs = detectForkContextReferences(
2138
+ step.with.script,
2139
+ );
2140
+ if (forkContextRefs.length) {
2141
+ actionProperties.push({
2142
+ name: "cdx:github:step:referencesForkContext",
2143
+ value: "true",
2144
+ });
2145
+ actionProperties.push({
2146
+ name: "cdx:github:step:forkContextRefs",
2147
+ value: [...new Set(forkContextRefs)].join(","),
2148
+ });
2149
+ }
2150
+ }
2151
+ appendSensitiveOperationProperties(actionProperties);
2152
+ actionProperties.push(...sharedJobCtxProps);
2153
+ actionProperties.push(...sharedCtxProps);
2154
+ const evidence = {
2155
+ identity: [
2156
+ {
2157
+ field: "purl",
2158
+ confidence: 0.5,
2159
+ methods: [
2160
+ {
2161
+ technique: "source-code-analysis",
2162
+ confidence: 0.5,
2163
+ value: f,
2164
+ },
2165
+ ],
2166
+ },
2167
+ ],
2168
+ };
2169
+ const acomp = {
2170
+ "bom-ref": purl,
2171
+ type: "application",
2172
+ group,
2173
+ name,
2174
+ version: tagOrCommit,
2175
+ purl,
2176
+ properties: actionProperties,
2177
+ scope: "required",
2178
+ evidence,
2179
+ };
2180
+ if (options?.specVersion >= 1.7) {
2181
+ acomp.isExternal = true;
2182
+ }
2183
+ components.push(acomp);
2184
+ jobDependsOn.push(purl);
2185
+ }
2186
+ } else {
2187
+ const normalizedRun = normalizeRunValue(step.run);
2188
+ if (normalizedRun === undefined) {
2189
+ steps.push({
2190
+ name: stepName,
2191
+ });
2192
+ continue;
2193
+ }
2194
+ commands.push({ executed: normalizedRun.trim().split("\n")[0] });
2195
+ const stepRef = `${jobRef}-step-${steps.length + 1}`;
2196
+ const runProperties = [
2197
+ { name: "internal:SrcFile", value: f },
2198
+ { name: "cdx:github:workflow:name", value: workflowName },
2199
+ { name: "cdx:github:workflow:file", value: f },
2200
+ { name: "cdx:github:job:name", value: jobName },
2201
+ { name: "cdx:github:step:type", value: "run" },
2202
+ {
2203
+ name: "cdx:github:step:command",
2204
+ value: normalizedRun.trim().split("\n")[0],
2205
+ },
2206
+ ];
2207
+ if (step.if) {
2208
+ runProperties.push({
2209
+ name: "cdx:github:step:condition",
2210
+ value: step.if,
2211
+ });
2212
+ runProperties.push({
2213
+ name: "cdx:github:step:if",
2214
+ value: step.if,
2215
+ });
2216
+ }
2217
+ if (step["continue-on-error"]) {
2218
+ runProperties.push({
2219
+ name: "cdx:github:step:continueOnError",
2220
+ value: "true",
2221
+ });
2222
+ }
2223
+ runProperties.push(...sharedJobCtxProps);
2224
+ runProperties.push(...sharedCtxProps);
2225
+
2226
+ const { hasInterpolation, vars } =
2227
+ detectUntrustedInterpolation(normalizedRun);
2228
+ runProperties.push(...analyzeCargoRunStep(normalizedRun));
2229
+ if (hasInterpolation) {
2230
+ runProperties.push({
2231
+ name: "cdx:github:step:hasUntrustedInterpolation",
2232
+ value: "true",
2233
+ });
2234
+ runProperties.push({
2235
+ name: "cdx:github:step:interpolatedVars",
2236
+ value: vars.join(","),
2237
+ });
2238
+ }
2239
+ const { hasMutation, targets } =
2240
+ detectRunnerStateMutation(normalizedRun);
2241
+ if (hasMutation) {
2242
+ runProperties.push({
2243
+ name: "cdx:github:step:mutatesRunnerState",
2244
+ value: "true",
2245
+ });
2246
+ runProperties.push({
2247
+ name: "cdx:github:step:runnerStateTargets",
2248
+ value: targets.join(","),
2249
+ });
2250
+ }
2251
+ const { hasOutboundCommand, tools } =
2252
+ detectOutboundNetworkCommand(normalizedRun);
2253
+ if (hasOutboundCommand) {
2254
+ runProperties.push({
2255
+ name: "cdx:github:step:hasOutboundNetworkCommand",
2256
+ value: "true",
2257
+ });
2258
+ runProperties.push({
2259
+ name: "cdx:github:step:outboundNetworkTools",
2260
+ value: tools.join(","),
2261
+ });
2262
+ }
2263
+ const sensitiveContextRefs = detectSensitiveContextReferences(
2264
+ normalizedRun,
2265
+ effectiveEnv,
2266
+ );
2267
+ const dispatchInfo = detectWorkflowDispatchInvocations(normalizedRun);
2268
+ if (dispatchInfo.hasDispatch) {
2269
+ collectSensitiveEnvBindings(effectiveEnv).forEach((ref) => {
2270
+ sensitiveContextRefs.push(ref);
2271
+ });
2272
+ }
2273
+ if (sensitiveContextRefs.length) {
2274
+ runProperties.push({
2275
+ name: "cdx:github:step:referencesSensitiveContext",
2276
+ value: "true",
2277
+ });
2278
+ runProperties.push({
2279
+ name: "cdx:github:step:sensitiveContextRefs",
2280
+ value: sensitiveContextRefs.join(","),
2281
+ });
2282
+ }
2283
+ appendDispatchProperties(runProperties, dispatchInfo);
2284
+ const forkContextRefs = detectForkContextReferences(normalizedRun);
2285
+ if (forkContextRefs.length) {
2286
+ runProperties.push({
2287
+ name: "cdx:github:step:referencesForkContext",
2288
+ value: "true",
2289
+ });
2290
+ runProperties.push({
2291
+ name: "cdx:github:step:forkContextRefs",
2292
+ value: [...new Set(forkContextRefs)].join(","),
2293
+ });
2294
+ }
2295
+ const exfiltrationIndicators = hasOutboundCommand
2296
+ ? detectOutboundExfiltrationIndicators(
2297
+ normalizedRun,
2298
+ sensitiveContextRefs,
2299
+ )
2300
+ : [];
2301
+ if (exfiltrationIndicators.length) {
2302
+ runProperties.push({
2303
+ name: "cdx:github:step:likelyExfiltration",
2304
+ value: "true",
2305
+ });
2306
+ runProperties.push({
2307
+ name: "cdx:github:step:exfiltrationIndicators",
2308
+ value: exfiltrationIndicators.join(","),
2309
+ });
2310
+ }
2311
+ runProperties.push(...analyzeLegacyPublishStep(step, effectiveEnv));
2312
+ appendSensitiveOperationProperties(runProperties);
2313
+ components.push({
2314
+ "bom-ref": stepRef,
2315
+ purl: undefined,
2316
+ scope: "excluded",
2317
+ type: "application",
2318
+ name: stepName,
2319
+ properties: runProperties,
2320
+ tags: ["workflow-step"],
2321
+ });
2322
+
2323
+ jobDependsOn.push(stepRef);
2324
+ }
2325
+
2326
+ steps.push({
2327
+ name: stepName,
2328
+ commands: commands.length ? commands : undefined,
2329
+ });
2330
+ }
2331
+
2332
+ const task = {
2333
+ "bom-ref": jobRef,
2334
+ uid: jobRef,
2335
+ name: jobName,
2336
+ taskTypes: ["build"],
2337
+ steps: disambiguateSteps(steps),
2338
+ properties: jobProperties,
2339
+ };
2340
+
2341
+ tasks.push(task);
2342
+ workflowDependsOn.push(jobRef);
2343
+
2344
+ // Wire job→action dependencies
2345
+ if (jobDependsOn.length) {
2346
+ dependencies.push({ ref: jobRef, dependsOn: jobDependsOn });
2347
+ }
2348
+ }
2349
+
2350
+ // Build workflow-level properties using the same helpers
2351
+ const workflowProperties = [
2352
+ { name: "cdx:github:workflow:file", value: f },
2353
+ { name: "cdx:github:workflow:name", value: workflowName },
2354
+ ...buildWorkflowContextProperties({
2355
+ hasExplicitPermissionsBlock: workflowHasExplicitPermissionsBlock,
2356
+ hasAnyExplicitPermissionsBlock:
2357
+ workflowHasExplicitPermissionsBlock ||
2358
+ anyJobHasExplicitPermissionsBlock,
2359
+ hasWritePermissions:
2360
+ workflowHasWritePermissions || anyJobHasWritePermissions,
2361
+ hasIdTokenWrite: workflowHasIdTokenWrite || anyJobHasIdTokenWrite,
2362
+ triggers,
2363
+ triggerNames,
2364
+ isHighRisk,
2365
+ concurrencyGroup: workflowConcurrency?.group,
2366
+ writeScopes: Array.from(workflowWriteScopes),
2367
+ dispatchInputs: workflowDispatchInputs,
2368
+ repositoryDispatchTypes,
2369
+ workflowReceiverAliases,
2370
+ workflowCallMetadata,
2371
+ }),
2372
+ ];
2373
+ appendHiddenUnicodeProperties(
2374
+ workflowProperties,
2375
+ hiddenUnicodeScan,
2376
+ "cdx:github:workflow",
2377
+ );
2378
+ const workflow = {
2379
+ "bom-ref": workflowRef,
2380
+ uid: workflowRef,
2381
+ name: workflowName,
2382
+ taskTypes: ["build"],
2383
+ tasks: tasks.length ? tasks : undefined,
2384
+ properties: workflowProperties,
2385
+ };
2386
+
2387
+ workflows.push(workflow);
2388
+
2389
+ if (workflowDependsOn.length) {
2390
+ dependencies.push({ ref: workflowRef, dependsOn: workflowDependsOn });
2391
+ }
2392
+
2393
+ return { workflows, components, dependencies };
2394
+ }
2395
+
2396
+ /**
2397
+ * GitHub Actions formulation parser.
2398
+ *
2399
+ * Matches `.github/workflows/*.yml` and `*.yaml` files and converts them into
2400
+ * CycloneDX formulation workflow objects, with referenced actions as components.
2401
+ *
2402
+ * Parser contract: `parse(files, options)` returns
2403
+ * `{ workflows, components, services, properties, dependencies }`.
2404
+ */
2405
+ export const githubActionsParser = {
2406
+ id: "github-actions",
2407
+ patterns: [".github/workflows/*.{yml,yaml}"],
2408
+
2409
+ /**
2410
+ * @param {string[]} files Matched workflow file paths
2411
+ * @param {Object} options CLI options
2412
+ * @returns {{ workflows: Object[], components: Object[], services: Object[], properties: Object[], dependencies: Object[] }}
2413
+ */
2414
+ parse(files, options) {
2415
+ const workflows = [];
2416
+ const components = [];
2417
+ const dependencies = [];
2418
+
2419
+ for (const f of files) {
2420
+ const result = parseWorkflowFile(f, options);
2421
+ workflows.push(...result.workflows);
2422
+ components.push(...result.components);
2423
+ dependencies.push(...result.dependencies);
2424
+ }
2425
+ enrichLocalDispatchRelationships(workflows, components);
2426
+ return {
2427
+ workflows,
2428
+ components,
2429
+ services: [],
2430
+ properties: [],
2431
+ dependencies,
2432
+ };
2433
+ },
2434
+ };