cyclonedx-cocoapods 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/cyclonedx/cocoapods/bom_builder.rb +33 -11
- data/lib/cyclonedx/cocoapods/cli_runner.rb +24 -11
- data/lib/cyclonedx/cocoapods/component.rb +6 -1
- data/lib/cyclonedx/cocoapods/podfile_analyzer.rb +35 -13
- data/lib/cyclonedx/cocoapods/version.rb +1 -1
- metadata +4 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84ed77501efec7ca77fce507dd1dbc4a29ffb4b8cf45fc6b942eafe3901af95a
|
4
|
+
data.tar.gz: 85204bb25786de11c3dc7ec302d016431ebecd7078149081a6b294ba65f756aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f4b84eb0a11f7f6488fe9fccef7806e786db41ea647806046b729b39952172175df7b8884b17c60e5cac0b246a9bfc6e56d8e53f69b3ad9521c9cde0f19726b
|
7
|
+
data.tar.gz: f719564347931af554dbc2705022a548405bbd95320db5c094f5616166a46ecd830d8fddedcaebd9e24fd76ff6e8be2e1917d3a3be8bc6ede3f21e77e763af77
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [1.4.1]
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- Minimum Ruby version is now v2.6.3 so the [Array.union](https://apidock.com/ruby/v2_6_3/Array/union) function can be used.
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
- Improved performance when analyzing a Podfile with many pods. ([Issue #78](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/78)) [@macblazer](https://github.com/macblazer).
|
14
|
+
|
15
|
+
## [1.4.0]
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- Added `evidence` element to the component output to indicate that we are doing manifest analysis to generate the bom. ([Issue #69](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/69)) [@macblazer](https://github.com/macblazer).
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- Added top level dependencies when the metadata/component is specified (by using the `--name`, `--version`, and `--type` parameters). ([PR #70](https://github.com/CycloneDX/cyclonedx-cocoapods/pull/70)) [@fnxpt](https://github.com/fnxpt)
|
22
|
+
- Properly concatenate paths to Podfile and Podfile.lock (with unit tests!). ([Issue #71](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/71)) [@macblazer](https://github.com/macblazer).
|
23
|
+
|
7
24
|
## [1.3.0]
|
8
25
|
|
9
26
|
### Added
|
@@ -104,10 +104,28 @@ module CycloneDX
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
|
107
|
+
# Add evidence of the purl identity.
|
108
|
+
# See https://github.com/CycloneDX/guides/blob/main/SBOM/en/0x60-Evidence.md for more info
|
109
|
+
def xml_add_evidence(xml, manifest_path)
|
110
|
+
xml.evidence do
|
111
|
+
xml.identity do
|
112
|
+
xml.field 'purl'
|
113
|
+
xml.confidence '0.6'
|
114
|
+
xml.methods_ do
|
115
|
+
xml.method_ do
|
116
|
+
xml.technique 'manifest-analysis'
|
117
|
+
xml.confidence '0.6'
|
118
|
+
xml.value manifest_path
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_to_bom(xml, manifest_path, trim_strings_length = 0)
|
108
126
|
xml.component(type: 'library', 'bom-ref': purl) do
|
109
127
|
xml_add_author(xml, trim_strings_length)
|
110
|
-
xml.
|
128
|
+
xml.name_ name
|
111
129
|
xml.version version.to_s
|
112
130
|
xml.description { xml.cdata description } unless description.nil?
|
113
131
|
unless checksum.nil?
|
@@ -126,6 +144,8 @@ module CycloneDX
|
|
126
144
|
xml.purl purl.slice(0, trim_strings_length)
|
127
145
|
end
|
128
146
|
xml_add_homepage(xml)
|
147
|
+
|
148
|
+
xml_add_evidence(xml, manifest_path)
|
129
149
|
end
|
130
150
|
end
|
131
151
|
|
@@ -133,7 +153,7 @@ module CycloneDX
|
|
133
153
|
def add_to_bom(xml)
|
134
154
|
xml.license do
|
135
155
|
xml.id identifier if identifier_type == :id
|
136
|
-
xml.
|
156
|
+
xml.name_ identifier if identifier_type == :name
|
137
157
|
xml.text_ text unless text.nil?
|
138
158
|
xml.url url unless url.nil?
|
139
159
|
end
|
@@ -143,21 +163,23 @@ module CycloneDX
|
|
143
163
|
|
144
164
|
class Component
|
145
165
|
def add_to_bom(xml)
|
146
|
-
xml.component(type: type) do
|
166
|
+
xml.component(type: type, 'bom-ref': bomref) do
|
147
167
|
xml.group group unless group.nil?
|
148
|
-
xml.
|
168
|
+
xml.name_ name
|
149
169
|
xml.version version
|
150
170
|
end
|
151
171
|
end
|
152
172
|
end
|
153
173
|
|
174
|
+
# Turns the internal model data into an XML bom.
|
154
175
|
class BOMBuilder
|
155
176
|
NAMESPACE = 'http://cyclonedx.org/schema/bom/1.5'
|
156
177
|
|
157
|
-
attr_reader :component, :pods, :dependencies
|
178
|
+
attr_reader :component, :pods, :manifest_path, :dependencies
|
158
179
|
|
159
|
-
def initialize(pods:, component: nil, dependencies: nil)
|
180
|
+
def initialize(pods:, manifest_path:, component: nil, dependencies: nil)
|
160
181
|
@pods = pods.sort_by(&:purl)
|
182
|
+
@manifest_path = manifest_path
|
161
183
|
@component = component
|
162
184
|
@dependencies = dependencies&.sort
|
163
185
|
end
|
@@ -184,17 +206,17 @@ module CycloneDX
|
|
184
206
|
xml.bom(xmlns: NAMESPACE, version: version.to_i.to_s, serialNumber: "urn:uuid:#{SecureRandom.uuid}") do
|
185
207
|
bom_metadata(xml)
|
186
208
|
|
187
|
-
bom_components(xml, pods, trim_strings_length)
|
209
|
+
bom_components(xml, pods, manifest_path, trim_strings_length)
|
188
210
|
|
189
211
|
bom_dependencies(xml, dependencies)
|
190
212
|
end
|
191
213
|
end.to_xml
|
192
214
|
end
|
193
215
|
|
194
|
-
def bom_components(xml, pods, trim_strings_length)
|
216
|
+
def bom_components(xml, pods, manifest_path, trim_strings_length)
|
195
217
|
xml.components do
|
196
218
|
pods.each do |pod|
|
197
|
-
pod.add_to_bom(xml, trim_strings_length)
|
219
|
+
pod.add_to_bom(xml, manifest_path, trim_strings_length)
|
198
220
|
end
|
199
221
|
end
|
200
222
|
end
|
@@ -223,7 +245,7 @@ module CycloneDX
|
|
223
245
|
xml.tools do
|
224
246
|
xml.tool do
|
225
247
|
xml.vendor 'CycloneDX'
|
226
|
-
xml.
|
248
|
+
xml.name_ 'cyclonedx-cocoapods'
|
227
249
|
xml.version VERSION
|
228
250
|
end
|
229
251
|
end
|
@@ -39,9 +39,9 @@ module CycloneDX
|
|
39
39
|
setup_logger(verbose: options[:verbose])
|
40
40
|
@logger.debug "Running cyclonedx-cocoapods with options: #{options}"
|
41
41
|
|
42
|
-
pods, dependencies = analyze(options)
|
42
|
+
component, pods, manifest_path, dependencies = analyze(options)
|
43
43
|
|
44
|
-
build_and_write_bom(options, pods, dependencies)
|
44
|
+
build_and_write_bom(options, component, pods, manifest_path, dependencies)
|
45
45
|
rescue StandardError => e
|
46
46
|
@logger.error ([e.message] + e.backtrace).join($INPUT_RECORD_SEPARATOR)
|
47
47
|
exit 1
|
@@ -100,12 +100,10 @@ module CycloneDX
|
|
100
100
|
parsed_options[:name] = name
|
101
101
|
end
|
102
102
|
options.on('-v', '--version version', 'Version of the component for which the BOM is generated') do |version|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
raise OptionParser::InvalidArgument, e.message
|
108
|
-
end
|
103
|
+
Gem::Version.new(version)
|
104
|
+
parsed_options[:version] = version
|
105
|
+
rescue StandardError => e
|
106
|
+
raise OptionParser::InvalidArgument, e.message
|
109
107
|
end
|
110
108
|
options.on('-t', '--type type',
|
111
109
|
'Type of the component for which the BOM is generated ' \
|
@@ -136,11 +134,26 @@ module CycloneDX
|
|
136
134
|
pods, dependencies = analyzer.parse_pods(podfile, lockfile)
|
137
135
|
analyzer.populate_pods_with_additional_info(pods)
|
138
136
|
|
139
|
-
|
137
|
+
component = component_from_options(options)
|
138
|
+
|
139
|
+
unless component.nil?
|
140
|
+
# add top level pods to main component
|
141
|
+
top_deps = analyzer.top_level_deps(podfile, lockfile)
|
142
|
+
dependencies[component.bomref] = top_deps
|
143
|
+
end
|
144
|
+
|
145
|
+
manifest_path = lockfile.defined_in_file
|
146
|
+
if manifest_path.absolute?
|
147
|
+
# Use the folder that we are building in, then the path to the manifest file
|
148
|
+
manifest_path = Pathname.pwd.basename + manifest_path.relative_path_from(Pathname.pwd)
|
149
|
+
end
|
150
|
+
|
151
|
+
[component, pods, manifest_path, dependencies]
|
140
152
|
end
|
141
153
|
|
142
|
-
def build_and_write_bom(options, pods, dependencies)
|
143
|
-
builder = BOMBuilder.new(pods: pods,
|
154
|
+
def build_and_write_bom(options, component, pods, manifest_path, dependencies)
|
155
|
+
builder = BOMBuilder.new(pods: pods, manifest_path: manifest_path,
|
156
|
+
component: component, dependencies: dependencies)
|
144
157
|
bom = builder.bom(version: options[:bom_version] || 1,
|
145
158
|
trim_strings_length: options[:trim_strings_length] || 0)
|
146
159
|
write_bom_to_file(bom: bom, options: options)
|
@@ -24,7 +24,7 @@ module CycloneDX
|
|
24
24
|
class Component
|
25
25
|
VALID_COMPONENT_TYPES = %w[application framework library container operating-system device firmware file].freeze
|
26
26
|
|
27
|
-
attr_reader :group, :name, :version, :type
|
27
|
+
attr_reader :group, :name, :version, :type, :bomref
|
28
28
|
|
29
29
|
def initialize(name:, version:, type:, group: nil)
|
30
30
|
raise ArgumentError, 'Group, if specified, must be non empty' if !group.nil? && group.to_s.strip.empty?
|
@@ -39,6 +39,11 @@ module CycloneDX
|
|
39
39
|
@name = name
|
40
40
|
@version = version
|
41
41
|
@type = type
|
42
|
+
@bomref = "#{name}@#{version}"
|
43
|
+
|
44
|
+
return if group.nil?
|
45
|
+
|
46
|
+
@bomref = "#{group}/#{@bomref}"
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
@@ -74,6 +74,11 @@ module CycloneDX
|
|
74
74
|
pods
|
75
75
|
end
|
76
76
|
|
77
|
+
def top_level_deps(podfile, lockfile)
|
78
|
+
pods_used = top_level_pods(podfile)
|
79
|
+
dependencies_for_pod(pods_used, podfile, lockfile)
|
80
|
+
end
|
81
|
+
|
77
82
|
private
|
78
83
|
|
79
84
|
def load_plugins(podfile_path)
|
@@ -137,6 +142,8 @@ module CycloneDX
|
|
137
142
|
end
|
138
143
|
|
139
144
|
def initialize_cocoapods_config(project_dir)
|
145
|
+
# First, reset the ::Pod::Config instance in case we need to use this analyzer on multiple pods
|
146
|
+
::Pod::Config.instance = nil
|
140
147
|
::Pod::Config.instance.installation_root = project_dir
|
141
148
|
end
|
142
149
|
|
@@ -177,12 +184,18 @@ module CycloneDX
|
|
177
184
|
end
|
178
185
|
end
|
179
186
|
|
180
|
-
|
181
|
-
|
187
|
+
# Calculate simple array of all used pods plus their direct dependencies
|
188
|
+
#
|
189
|
+
# @param [Array<String>] top_level_pods List of pod names that are directly imported by the Podfile
|
190
|
+
# @param [Hash<String,Array<String>>] pods_cache Dependency information directly from the Podfile.lock;
|
191
|
+
# keys are string pod names, values are list of direct dependencies of the given pod.
|
192
|
+
# @return [Array<String>, Hash<String,Array<String>>] First element is list of all used pod names.
|
193
|
+
# Second element is a hash: keys are string pod names, values are the direct dependencies of that pod.
|
194
|
+
def append_all_pod_dependencies(top_level_pods, pods_cache)
|
195
|
+
result = top_level_pods
|
182
196
|
original_number = 0
|
183
|
-
dependencies_hash = {}
|
184
197
|
|
185
|
-
# Loop adding pod dependencies until we are not adding any more dependencies to the result
|
198
|
+
# Loop adding pod dependencies until we are not adding any more dependencies to the result.
|
186
199
|
# This brings in all the transitive dependencies of every top level pod.
|
187
200
|
# Note this also handles two edge cases:
|
188
201
|
# 1. Having a Podfile with no pods used.
|
@@ -190,29 +203,38 @@ module CycloneDX
|
|
190
203
|
while result.length != original_number
|
191
204
|
original_number = result.length
|
192
205
|
|
193
|
-
|
206
|
+
top_level_pods.each do |pod_name|
|
194
207
|
if pods_cache.key?(pod_name)
|
195
|
-
|
196
|
-
|
208
|
+
# Append all of the dependencies of this pod into the main list, if they aren't already in the list
|
209
|
+
result = result.union(pods_cache[pod_name])
|
197
210
|
end
|
198
211
|
end
|
199
212
|
|
200
|
-
|
201
|
-
|
213
|
+
top_level_pods = result
|
214
|
+
end
|
215
|
+
|
216
|
+
# Now that we have the simple list of all unique pods, grab their direct dependencies
|
217
|
+
dependencies_hash = {}
|
218
|
+
result.each do |pod_name|
|
219
|
+
dependencies_hash[pod_name] = pods_cache.key?(pod_name) ? pods_cache[pod_name] : []
|
202
220
|
end
|
203
221
|
|
204
222
|
[result, dependencies_hash]
|
205
223
|
end
|
206
224
|
|
207
|
-
def
|
208
|
-
pods_cache = simple_hash_of_lockfile_pods(lockfile)
|
209
|
-
|
225
|
+
def top_level_pods(podfile)
|
210
226
|
included_targets = podfile.target_definition_list.select { |target| include_target_named(target.label) }
|
211
227
|
included_target_names = included_targets.map(&:label)
|
212
228
|
@logger.debug "Including all pods for targets: #{included_target_names}"
|
213
229
|
|
214
230
|
top_level_deps = included_targets.map(&:dependencies).flatten.uniq
|
215
|
-
|
231
|
+
top_level_deps.map(&:name).uniq
|
232
|
+
end
|
233
|
+
|
234
|
+
def create_list_of_included_pods(podfile, lockfile)
|
235
|
+
pods_cache = simple_hash_of_lockfile_pods(lockfile)
|
236
|
+
|
237
|
+
pods_used = top_level_pods(podfile)
|
216
238
|
pods_used, dependencies = append_all_pod_dependencies(pods_used, pods_cache)
|
217
239
|
|
218
240
|
[pods_used.sort, dependencies]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cyclonedx-cocoapods
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- José González
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cocoapods
|
@@ -51,48 +51,6 @@ dependencies:
|
|
51
51
|
- - "<"
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '2.0'
|
54
|
-
- !ruby/object:Gem::Dependency
|
55
|
-
name: equivalent-xml
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: 0.6.0
|
61
|
-
type: :development
|
62
|
-
prerelease: false
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: 0.6.0
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
|
-
name: rake
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '13.0'
|
75
|
-
type: :development
|
76
|
-
prerelease: false
|
77
|
-
version_requirements: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - "~>"
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '13.0'
|
82
|
-
- !ruby/object:Gem::Dependency
|
83
|
-
name: rspec
|
84
|
-
requirement: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - "~>"
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '3.0'
|
89
|
-
type: :development
|
90
|
-
prerelease: false
|
91
|
-
version_requirements: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - "~>"
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '3.0'
|
96
54
|
description: CycloneDX is a lightweight software bill-of-material (SBOM) specification
|
97
55
|
designed for use in application security contexts and supply chain component analysis.
|
98
56
|
This Gem generates CycloneDX BOMs from CocoaPods projects.
|
@@ -133,14 +91,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
91
|
requirements:
|
134
92
|
- - ">="
|
135
93
|
- !ruby/object:Gem::Version
|
136
|
-
version: 2.
|
94
|
+
version: 2.6.3
|
137
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
96
|
requirements:
|
139
97
|
- - ">="
|
140
98
|
- !ruby/object:Gem::Version
|
141
99
|
version: '0'
|
142
100
|
requirements: []
|
143
|
-
rubygems_version: 3.5.
|
101
|
+
rubygems_version: 3.5.23
|
144
102
|
signing_key:
|
145
103
|
specification_version: 4
|
146
104
|
summary: CycloneDX software bill-of-material (SBOM) generation utility
|