sbom 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +9 -0
- data/README.md +7 -0
- data/lib/sbom/cyclonedx/generator.rb +76 -0
- data/lib/sbom/version.rb +1 -1
- data/spec/cyclonedx/schema/bom-1.2-strict.schema.json +1029 -0
- data/spec/cyclonedx/schema/bom-1.2.schema.json +1001 -0
- data/spec/cyclonedx/schema/bom-1.3-strict.schema.json +1089 -0
- data/spec/cyclonedx/schema/bom-1.3.schema.json +1058 -0
- data/spec/cyclonedx/schema/bom-1.4.schema.json +1697 -0
- data/spec/cyclonedx/schema/bom-1.5.schema.json +3799 -0
- data/spec/cyclonedx/schema/bom-1.6.schema.json +5699 -0
- data/spec/cyclonedx/schema/bom-1.7.schema.json +6700 -0
- data/spec/spdx/schemas/spdx-schema.json +760 -0
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 91a2d7468e5e306cb02358a3d4c55d5169cb54e1b022d9ef1cd99f9795713b27
|
|
4
|
+
data.tar.gz: 6bc9e80848847c7f9cd535acc4b2747f03e6e944982da35c1b5bcfcad9a55c99
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30b94e777404ed7bf30f3a4f4911079e391a1c51a046175a31a1333b4635a7e4aa16d52d85ff9ccbbc3ecbee29326b89cbd84e78eabb2a4b38a38e42731cddec
|
|
7
|
+
data.tar.gz: f6ee5ca68429f3bce881b7213e92fab8e030182ecf0cbdffa8ee94799d32cf6ef87c91b9bff589ed99e0792313c826eb8db24355ec7b55637335fc85ea1a2492
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.0.
|
|
1
|
+
4.0.5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-06-26
|
|
4
|
+
|
|
5
|
+
- CycloneDX generator: support `analysis` on vulnerabilities (`state`, `justification`, `response`, `detail`, `firstIssued`, `lastUpdated`)
|
|
6
|
+
- CycloneDX generator: support `pedigree` on components (`patches` with `type`/`diff`/`resolves`, and `notes`)
|
|
7
|
+
|
|
8
|
+
## [0.4.1] - 2026-01-14
|
|
9
|
+
|
|
10
|
+
- Include CycloneDX and SPDX schema files in published gem
|
|
11
|
+
|
|
3
12
|
## [0.4.0] - 2026-01-08
|
|
4
13
|
|
|
5
14
|
- Add CycloneDX vulnerabilities array support to generator
|
data/README.md
CHANGED
|
@@ -63,6 +63,7 @@ data = {
|
|
|
63
63
|
ratings: [{ severity: "high", score: 8.1, method: "CVSSv31" }],
|
|
64
64
|
description: "A critical vulnerability",
|
|
65
65
|
affects: [{ ref: "pkg:npm/lodash@4.17.20" }],
|
|
66
|
+
analysis: { state: "resolved", detail: "Patched by distro" },
|
|
66
67
|
published: "2024-01-15T00:00:00Z",
|
|
67
68
|
updated: "2024-01-20T12:00:00Z"
|
|
68
69
|
}
|
|
@@ -131,6 +132,12 @@ package.version = "7.0.0"
|
|
|
131
132
|
package.license_concluded = "MIT"
|
|
132
133
|
package.add_checksum("SHA256", "abc123...")
|
|
133
134
|
|
|
135
|
+
# Go modules use base64-encoded hashes in go.sum - convert to hex first:
|
|
136
|
+
require "base64"
|
|
137
|
+
go_hash = "h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4="
|
|
138
|
+
hex = Base64.decode64(go_hash.sub(/^h1:/, "")).unpack1("H*")
|
|
139
|
+
package.add_checksum("SHA256", hex)
|
|
140
|
+
|
|
134
141
|
# Generate a PURL
|
|
135
142
|
package.generate_purl(type: "gem")
|
|
136
143
|
# => "pkg:gem/rails@7.0.0"
|
|
@@ -207,9 +207,68 @@ module Sbom
|
|
|
207
207
|
end
|
|
208
208
|
end
|
|
209
209
|
|
|
210
|
+
pedigree = generate_pedigree(pkg[:pedigree])
|
|
211
|
+
component["pedigree"] = pedigree if pedigree
|
|
212
|
+
|
|
210
213
|
@components << component
|
|
211
214
|
end
|
|
212
215
|
|
|
216
|
+
def generate_pedigree(pedigree)
|
|
217
|
+
return nil unless pedigree
|
|
218
|
+
|
|
219
|
+
result = {}
|
|
220
|
+
|
|
221
|
+
if pedigree[:patches]&.any?
|
|
222
|
+
patches = pedigree[:patches].map { |p| generate_pedigree_patch(p) }.compact
|
|
223
|
+
result["patches"] = patches if patches.any?
|
|
224
|
+
end
|
|
225
|
+
result["notes"] = pedigree[:notes] if pedigree[:notes]
|
|
226
|
+
|
|
227
|
+
result.empty? ? nil : result
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def generate_pedigree_patch(patch)
|
|
231
|
+
# CycloneDX requires `type` on patch objects; drop entries without one
|
|
232
|
+
# rather than emit `{}` or an empty-string type that fails validation.
|
|
233
|
+
return nil unless patch && patch[:type]
|
|
234
|
+
|
|
235
|
+
result = { "type" => patch[:type].to_s }
|
|
236
|
+
|
|
237
|
+
if patch[:diff]
|
|
238
|
+
diff = {}
|
|
239
|
+
diff["text"] = patch[:diff][:text] if patch[:diff][:text]
|
|
240
|
+
diff["url"] = patch[:diff][:url] if patch[:diff][:url]
|
|
241
|
+
result["diff"] = diff if diff.any?
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
if patch[:resolves]&.any?
|
|
245
|
+
resolves = patch[:resolves].map { |i| generate_issue(i) }.compact
|
|
246
|
+
result["resolves"] = resolves if resolves.any?
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
result
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def generate_issue(issue)
|
|
253
|
+
# `type` is required on CycloneDX issue objects.
|
|
254
|
+
return nil unless issue && issue[:type]
|
|
255
|
+
|
|
256
|
+
result = { "type" => issue[:type].to_s }
|
|
257
|
+
result["id"] = issue[:id] if issue[:id]
|
|
258
|
+
result["name"] = issue[:name] if issue[:name]
|
|
259
|
+
result["description"] = issue[:description] if issue[:description]
|
|
260
|
+
|
|
261
|
+
if issue[:source]
|
|
262
|
+
source = {}
|
|
263
|
+
source["name"] = issue[:source][:name] if issue[:source][:name]
|
|
264
|
+
source["url"] = issue[:source][:url] if issue[:source][:url]
|
|
265
|
+
result["source"] = source if source.any?
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
result["references"] = Array(issue[:references]) if issue[:references]
|
|
269
|
+
result
|
|
270
|
+
end
|
|
271
|
+
|
|
213
272
|
def generate_dependencies(relationships_data)
|
|
214
273
|
return unless relationships_data&.any?
|
|
215
274
|
|
|
@@ -274,12 +333,29 @@ module Sbom
|
|
|
274
333
|
end
|
|
275
334
|
end
|
|
276
335
|
|
|
336
|
+
analysis = generate_analysis(vuln[:analysis])
|
|
337
|
+
vulnerability["analysis"] = analysis if analysis
|
|
338
|
+
|
|
277
339
|
vulnerability["published"] = vuln[:published] if vuln[:published]
|
|
278
340
|
vulnerability["updated"] = vuln[:updated] if vuln[:updated]
|
|
279
341
|
|
|
280
342
|
@vulnerabilities << vulnerability
|
|
281
343
|
end
|
|
282
344
|
|
|
345
|
+
def generate_analysis(analysis)
|
|
346
|
+
return nil unless analysis
|
|
347
|
+
|
|
348
|
+
result = {}
|
|
349
|
+
result["state"] = analysis[:state] if analysis[:state]
|
|
350
|
+
result["justification"] = analysis[:justification] if analysis[:justification]
|
|
351
|
+
result["response"] = Array(analysis[:response]) if analysis[:response]
|
|
352
|
+
result["detail"] = analysis[:detail] if analysis[:detail]
|
|
353
|
+
result["firstIssued"] = analysis[:first_issued] if analysis[:first_issued]
|
|
354
|
+
result["lastUpdated"] = analysis[:last_updated] if analysis[:last_updated]
|
|
355
|
+
|
|
356
|
+
result.empty? ? nil : result
|
|
357
|
+
end
|
|
358
|
+
|
|
283
359
|
def finalize_output
|
|
284
360
|
@output["components"] = @components if @components.any?
|
|
285
361
|
@output["dependencies"] = @dependencies if @dependencies.any?
|
data/lib/sbom/version.rb
CHANGED