cyclonedx-cocoapods 1.0.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 +7 -0
- data/CHANGELOG.md +21 -0
- data/LICENSE +201 -0
- data/NOTICE +5 -0
- data/README.md +92 -0
- data/exe/cyclonedx-cocoapods +23 -0
- data/lib/cyclonedx/cocoapods/bom_builder.rb +158 -0
- data/lib/cyclonedx/cocoapods/cli_runner.rb +224 -0
- data/lib/cyclonedx/cocoapods/component.rb +37 -0
- data/lib/cyclonedx/cocoapods/license.rb +44 -0
- data/lib/cyclonedx/cocoapods/pod.rb +108 -0
- data/lib/cyclonedx/cocoapods/pod_attributes.rb +72 -0
- data/lib/cyclonedx/cocoapods/source.rb +59 -0
- data/lib/cyclonedx/cocoapods/spdx-licenses.json +485 -0
- data/lib/cyclonedx/cocoapods/version.rb +29 -0
- metadata +132 -0
@@ -0,0 +1,224 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# This file is part of CycloneDX CocoaPods
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the “License”);
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an “AS IS” BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
# SPDX-License-Identifier: Apache-2.0
|
18
|
+
# Copyright (c) OWASP Foundation. All Rights Reserved.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'optparse'
|
22
|
+
require 'logger'
|
23
|
+
require 'cocoapods'
|
24
|
+
|
25
|
+
require_relative 'component'
|
26
|
+
require_relative 'pod'
|
27
|
+
require_relative 'pod_attributes'
|
28
|
+
require_relative 'source'
|
29
|
+
require_relative 'bom_builder'
|
30
|
+
|
31
|
+
module CycloneDX
|
32
|
+
module CocoaPods
|
33
|
+
class PodfileParsingError < StandardError; end
|
34
|
+
class BOMOutputError < StandardError; end
|
35
|
+
|
36
|
+
class CLIRunner
|
37
|
+
def run
|
38
|
+
begin
|
39
|
+
setup_logger # Needed in case we have errors while processing CLI parameters
|
40
|
+
options = parseOptions
|
41
|
+
setup_logger(verbose: options[:verbose])
|
42
|
+
@logger.debug "Running cyclonedx-cocoapods with options: #{options}"
|
43
|
+
|
44
|
+
podfile, lockfile = ensure_podfile_and_lock_are_present(options)
|
45
|
+
pods = parse_pods(podfile, lockfile)
|
46
|
+
|
47
|
+
populate_pods_with_additional_info(pods)
|
48
|
+
|
49
|
+
bom = BOMBuilder.new(component: component_from_options(options), pods: pods).bom(version: options[:bom_version] || 1)
|
50
|
+
write_bom_to_file(bom: bom, options: options)
|
51
|
+
rescue StandardError => e
|
52
|
+
@logger.error ([e.message] + e.backtrace).join($/)
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def parseOptions
|
61
|
+
parsedOptions = {}
|
62
|
+
component_types = Component::VALID_COMPONENT_TYPES
|
63
|
+
OptionParser.new do |options|
|
64
|
+
options.banner = <<~BANNER
|
65
|
+
Usage: cyclonedx-cocoapods [options]
|
66
|
+
Generates a BOM with the given parameters. BOM component metadata is only generated if the component's name and version are provided using the --name and --version parameters.
|
67
|
+
BANNER
|
68
|
+
|
69
|
+
options.on('--[no-]verbose', 'Run verbosely') do |v|
|
70
|
+
parsedOptions[:verbose] = v
|
71
|
+
end
|
72
|
+
options.on('-p', '--path path', '(Optional) Path to CocoaPods project directory, current directory if missing') do |path|
|
73
|
+
parsedOptions[:path] = path
|
74
|
+
end
|
75
|
+
options.on('-o', '--output bom_file_path', '(Optional) Path to output the bom.xml file to') do |bom_file_path|
|
76
|
+
parsedOptions[:bom_file_path] = bom_file_path
|
77
|
+
end
|
78
|
+
options.on('-b', '--bom-version bom_version', Integer, '(Optional) Version of the generated BOM, 1 if not provided') do |version|
|
79
|
+
parsedOptions[:bom_version] = version
|
80
|
+
end
|
81
|
+
options.on('-g', '--group group', '(Optional) Group of the component for which the BOM is generated') do |group|
|
82
|
+
parsedOptions[:group] = group
|
83
|
+
end
|
84
|
+
options.on('-n', '--name name', '(Optional, if specified version and type are also required) Name of the component for which the BOM is generated') do |name|
|
85
|
+
parsedOptions[:name] = name
|
86
|
+
end
|
87
|
+
options.on('-v', '--version version', '(Optional) Version of the component for which the BOM is generated') do |version|
|
88
|
+
begin
|
89
|
+
Gem::Version.new(version)
|
90
|
+
parsedOptions[:version] = version
|
91
|
+
rescue StandardError => e
|
92
|
+
raise OptionParser::InvalidArgument, e.message
|
93
|
+
end
|
94
|
+
end
|
95
|
+
options.on('-t', '--type type', "(Optional) Type of the component for which the BOM is generated (one of #{component_types.join('|')})") do |type|
|
96
|
+
raise OptionParser::InvalidArgument, "Invalid value for component's type (#{type}). It must be one of #{component_types.join('|')}" unless component_types.include?(type)
|
97
|
+
parsedOptions[:type] = type
|
98
|
+
end
|
99
|
+
options.on_tail('-h', '--help', 'Show help message') do
|
100
|
+
puts options
|
101
|
+
exit
|
102
|
+
end
|
103
|
+
end.parse!
|
104
|
+
|
105
|
+
raise OptionParser::InvalidArgument, 'You must also specify --version and --type if --name is provided' if !parsedOptions[:name].nil? && (parsedOptions[:version].nil? || parsedOptions[:type].nil?)
|
106
|
+
return parsedOptions
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def component_from_options(options)
|
111
|
+
Component.new(group: options[:group], name: options[:name], version: options[:version], type: options[:type]) if options[:name]
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def setup_logger(verbose: true)
|
116
|
+
@logger ||= Logger.new($stdout)
|
117
|
+
@logger.level = verbose ? Logger::DEBUG : Logger::INFO
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def ensure_podfile_and_lock_are_present(options)
|
122
|
+
project_dir = Pathname.new(options[:path] || Dir.pwd)
|
123
|
+
raise PodfileParsingError, "#{options[:path]} is not a valid directory." unless File.directory?(project_dir)
|
124
|
+
options[:podfile_path] = project_dir + 'Podfile'
|
125
|
+
raise PodfileParsingError, "Missing Podfile in #{project_dir}. Please use the --path option if not running from the CocoaPods project directory." unless File.exist?(options[:podfile_path])
|
126
|
+
options[:podfile_lock_path] = project_dir + 'Podfile.lock'
|
127
|
+
raise PodfileParsingError, "Missing Podfile.lock, please run 'pod install' before generating BOM" unless File.exist?(options[:podfile_lock_path])
|
128
|
+
|
129
|
+
initialize_cocoapods_config(project_dir)
|
130
|
+
|
131
|
+
lockfile = ::Pod::Lockfile.from_file(options[:podfile_lock_path])
|
132
|
+
verify_synced_sandbox(lockfile)
|
133
|
+
|
134
|
+
return ::Pod::Podfile.from_file(options[:podfile_path]), lockfile
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def initialize_cocoapods_config(project_dir)
|
139
|
+
::Pod::Config.instance.installation_root = project_dir
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def verify_synced_sandbox(lockfile)
|
144
|
+
manifestFile = ::Pod::Config.instance.sandbox.manifest
|
145
|
+
raise PodfileParsingError, "Missing Manifest.lock, please run 'pod install' before generating BOM" if manifestFile.nil?
|
146
|
+
raise PodfileParsingError, "The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation." unless lockfile == manifestFile
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def cocoapods_repository_source(podfile, lockfile, pod_name)
|
151
|
+
@source_manager ||= create_source_manager(podfile)
|
152
|
+
return Source::CocoaPodsRepository.searchable_source(url: lockfile.spec_repo(pod_name), source_manager: @source_manager)
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
def git_source(lockfile, pod_name)
|
157
|
+
checkout_options = lockfile.checkout_options_for_pod_named(pod_name)
|
158
|
+
url = checkout_options[:git]
|
159
|
+
[:tag, :branch, :commit].each do |type|
|
160
|
+
return Source::GitRepository.new(url: url, type: type, label: checkout_options[type]) if checkout_options[type]
|
161
|
+
end
|
162
|
+
return Source::GitRepository.new(url: url)
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
def source_for_pod(podfile, lockfile, pod_name)
|
167
|
+
root_name = pod_name.split('/').first
|
168
|
+
return cocoapods_repository_source(podfile, lockfile, root_name) unless lockfile.spec_repo(root_name).nil?
|
169
|
+
return git_source(lockfile, root_name) unless lockfile.checkout_options_for_pod_named(root_name).nil?
|
170
|
+
return Source::LocalPod.new(path: lockfile.to_hash['EXTERNAL SOURCES'][root_name][:path]) if lockfile.to_hash['EXTERNAL SOURCES'][root_name][:path]
|
171
|
+
return Source::Podspec.new(url: lockfile.to_hash['EXTERNAL SOURCES'][root_name][:podspec]) if lockfile.to_hash['EXTERNAL SOURCES'][root_name][:podspec]
|
172
|
+
return nil
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
def parse_pods(podfile, lockfile)
|
177
|
+
@logger.debug "Parsing pods from #{podfile.defined_in_file}"
|
178
|
+
return lockfile.pod_names.map do |name|
|
179
|
+
Pod.new(name: name, version: lockfile.version(name), source: source_for_pod(podfile, lockfile, name), checksum: lockfile.checksum(name))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def create_source_manager(podfile)
|
185
|
+
sourceManager = ::Pod::Source::Manager.new(::Pod::Config::instance.repos_dir)
|
186
|
+
@logger.debug "Parsing sources from #{podfile.defined_in_file}"
|
187
|
+
podfile.sources.each do |source|
|
188
|
+
@logger.debug "Ensuring #{source} is available for searches"
|
189
|
+
sourceManager.find_or_create_source_with_url(source)
|
190
|
+
end
|
191
|
+
@logger.debug "Source manager successfully created with all needed sources"
|
192
|
+
return sourceManager
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def populate_pods_with_additional_info(pods)
|
197
|
+
pods.each do |pod|
|
198
|
+
@logger.debug "Completing information for #{pod.name}"
|
199
|
+
pod.complete_information_from_source
|
200
|
+
end
|
201
|
+
return pods
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
def write_bom_to_file(bom:, options:)
|
206
|
+
bom_file_path = Pathname.new(options[:bom_file_path] || './bom.xml').expand_path
|
207
|
+
bom_dir = bom_file_path.dirname
|
208
|
+
|
209
|
+
begin
|
210
|
+
FileUtils.mkdir_p(bom_dir) unless bom_dir.directory?
|
211
|
+
rescue
|
212
|
+
raise BOMOutputError, "Unable to create the BOM output directory at #{bom_dir}"
|
213
|
+
end
|
214
|
+
|
215
|
+
begin
|
216
|
+
File.open(bom_file_path, 'w') { |file| file.write(bom) }
|
217
|
+
@logger.info "BOM written to #{bom_file_path}"
|
218
|
+
rescue
|
219
|
+
raise BOMOutputError, "Unable to write the BOM to #{bom_file_path}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of CycloneDX CocoaPods
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the “License”);
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an “AS IS” BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# SPDX-License-Identifier: Apache-2.0
|
17
|
+
# Copyright (c) OWASP Foundation. All Rights Reserved.
|
18
|
+
#
|
19
|
+
|
20
|
+
module CycloneDX
|
21
|
+
module CocoaPods
|
22
|
+
class Component
|
23
|
+
VALID_COMPONENT_TYPES = %w[application framework library container operating-system device firmware file].freeze
|
24
|
+
|
25
|
+
attr_reader :group, :name, :version, :type
|
26
|
+
|
27
|
+
def initialize(group: nil, name:, version:, type:)
|
28
|
+
raise ArgumentError, "Group, if specified, must be non empty" if !group.nil? && group.to_s.strip.empty?
|
29
|
+
raise ArgumentError, "Name must be non empty" if name.nil? || name.to_s.strip.empty?
|
30
|
+
Gem::Version.new(version) # To check that the version string is well formed
|
31
|
+
raise ArgumentError, "#{type} is not valid component type (#{VALID_COMPONENT_TYPES.join('|')})" unless VALID_COMPONENT_TYPES.include?(type)
|
32
|
+
|
33
|
+
@group, @name, @version, @type = group, name, version, type
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of CycloneDX CocoaPods
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the “License”);
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an “AS IS” BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# SPDX-License-Identifier: Apache-2.0
|
17
|
+
# Copyright (c) OWASP Foundation. All Rights Reserved.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'json'
|
21
|
+
|
22
|
+
module CycloneDX
|
23
|
+
module CocoaPods
|
24
|
+
class Pod
|
25
|
+
class License
|
26
|
+
SPDX_LICENSES = JSON.parse(File.read("#{__dir__}/spdx-licenses.json")).freeze
|
27
|
+
IDENTIFIER_TYPES = [:id, :name].freeze
|
28
|
+
|
29
|
+
attr_reader :identifier
|
30
|
+
attr_reader :identifier_type
|
31
|
+
attr_accessor :text
|
32
|
+
attr_accessor :url
|
33
|
+
|
34
|
+
def initialize(identifier:)
|
35
|
+
raise ArgumentError, "License identifier must be non empty" if identifier.nil? || identifier.to_s.strip.empty?
|
36
|
+
|
37
|
+
@identifier = SPDX_LICENSES.find { |license_id| license_id.downcase == identifier.to_s.downcase }
|
38
|
+
@identifier_type = @identifier.nil? ? :name : :id
|
39
|
+
@identifier ||= identifier
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of CycloneDX CocoaPods
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the “License”);
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an “AS IS” BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# SPDX-License-Identifier: Apache-2.0
|
17
|
+
# Copyright (c) OWASP Foundation. All Rights Reserved.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'rubygems/version'
|
21
|
+
require_relative 'license'
|
22
|
+
|
23
|
+
module CycloneDX
|
24
|
+
module CocoaPods
|
25
|
+
class Pod
|
26
|
+
attr_reader :name # xs:normalizedString
|
27
|
+
attr_reader :version # xs:normalizedString
|
28
|
+
attr_reader :source # Anything responding to :source_qualifier
|
29
|
+
attr_reader :homepage # xs:anyURI - https://cyclonedx.org/docs/1.4/#type_externalReference
|
30
|
+
attr_reader :checksum # https://cyclonedx.org/docs/1.4/#type_hashValue (We only use SHA-1 hashes - length == 40)
|
31
|
+
attr_reader :author # xs:normalizedString
|
32
|
+
attr_reader :description # xs:normalizedString
|
33
|
+
attr_reader :license # https://cyclonedx.org/docs/1.4/#type_licenseType
|
34
|
+
# We don't currently support several licenses or license expressions https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/
|
35
|
+
def initialize(name:, version:, source: nil, checksum: nil)
|
36
|
+
raise ArgumentError, "Name must be non empty" if name.nil? || name.to_s.empty?
|
37
|
+
raise ArgumentError, "Name shouldn't contain spaces" if name.to_s.include?(' ')
|
38
|
+
raise ArgumentError, "Name shouldn't start with a dot" if name.to_s.start_with?('.')
|
39
|
+
# `pod create` also enforces no plus sign, but more than 500 public pods have a plus in the root name.
|
40
|
+
# https://github.com/CocoaPods/CocoaPods/blob/9461b346aeb8cba6df71fd4e71661688138ec21b/lib/cocoapods/command/lib/create.rb#L35
|
41
|
+
|
42
|
+
Gem::Version.new(version) # To check that the version string is well formed
|
43
|
+
raise ArgumentError, "Invalid pod source" unless source.nil? || source.respond_to?(:source_qualifier)
|
44
|
+
raise ArgumentError, "#{checksum} is not valid SHA-1 hash" unless checksum.nil? || checksum =~ /[a-fA-F0-9]{40}/
|
45
|
+
@name, @version, @source, @checksum = name.to_s, version, source, checksum
|
46
|
+
end
|
47
|
+
|
48
|
+
def root_name
|
49
|
+
@name.split('/').first
|
50
|
+
end
|
51
|
+
|
52
|
+
def populate(attributes)
|
53
|
+
attributes.transform_keys!(&:to_sym)
|
54
|
+
populate_author(attributes)
|
55
|
+
populate_description(attributes)
|
56
|
+
populate_license(attributes)
|
57
|
+
populate_homepage(attributes)
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
"Pod<#{name}, #{version.to_s}>"
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def populate_author(attributes)
|
68
|
+
authors = attributes[:author] || attributes[:authors]
|
69
|
+
case authors
|
70
|
+
when String
|
71
|
+
@author = authors
|
72
|
+
when Array
|
73
|
+
@author = authors.join(', ')
|
74
|
+
when Hash
|
75
|
+
@author = authors.map { |name, email| "#{name} <#{email}>" }.join(', ')
|
76
|
+
else
|
77
|
+
@author = nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def populate_description(attributes)
|
82
|
+
@description = attributes[:description] || attributes[:summary]
|
83
|
+
end
|
84
|
+
|
85
|
+
def populate_license(attributes)
|
86
|
+
case attributes[:license]
|
87
|
+
when String
|
88
|
+
@license = License.new(identifier: attributes[:license])
|
89
|
+
when Hash
|
90
|
+
attributes[:license].transform_keys!(&:to_sym)
|
91
|
+
identifier = attributes[:license][:type]
|
92
|
+
unless identifier.nil? || identifier.to_s.strip.empty?
|
93
|
+
@license = License.new(identifier: identifier)
|
94
|
+
@license.text = attributes[:license][:text]
|
95
|
+
else
|
96
|
+
@license = nil
|
97
|
+
end
|
98
|
+
else
|
99
|
+
@license = nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def populate_homepage(attributes)
|
104
|
+
@homepage = attributes[:homepage]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of CycloneDX CocoaPods
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the “License”);
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an “AS IS” BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# SPDX-License-Identifier: Apache-2.0
|
17
|
+
# Copyright (c) OWASP Foundation. All Rights Reserved.
|
18
|
+
#
|
19
|
+
|
20
|
+
module CycloneDX
|
21
|
+
module CocoaPods
|
22
|
+
class SearchError < StandardError; end
|
23
|
+
|
24
|
+
module Source
|
25
|
+
class CocoaPodsRepository
|
26
|
+
attr_accessor :source_manager
|
27
|
+
|
28
|
+
def self.searchable_source(url:, source_manager:)
|
29
|
+
source = CocoaPodsRepository.new(url: url)
|
30
|
+
source.source_manager = source_manager
|
31
|
+
return source
|
32
|
+
end
|
33
|
+
|
34
|
+
def attributes_for(pod:)
|
35
|
+
specification_sets = @source_manager.search_by_name("^#{Regexp.escape(pod.root_name)}$")
|
36
|
+
raise SearchError, "No pod found named #{pod.name}" if specification_sets.length == 0
|
37
|
+
raise SearchError, "More than one pod found named #{pod.name}" if specification_sets.length > 1
|
38
|
+
|
39
|
+
paths = specification_sets[0].specification_paths_for_version(pod.version)
|
40
|
+
raise SearchError, "Version #{pod.version} not found for pod #{pod.name}" if paths.length == 0
|
41
|
+
|
42
|
+
::Pod::Specification.from_file(paths[0]).attributes_hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class GitRepository
|
47
|
+
def attributes_for(pod:)
|
48
|
+
::Pod::Config.instance.sandbox.specification(pod.name).attributes_hash
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class LocalPod
|
53
|
+
def attributes_for(pod:)
|
54
|
+
::Pod::Config.instance.sandbox.specification(pod.name).attributes_hash
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Podspec
|
59
|
+
def attributes_for(pod:)
|
60
|
+
::Pod::Config.instance.sandbox.specification(pod.name).attributes_hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
class Pod
|
67
|
+
def complete_information_from_source
|
68
|
+
populate(source.attributes_for(pod: self))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of CycloneDX CocoaPods
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the “License”);
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an “AS IS” BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# SPDX-License-Identifier: Apache-2.0
|
17
|
+
# Copyright (c) OWASP Foundation. All Rights Reserved.
|
18
|
+
#
|
19
|
+
|
20
|
+
module CycloneDX
|
21
|
+
module CocoaPods
|
22
|
+
module Source
|
23
|
+
class CocoaPodsRepository
|
24
|
+
attr_reader :url
|
25
|
+
|
26
|
+
def initialize(url:)
|
27
|
+
@url = url
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class GitRepository
|
32
|
+
VALID_TYPES = [:branch, :tag, :commit].freeze
|
33
|
+
|
34
|
+
attr_reader :url, :type, :label
|
35
|
+
|
36
|
+
def initialize(url:, type: nil, label: nil)
|
37
|
+
raise ArgumentError, "Invalid checkout information" if !type.nil? && !VALID_TYPES.include?(type)
|
38
|
+
@url, @type, @label = url, type, label
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class LocalPod
|
43
|
+
attr_reader :path
|
44
|
+
|
45
|
+
def initialize(path:)
|
46
|
+
@path = path
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Podspec
|
51
|
+
attr_reader :url
|
52
|
+
|
53
|
+
def initialize(url:)
|
54
|
+
@url = url
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|