sbom 0.4.1 → 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 +5 -0
- data/README.md +1 -0
- data/lib/sbom/cyclonedx/generator.rb +76 -0
- data/lib/sbom/version.rb +1 -1
- data/spec/cyclonedx/schema/bom-1.6.schema.json +3 -3
- data/spec/cyclonedx/schema/bom-1.7.schema.json +3 -3
- data/spec/spdx/schemas/spdx-schema.json +20 -10
- metadata +2 -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,10 @@
|
|
|
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
|
+
|
|
3
8
|
## [0.4.1] - 2026-01-14
|
|
4
9
|
|
|
5
10
|
- Include CycloneDX and SPDX schema files in published gem
|
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
|
}
|
|
@@ -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
|
@@ -536,7 +536,7 @@
|
|
|
536
536
|
"description": "Identifier for referable and therefore interlinkable elements.\nValue SHOULD not start with the BOM-Link intro 'urn:cdx:' to avoid conflicts with BOM-Links.",
|
|
537
537
|
"type": "string",
|
|
538
538
|
"minLength": 1,
|
|
539
|
-
"$comment": "TODO (breaking change): add a format constraint that prevents the value from
|
|
539
|
+
"$comment": "TODO (breaking change): add a format constraint that prevents the value from starting with 'urn:cdx:'"
|
|
540
540
|
},
|
|
541
541
|
"refLinkType": {
|
|
542
542
|
"description": "Descriptor for an element identified by the attribute 'bom-ref' in the same BOM document.\nIn contrast to `bomLinkElementType`.",
|
|
@@ -1161,7 +1161,7 @@
|
|
|
1161
1161
|
"contentType": {
|
|
1162
1162
|
"type": "string",
|
|
1163
1163
|
"title": "Content-Type",
|
|
1164
|
-
"description": "Specifies the format and nature of the data being attached, helping systems correctly interpret and process the content. Common content type examples include `application/json` for JSON data and `text/plain` for
|
|
1164
|
+
"description": "Specifies the format and nature of the data being attached, helping systems correctly interpret and process the content. Common content type examples include `application/json` for JSON data and `text/plain` for plain text documents.\n [RFC 2045 section 5.1](https://www.ietf.org/rfc/rfc2045.html#section-5.1) outlines the structure and use of content types. For a comprehensive list of registered content types, refer to the [IANA media types registry](https://www.iana.org/assignments/media-types/media-types.xhtml).",
|
|
1165
1165
|
"default": "text/plain",
|
|
1166
1166
|
"examples": [
|
|
1167
1167
|
"text/plain",
|
|
@@ -2681,7 +2681,7 @@
|
|
|
2681
2681
|
"ratings": {
|
|
2682
2682
|
"type": "array",
|
|
2683
2683
|
"title": "Ratings",
|
|
2684
|
-
"description": "List of vulnerability ratings",
|
|
2684
|
+
"description": "List of vulnerability ratings. Consumers SHOULD consider ratings in prioritization decisions; source ratings may differ and aid prioritization.",
|
|
2685
2685
|
"items": {
|
|
2686
2686
|
"$ref": "#/definitions/rating"
|
|
2687
2687
|
}
|
|
@@ -555,7 +555,7 @@
|
|
|
555
555
|
"description": "Identifier for referable and therefore interlinkable elements.\nValue SHOULD not start with the BOM-Link intro 'urn:cdx:' to avoid conflicts with BOM-Links.",
|
|
556
556
|
"type": "string",
|
|
557
557
|
"minLength": 1,
|
|
558
|
-
"$comment": "TODO (breaking change): add a format constraint that prevents the value from
|
|
558
|
+
"$comment": "TODO (breaking change): add a format constraint that prevents the value from starting with 'urn:cdx:'"
|
|
559
559
|
},
|
|
560
560
|
"refLinkType": {
|
|
561
561
|
"title": "BOM Reference",
|
|
@@ -1248,7 +1248,7 @@
|
|
|
1248
1248
|
"contentType": {
|
|
1249
1249
|
"type": "string",
|
|
1250
1250
|
"title": "Content-Type",
|
|
1251
|
-
"description": "Specifies the format and nature of the data being attached, helping systems correctly interpret and process the content. Common content type examples include `application/json` for JSON data and `text/plain` for
|
|
1251
|
+
"description": "Specifies the format and nature of the data being attached, helping systems correctly interpret and process the content. Common content type examples include `application/json` for JSON data and `text/plain` for plain text documents.\n [RFC 2045 section 5.1](https://www.ietf.org/rfc/rfc2045.html#section-5.1) outlines the structure and use of content types. For a comprehensive list of registered content types, refer to the [IANA media types registry](https://www.iana.org/assignments/media-types/media-types.xhtml).",
|
|
1252
1252
|
"default": "text/plain",
|
|
1253
1253
|
"examples": [
|
|
1254
1254
|
"text/plain",
|
|
@@ -2841,7 +2841,7 @@
|
|
|
2841
2841
|
"ratings": {
|
|
2842
2842
|
"type": "array",
|
|
2843
2843
|
"title": "Ratings",
|
|
2844
|
-
"description": "List of vulnerability ratings",
|
|
2844
|
+
"description": "List of vulnerability ratings. Consumers SHOULD consider ratings in prioritization decisions; source ratings may differ and aid prioritization.",
|
|
2845
2845
|
"items": {
|
|
2846
2846
|
"$ref": "#/definitions/rating"
|
|
2847
2847
|
}
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"properties" : {
|
|
21
21
|
"annotationDate" : {
|
|
22
22
|
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
|
|
23
|
-
"type" : "string"
|
|
23
|
+
"type" : "string",
|
|
24
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
24
25
|
},
|
|
25
26
|
"annotationType" : {
|
|
26
27
|
"description" : "Type of the annotation.",
|
|
@@ -51,7 +52,8 @@
|
|
|
51
52
|
},
|
|
52
53
|
"created" : {
|
|
53
54
|
"description" : "Identify when the SPDX document was originally created. The date is to be specified according to combined date and time in UTC format as specified in ISO 8601 standard.",
|
|
54
|
-
"type" : "string"
|
|
55
|
+
"type" : "string",
|
|
56
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
55
57
|
},
|
|
56
58
|
"creators" : {
|
|
57
59
|
"description" : "Identify who (or what, in the case of a tool) created the SPDX document. If the SPDX document was created by an individual, indicate the person's name. If the SPDX document was created on behalf of a company or organization, indicate the entity name. If the SPDX document was created using a software tool, indicate the name and version for that tool. If multiple participants or tools were involved, use multiple instances of this field. Person name or organization name may be designated as “anonymous” if appropriate.",
|
|
@@ -149,7 +151,8 @@
|
|
|
149
151
|
},
|
|
150
152
|
"timestamp" : {
|
|
151
153
|
"description" : "Timestamp",
|
|
152
|
-
"type" : "string"
|
|
154
|
+
"type" : "string",
|
|
155
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
153
156
|
},
|
|
154
157
|
"url" : {
|
|
155
158
|
"description" : "URL Reference",
|
|
@@ -201,7 +204,8 @@
|
|
|
201
204
|
},
|
|
202
205
|
"reviewDate" : {
|
|
203
206
|
"description" : "The date and time at which the SpdxDocument was reviewed. This value must be in UTC and have 'Z' as its timezone indicator.",
|
|
204
|
-
"type" : "string"
|
|
207
|
+
"type" : "string",
|
|
208
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
205
209
|
},
|
|
206
210
|
"reviewer" : {
|
|
207
211
|
"description" : "The name and, optionally, contact information of the person who performed the review. Values of this property must conform to the agent and tool syntax. The reviewer property is deprecated in favor of Annotation with an annotationType review.",
|
|
@@ -249,7 +253,8 @@
|
|
|
249
253
|
"properties" : {
|
|
250
254
|
"annotationDate" : {
|
|
251
255
|
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
|
|
252
|
-
"type" : "string"
|
|
256
|
+
"type" : "string",
|
|
257
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
253
258
|
},
|
|
254
259
|
"annotationType" : {
|
|
255
260
|
"description" : "Type of the annotation.",
|
|
@@ -279,7 +284,8 @@
|
|
|
279
284
|
},
|
|
280
285
|
"builtDate" : {
|
|
281
286
|
"description" : "This field provides a place for recording the actual date the package was built.",
|
|
282
|
-
"type" : "string"
|
|
287
|
+
"type" : "string",
|
|
288
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
283
289
|
},
|
|
284
290
|
"checksums" : {
|
|
285
291
|
"description" : "The checksum property provides a mechanism that can be used to verify that the contents of a File or Package have not changed.",
|
|
@@ -421,7 +427,8 @@
|
|
|
421
427
|
},
|
|
422
428
|
"releaseDate" : {
|
|
423
429
|
"description" : "This field provides a place for recording the date the package was released.",
|
|
424
|
-
"type" : "string"
|
|
430
|
+
"type" : "string",
|
|
431
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
425
432
|
},
|
|
426
433
|
"sourceInfo" : {
|
|
427
434
|
"description" : "Allows the producer(s) of the SPDX document to describe how the package was acquired and/or changed from the original source.",
|
|
@@ -437,7 +444,8 @@
|
|
|
437
444
|
},
|
|
438
445
|
"validUntilDate" : {
|
|
439
446
|
"description" : "This field provides a place for recording the end of the support period for a package from the supplier.",
|
|
440
|
-
"type" : "string"
|
|
447
|
+
"type" : "string",
|
|
448
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
441
449
|
},
|
|
442
450
|
"versionInfo" : {
|
|
443
451
|
"description" : "Provides an indication of the version of the package that is described by this SpdxDocument.",
|
|
@@ -466,7 +474,8 @@
|
|
|
466
474
|
"properties" : {
|
|
467
475
|
"annotationDate" : {
|
|
468
476
|
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
|
|
469
|
-
"type" : "string"
|
|
477
|
+
"type" : "string",
|
|
478
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
470
479
|
},
|
|
471
480
|
"annotationType" : {
|
|
472
481
|
"description" : "Type of the annotation.",
|
|
@@ -603,7 +612,8 @@
|
|
|
603
612
|
"properties" : {
|
|
604
613
|
"annotationDate" : {
|
|
605
614
|
"description" : "Identify when the comment was made. This is to be specified according to the combined date and time in the UTC format, as specified in the ISO 8601 standard.",
|
|
606
|
-
"type" : "string"
|
|
615
|
+
"type" : "string",
|
|
616
|
+
"pattern" : "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]|23:59:60)Z$"
|
|
607
617
|
},
|
|
608
618
|
"annotationType" : {
|
|
609
619
|
"description" : "Type of the annotation.",
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sbom
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Nesbitt
|
|
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '0'
|
|
125
125
|
requirements: []
|
|
126
|
-
rubygems_version: 4.0.
|
|
126
|
+
rubygems_version: 4.0.12
|
|
127
127
|
specification_version: 4
|
|
128
128
|
summary: Parse, generate, and validate Software Bill of Materials (SBOM)
|
|
129
129
|
test_files: []
|