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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea09b1deb0550d9a03da739b170da712b89c73415462752f51cb133c43639978
4
- data.tar.gz: '019af2723634da6944d51280f8b8fb9b3bd8155135d01ad1464a102b1efc31a1'
3
+ metadata.gz: 91a2d7468e5e306cb02358a3d4c55d5169cb54e1b022d9ef1cd99f9795713b27
4
+ data.tar.gz: 6bc9e80848847c7f9cd535acc4b2747f03e6e944982da35c1b5bcfcad9a55c99
5
5
  SHA512:
6
- metadata.gz: dd10cb7772869ca0e7a22f60668cdaa76b5fcdd5dabf938894078c3a0936f2ad7897b0cf00487d47b1b191815025c2c722007d7a6a77d03e2d788a42388c6c89
7
- data.tar.gz: 4696e6a8d0bebdcb97f8022e9a4c25f52f5e7930fa040391432e2e28bf2ef013b6c1c1d76bf4931e7fb69605a74cf457db76be92eaea2cc76a7a63b5ccac8159
6
+ metadata.gz: 30b94e777404ed7bf30f3a4f4911079e391a1c51a046175a31a1333b4635a7e4aa16d52d85ff9ccbbc3ecbee29326b89cbd84e78eabb2a4b38a38e42731cddec
7
+ data.tar.gz: f6ee5ca68429f3bce881b7213e92fab8e030182ecf0cbdffa8ee94799d32cf6ef87c91b9bff589ed99e0792313c826eb8db24355ec7b55637335fc85ea1a2492
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 4.0.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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sbom
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -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 staring with 'urn:cdx:'"
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 plan 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).",
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 staring with 'urn:cdx:'"
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 plan 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).",
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.1
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.3
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: []