cyclonedx-cocoapods 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e656666b5b0297c98ddebe571a31e68ada3ff7fa9a048fc10f4f824fee1982c8
4
- data.tar.gz: d398292e90265bf460874a2db759fb20a7d596067c4aa35afdb07d942aead192
3
+ metadata.gz: a3c7ebcac0eb8ea04cf5b1aed4da3bdbe1cadc2acb33e1bc4ebec9f52ac9bad9
4
+ data.tar.gz: bdc83e96c9b4750bf2135a85b30d384ae2096e4c0591d3db2f65434506f4c220
5
5
  SHA512:
6
- metadata.gz: 1d7e28f6e783cc643d6563671412747c57ed8f26c49fdb34df1bc708662e6369027444f3ef2a4b0be84e1429538d12f80017a7ea61be0b5612210ae272ee00fa
7
- data.tar.gz: 2e99db6f7a0f502190ace2511e954b6c43439eb21b5b13509165590ea3075b30ea8ee9fdb7f88a5986ae767c487abb941d6d5548e91448edc11784a377dec25b
6
+ metadata.gz: 94cdbbcb32c6d83dad78c383536dc484f08a040f5104318a3c2355b070fb915474e25027188bcaa8dfffc4222772525e4e051dfc8a1d673a08a31cd51f4d3cc2
7
+ data.tar.gz: 1c0da4d2d356eb06207f889605e3c65ea0594821b7de130ebe5ce3d182917f87415fdc615d727f54f540b5a3c9c2b58d915117627b7b71c7a115045e799bc0c4
data/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ 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.1.0]
8
+
9
+ - Can now eliminate Podfile targets that include "test" in their name ([Issue #43](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/43)) [@macblazer](https://github.com/macblazer).
10
+
7
11
  ## [1.0.0]
8
12
 
9
13
  ### Added
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  # CycloneDX CocoaPods (Objective-C/Swift)
11
11
 
12
- The CycloneDX CocoaPods Gem creates a valid CycloneDX software bill-of-material document from all project dependencies. CycloneDX is a lightweight BoM specification that is easily created, human readable, and simple to parse.
12
+ The CycloneDX CocoaPods Gem creates a valid CycloneDX software bill-of-material document from all [CocoaPods](https://cocoapods.org/) project dependencies. CycloneDX is a lightweight BoM specification that is easily created, human readable, and simple to parse.
13
13
 
14
14
  ## Installation
15
15
 
@@ -36,18 +36,30 @@ Building from source requires Ruby 2.4.0 or newer.
36
36
  You can use the [CycloneDX CLI](https://github.com/CycloneDX/cyclonedx-cli#convert-command) to convert between multiple BOM formats or specification versions.
37
37
 
38
38
  ## Usage
39
- Usage: `cyclonedx-cocoapods` [options]
40
-
41
- --[no-]verbose Run verbosely
42
- -p, --path path (Optional) Path to CocoaPods project directory, current directory if missing
43
- -o, --output bom_file_path (Optional) Path to output the bom.xml file to
44
- -b, --bom-version bom_version (Optional) Version of the generated BOM, 1 if not provided
45
- -g, --group group (Optional) Group of the component for which the BOM is generated
46
- -n, --name name (Optional, if specified version and type are also required) Name of the component for which the BOM is generated
47
- -v, --version version (Optional) Version of the component for which the BOM is generated
48
- -t, --type type (Optional) Type of the component for which the BOM is generated (one of application|framework|library|container|operating-system|device|firmware|file)
39
+ ```
40
+ Generates a BOM with the given parameters. BOM component metadata is only generated if the component's name, version, and type are provided using the --name, --version, and --type parameters.
41
+ [version <version_number>]
42
+
43
+ USAGE
44
+ cyclonedx-cocoapods [options]
45
+
46
+ OPTIONS
47
+ --[no-]verbose Show verbose debugging output
49
48
  -h, --help Show help message
50
49
 
50
+ BOM Generation
51
+ -p, --path path Path to CocoaPods project directory (default: current directory)
52
+ -o, --output bom_file_path Path to output the bom.xml file to (default: "bom.xml")
53
+ -b, --bom-version bom_version Version of the generated BOM (default: "1")
54
+ -x, --exclude-test-targets Eliminate Podfile targets whose name contains the word "test"
55
+
56
+ Component Metadata
57
+ -n, --name name (If specified version and type are also required) Name of the component for which the BOM is generated
58
+ -v, --version version Version of the component for which the BOM is generated
59
+ -t, --type type Type of the component for which the BOM is generated (one of application|framework|library|container|operating-system|device|firmware|file)
60
+ -g, --group group Group of the component for which the BOM is generated
61
+ ```
62
+
51
63
  **Output:** BoM file at specified location, `./bom.xml` if not specified
52
64
 
53
65
  ### Example
@@ -18,19 +18,15 @@
18
18
  # Copyright (c) OWASP Foundation. All Rights Reserved.
19
19
  #
20
20
 
21
- require 'optparse'
22
21
  require 'logger'
23
- require 'cocoapods'
22
+ require 'optparse'
24
23
 
25
- require_relative 'component'
26
- require_relative 'pod'
27
- require_relative 'pod_attributes'
28
- require_relative 'source'
29
24
  require_relative 'bom_builder'
25
+ require_relative 'component'
26
+ require_relative 'podfile_analyzer'
30
27
 
31
28
  module CycloneDX
32
29
  module CocoaPods
33
- class PodfileParsingError < StandardError; end
34
30
  class BOMOutputError < StandardError; end
35
31
 
36
32
  class CLIRunner
@@ -41,10 +37,10 @@ module CycloneDX
41
37
  setup_logger(verbose: options[:verbose])
42
38
  @logger.debug "Running cyclonedx-cocoapods with options: #{options}"
43
39
 
44
- podfile, lockfile = ensure_podfile_and_lock_are_present(options)
45
- pods = parse_pods(podfile, lockfile)
46
-
47
- populate_pods_with_additional_info(pods)
40
+ analyzer = PodfileAnalyzer.new(logger: @logger, exclude_test_targets: options[:exclude_test_targets])
41
+ podfile, lockfile = analyzer.ensure_podfile_and_lock_are_present(options)
42
+ pods = analyzer.parse_pods(podfile, lockfile)
43
+ analyzer.populate_pods_with_additional_info(pods)
48
44
 
49
45
  bom = BOMBuilder.new(component: component_from_options(options), pods: pods).bom(version: options[:bom_version] || 1)
50
46
  write_bom_to_file(bom: bom, options: options)
@@ -57,34 +53,48 @@ module CycloneDX
57
53
 
58
54
  private
59
55
 
56
+
60
57
  def parseOptions
61
58
  parsedOptions = {}
62
59
  component_types = Component::VALID_COMPONENT_TYPES
63
60
  OptionParser.new do |options|
64
61
  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.
62
+ Generates a BOM with the given parameters. BOM component metadata is only generated if the component's name, version, and type are provided using the --name, --version, and --type parameters.
63
+ [version #{CycloneDX::CocoaPods::VERSION}]
64
+
65
+ USAGE
66
+ cyclonedx-cocoapods [options]
67
+
68
+ OPTIONS
67
69
  BANNER
68
70
 
69
- options.on('--[no-]verbose', 'Run verbosely') do |v|
71
+ options.on('--[no-]verbose', 'Show verbose debugging output') do |v|
70
72
  parsedOptions[:verbose] = v
71
73
  end
72
- options.on('-p', '--path path', '(Optional) Path to CocoaPods project directory, current directory if missing') do |path|
74
+ options.on('-h', '--help', 'Show help message') do
75
+ puts options
76
+ exit
77
+ end
78
+
79
+ options.separator("\n BOM Generation")
80
+ options.on('-p', '--path path', 'Path to CocoaPods project directory (default: current directory)') do |path|
73
81
  parsedOptions[:path] = path
74
82
  end
75
- options.on('-o', '--output bom_file_path', '(Optional) Path to output the bom.xml file to') do |bom_file_path|
83
+ options.on('-o', '--output bom_file_path', 'Path to output the bom.xml file to (default: "bom.xml")') do |bom_file_path|
76
84
  parsedOptions[:bom_file_path] = bom_file_path
77
85
  end
78
- options.on('-b', '--bom-version bom_version', Integer, '(Optional) Version of the generated BOM, 1 if not provided') do |version|
86
+ options.on('-b', '--bom-version bom_version', Integer, 'Version of the generated BOM (default: "1")') do |version|
79
87
  parsedOptions[:bom_version] = version
80
88
  end
81
- options.on('-g', '--group group', '(Optional) Group of the component for which the BOM is generated') do |group|
82
- parsedOptions[:group] = group
89
+ options.on('-x', '--exclude-test-targets', 'Eliminate Podfile targets whose name contains the word "test"') do |exclude|
90
+ parsedOptions[:exclude_test_targets] = exclude
83
91
  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|
92
+
93
+ options.separator("\n Component Metadata\n")
94
+ options.on('-n', '--name name', '(If specified version and type are also required) Name of the component for which the BOM is generated') do |name|
85
95
  parsedOptions[:name] = name
86
96
  end
87
- options.on('-v', '--version version', '(Optional) Version of the component for which the BOM is generated') do |version|
97
+ options.on('-v', '--version version', 'Version of the component for which the BOM is generated') do |version|
88
98
  begin
89
99
  Gem::Version.new(version)
90
100
  parsedOptions[:version] = version
@@ -92,13 +102,12 @@ module CycloneDX
92
102
  raise OptionParser::InvalidArgument, e.message
93
103
  end
94
104
  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|
105
+ options.on('-t', '--type type', "Type of the component for which the BOM is generated (one of #{component_types.join('|')})") do |type|
96
106
  raise OptionParser::InvalidArgument, "Invalid value for component's type (#{type}). It must be one of #{component_types.join('|')}" unless component_types.include?(type)
97
107
  parsedOptions[:type] = type
98
108
  end
99
- options.on_tail('-h', '--help', 'Show help message') do
100
- puts options
101
- exit
109
+ options.on('-g', '--group group', 'Group of the component for which the BOM is generated') do |group|
110
+ parsedOptions[:group] = group
102
111
  end
103
112
  end.parse!
104
113
 
@@ -118,90 +127,6 @@ module CycloneDX
118
127
  end
119
128
 
120
129
 
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
130
  def write_bom_to_file(bom:, options:)
206
131
  bom_file_path = Pathname.new(options[:bom_file_path] || './bom.xml').expand_path
207
132
  bom_dir = bom_file_path.dirname
@@ -0,0 +1,182 @@
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 'cocoapods'
22
+ require 'logger'
23
+
24
+ require_relative 'pod'
25
+ require_relative 'pod_attributes'
26
+ require_relative 'source'
27
+
28
+ module CycloneDX
29
+ module CocoaPods
30
+ class PodfileParsingError < StandardError; end
31
+
32
+ class PodfileAnalyzer
33
+ def initialize(logger:, exclude_test_targets: false)
34
+ @logger = logger
35
+ @exclude_test_targets = exclude_test_targets
36
+ end
37
+
38
+ def ensure_podfile_and_lock_are_present(options)
39
+ project_dir = Pathname.new(options[:path] || Dir.pwd)
40
+ raise PodfileParsingError, "#{options[:path]} is not a valid directory." unless File.directory?(project_dir)
41
+ options[:podfile_path] = project_dir + 'Podfile'
42
+ 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])
43
+ options[:podfile_lock_path] = project_dir + 'Podfile.lock'
44
+ raise PodfileParsingError, "Missing Podfile.lock, please run 'pod install' before generating BOM" unless File.exist?(options[:podfile_lock_path])
45
+
46
+ initialize_cocoapods_config(project_dir)
47
+
48
+ lockfile = ::Pod::Lockfile.from_file(options[:podfile_lock_path])
49
+ verify_synced_sandbox(lockfile)
50
+
51
+ return ::Pod::Podfile.from_file(options[:podfile_path]), lockfile
52
+ end
53
+
54
+
55
+ def parse_pods(podfile, lockfile)
56
+ @logger.debug "Parsing pods from #{podfile.defined_in_file}"
57
+ included_pods = create_list_of_included_pods(podfile, lockfile)
58
+ return lockfile.pod_names.select { |name| included_pods.include?(name) }.map do |name|
59
+ Pod.new(name: name, version: lockfile.version(name), source: source_for_pod(podfile, lockfile, name), checksum: lockfile.checksum(name))
60
+ end
61
+ end
62
+
63
+
64
+ def populate_pods_with_additional_info(pods)
65
+ pods.each do |pod|
66
+ @logger.debug "Completing information for #{pod.name}"
67
+ pod.complete_information_from_source
68
+ end
69
+ return pods
70
+ end
71
+
72
+
73
+ private
74
+
75
+
76
+ def initialize_cocoapods_config(project_dir)
77
+ ::Pod::Config.instance.installation_root = project_dir
78
+ end
79
+
80
+
81
+ def verify_synced_sandbox(lockfile)
82
+ manifestFile = ::Pod::Config.instance.sandbox.manifest
83
+ raise PodfileParsingError, "Missing Manifest.lock, please run 'pod install' before generating BOM" if manifestFile.nil?
84
+ raise PodfileParsingError, "The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation." unless lockfile == manifestFile
85
+ end
86
+
87
+ def simple_hash_of_lockfile_pods(lockfile)
88
+ pods_hash = { }
89
+
90
+ pods_used = lockfile.internal_data['PODS']
91
+ pods_used.each { |pod|
92
+ if pod.is_a?(String)
93
+ # Pods stored as String have no dependencies
94
+ pod_name = pod.split.first
95
+ pods_hash[pod_name] = []
96
+ else
97
+ # Pods stored as a hash have pod name and dependencies.
98
+ pod.each { |pod, dependencies|
99
+ pod_name = pod.split.first
100
+ pods_hash[pod_name] = dependencies.map { |d| d.split.first }
101
+ }
102
+ end
103
+ }
104
+ pods_hash
105
+ end
106
+
107
+ def append_all_pod_dependencies(pods_used, pods_cache)
108
+ result = pods_used
109
+ original_number = 0
110
+ # Loop adding pod dependencies until we are not adding any more dependencies to the result
111
+ # This brings in all the transitive dependencies of every top level pod.
112
+ # Note this also handles the edge case of having a Podfile with no pods used.
113
+ while result.length != original_number
114
+ original_number = result.length
115
+ pods_used.each { |pod_name|
116
+ result.push(*pods_cache[pod_name]) unless pods_cache[pod_name].empty?
117
+ }
118
+ result = result.uniq
119
+ pods_used = result
120
+ end
121
+ result
122
+ end
123
+
124
+ def create_list_of_included_pods(podfile, lockfile)
125
+ pods_cache = simple_hash_of_lockfile_pods(lockfile)
126
+
127
+ includedTargets = podfile.target_definition_list.select{ |target| include_target_named(target.label) }
128
+ includedTargetNames = includedTargets.map { |target| target.label }
129
+ @logger.debug "Including all pods for targets: #{includedTargetNames}"
130
+
131
+ topLevelDeps = includedTargets.map(&:dependencies).flatten.uniq
132
+ pods_used = topLevelDeps.map(&:name).uniq
133
+ pods_used = append_all_pod_dependencies(pods_used, pods_cache)
134
+
135
+ return pods_used.sort
136
+ end
137
+
138
+
139
+ def include_target_named(targetname)
140
+ !@exclude_test_targets || !targetname.downcase.include?('test')
141
+ end
142
+
143
+
144
+ def cocoapods_repository_source(podfile, lockfile, pod_name)
145
+ @source_manager ||= create_source_manager(podfile)
146
+ return Source::CocoaPodsRepository.searchable_source(url: lockfile.spec_repo(pod_name), source_manager: @source_manager)
147
+ end
148
+
149
+
150
+ def git_source(lockfile, pod_name)
151
+ checkout_options = lockfile.checkout_options_for_pod_named(pod_name)
152
+ url = checkout_options[:git]
153
+ [:tag, :branch, :commit].each do |type|
154
+ return Source::GitRepository.new(url: url, type: type, label: checkout_options[type]) if checkout_options[type]
155
+ end
156
+ return Source::GitRepository.new(url: url)
157
+ end
158
+
159
+
160
+ def source_for_pod(podfile, lockfile, pod_name)
161
+ root_name = pod_name.split('/').first
162
+ return cocoapods_repository_source(podfile, lockfile, root_name) unless lockfile.spec_repo(root_name).nil?
163
+ return git_source(lockfile, root_name) unless lockfile.checkout_options_for_pod_named(root_name).nil?
164
+ return Source::LocalPod.new(path: lockfile.to_hash['EXTERNAL SOURCES'][root_name][:path]) if lockfile.to_hash['EXTERNAL SOURCES'][root_name][:path]
165
+ return Source::Podspec.new(url: lockfile.to_hash['EXTERNAL SOURCES'][root_name][:podspec]) if lockfile.to_hash['EXTERNAL SOURCES'][root_name][:podspec]
166
+ return nil
167
+ end
168
+
169
+
170
+ def create_source_manager(podfile)
171
+ sourceManager = ::Pod::Source::Manager.new(::Pod::Config::instance.repos_dir)
172
+ @logger.debug "Parsing sources from #{podfile.defined_in_file}"
173
+ podfile.sources.each do |source|
174
+ @logger.debug "Ensuring #{source} is available for searches"
175
+ sourceManager.find_or_create_source_with_url(source)
176
+ end
177
+ @logger.debug "Source manager successfully created with all needed sources"
178
+ return sourceManager
179
+ end
180
+ end
181
+ end
182
+ end
@@ -20,7 +20,7 @@
20
20
 
21
21
  module CycloneDX
22
22
  module CocoaPods
23
- VERSION = '1.0.0'
23
+ VERSION = '1.1.0'
24
24
  DEPENDENCIES = {
25
25
  cocoapods: '~> 1.10.1',
26
26
  nokogiri: '~> 1.11.2'
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cyclonedx-cocoapods
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - José González
8
+ - Kyle Hammond
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2022-08-12 00:00:00.000000000 Z
12
+ date: 2022-09-13 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: cocoapods
@@ -85,6 +86,7 @@ description: CycloneDX is a lightweight software bill-of-material (SBOM) specifi
85
86
  This Gem generates CycloneDX BOMs from CocoaPods projects.
86
87
  email:
87
88
  - jose.gonzalez@openinput.com
89
+ - kyle.hammond@jamf.com
88
90
  executables:
89
91
  - cyclonedx-cocoapods
90
92
  extensions: []
@@ -101,6 +103,7 @@ files:
101
103
  - lib/cyclonedx/cocoapods/license.rb
102
104
  - lib/cyclonedx/cocoapods/pod.rb
103
105
  - lib/cyclonedx/cocoapods/pod_attributes.rb
106
+ - lib/cyclonedx/cocoapods/podfile_analyzer.rb
104
107
  - lib/cyclonedx/cocoapods/source.rb
105
108
  - lib/cyclonedx/cocoapods/spdx-licenses.json
106
109
  - lib/cyclonedx/cocoapods/version.rb