sbom 0.1.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.
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbom
4
+ module Data
5
+ class Relationship
6
+ attr_accessor :source, :target, :relationship_type,
7
+ :source_id, :target_id,
8
+ :source_type, :target_type
9
+
10
+ def initialize(source: nil, target: nil, relationship_type: nil)
11
+ @source = source
12
+ @target = target
13
+ @relationship_type = relationship_type&.strip
14
+ @source_id = nil
15
+ @target_id = nil
16
+ @source_type = nil
17
+ @target_type = nil
18
+ end
19
+
20
+ def reset!
21
+ @source = nil
22
+ @target = nil
23
+ @relationship_type = nil
24
+ @source_id = nil
25
+ @target_id = nil
26
+ @source_type = nil
27
+ @target_type = nil
28
+ end
29
+
30
+ def to_h
31
+ {
32
+ source: @source,
33
+ target: @target,
34
+ type: @relationship_type,
35
+ source_id: @source_id,
36
+ target_id: @target_id,
37
+ source_type: @source_type,
38
+ target_type: @target_type
39
+ }.compact
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbom
4
+ module Data
5
+ class Sbom
6
+ attr_accessor :sbom_type, :version, :uuid, :bom_version
7
+
8
+ def initialize(sbom_type: :auto)
9
+ @sbom_type = sbom_type
10
+ @document = nil
11
+ @files = {}
12
+ @packages = {}
13
+ @relationships = []
14
+ @licenses = []
15
+ @annotations = []
16
+ @properties = []
17
+ end
18
+
19
+ def document
20
+ @document
21
+ end
22
+
23
+ def document=(doc)
24
+ @document = doc.is_a?(Hash) ? doc : doc&.to_h
25
+ end
26
+
27
+ def add_document(doc)
28
+ @document = doc.is_a?(Hash) ? doc : doc&.to_h
29
+ end
30
+
31
+ def files
32
+ @files.values
33
+ end
34
+
35
+ def add_file(file)
36
+ data = file.is_a?(Hash) ? file : file.to_h
37
+ key = data[:name]
38
+ @files[key] = data if key
39
+ end
40
+
41
+ def add_files(files_hash)
42
+ @files.merge!(files_hash) if files_hash.is_a?(Hash) && files_hash.any?
43
+ end
44
+
45
+ def packages
46
+ @packages.values
47
+ end
48
+
49
+ def add_package(package)
50
+ data = package.is_a?(Hash) ? package : package.to_h
51
+ key = [data[:name], data[:version]]
52
+ @packages[key] = data if data[:name]
53
+ end
54
+
55
+ def add_packages(packages_hash)
56
+ @packages.merge!(packages_hash) if packages_hash.is_a?(Hash) && packages_hash.any?
57
+ end
58
+
59
+ def relationships
60
+ @relationships
61
+ end
62
+
63
+ def add_relationship(relationship)
64
+ data = relationship.is_a?(Hash) ? relationship : relationship.to_h
65
+ @relationships << data
66
+ end
67
+
68
+ def add_relationships(relationships_list)
69
+ @relationships.concat(relationships_list) if relationships_list.is_a?(Array)
70
+ end
71
+
72
+ def licenses
73
+ @licenses
74
+ end
75
+
76
+ def add_license(license)
77
+ @licenses << license
78
+ end
79
+
80
+ def add_licenses(licenses_list)
81
+ @licenses.concat(licenses_list) if licenses_list.is_a?(Array)
82
+ end
83
+
84
+ def annotations
85
+ @annotations
86
+ end
87
+
88
+ def add_annotation(annotation)
89
+ @annotations << annotation
90
+ end
91
+
92
+ def add_annotations(annotations_list)
93
+ @annotations.concat(annotations_list) if annotations_list.is_a?(Array)
94
+ end
95
+
96
+ def add_property(name, value)
97
+ @properties << [name.strip, value]
98
+ end
99
+
100
+ def properties
101
+ @properties
102
+ end
103
+
104
+ def to_h
105
+ result = {
106
+ type: @sbom_type,
107
+ version: @version,
108
+ uuid: @uuid,
109
+ bom_version: @bom_version
110
+ }
111
+
112
+ result[:document] = @document if @document
113
+ result[:files] = @files if @files.any?
114
+ result[:packages] = @packages if @packages.any?
115
+ result[:relationships] = @relationships if @relationships.any?
116
+ result[:licenses] = @licenses if @licenses.any?
117
+ result[:annotations] = @annotations if @annotations.any?
118
+ result[:properties] = @properties if @properties.any?
119
+
120
+ result.compact
121
+ end
122
+ end
123
+ end
124
+ end
data/lib/sbom/error.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbom
4
+ class Error < StandardError; end
5
+
6
+ class ParserError < Error; end
7
+
8
+ class GeneratorError < Error; end
9
+
10
+ class ValidatorError < Error; end
11
+
12
+ class UnsupportedFormatError < Error; end
13
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbom
4
+ class Generator
5
+ VALID_FORMATS = %i[tag json yaml].freeze
6
+ VALID_TYPES = %i[spdx cyclonedx].freeze
7
+
8
+ def initialize(sbom_type: :spdx, format: :json, application: "sbom", version: Sbom::VERSION)
9
+ @sbom_type = validate_type(sbom_type)
10
+ @format = validate_format(format, @sbom_type)
11
+ @application = application
12
+ @version = version
13
+ @generator = create_generator
14
+ end
15
+
16
+ def generate(project_name, sbom_data)
17
+ @generator.generate(project_name, sbom_data)
18
+ end
19
+
20
+ def output
21
+ @generator.output
22
+ end
23
+
24
+ def to_h
25
+ @generator.to_h
26
+ end
27
+
28
+ def sbom_type
29
+ @sbom_type
30
+ end
31
+
32
+ def format
33
+ @format
34
+ end
35
+
36
+ def self.generate(project_name, sbom_data, sbom_type: :spdx, format: :json)
37
+ gen = new(sbom_type: sbom_type, format: format)
38
+ gen.generate(project_name, sbom_data)
39
+ gen
40
+ end
41
+
42
+ private
43
+
44
+ def validate_type(type)
45
+ type_sym = type.to_s.downcase.to_sym
46
+ return type_sym if VALID_TYPES.include?(type_sym)
47
+
48
+ :spdx
49
+ end
50
+
51
+ def validate_format(format, sbom_type)
52
+ format_sym = format.to_s.downcase.to_sym
53
+
54
+ if sbom_type == :cyclonedx
55
+ return :json
56
+ end
57
+
58
+ return format_sym if VALID_FORMATS.include?(format_sym)
59
+
60
+ :json
61
+ end
62
+
63
+ def create_generator
64
+ if @sbom_type == :cyclonedx
65
+ Cyclonedx::Generator.new(
66
+ format: @format,
67
+ application: @application,
68
+ version: @version
69
+ )
70
+ else
71
+ Spdx::Generator.new(
72
+ format: @format,
73
+ application: @application,
74
+ version: @version
75
+ )
76
+ end
77
+ end
78
+ end
79
+ end