cyclonedx-cocoapods 1.1.0 → 1.1.2

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: a3c7ebcac0eb8ea04cf5b1aed4da3bdbe1cadc2acb33e1bc4ebec9f52ac9bad9
4
- data.tar.gz: bdc83e96c9b4750bf2135a85b30d384ae2096e4c0591d3db2f65434506f4c220
3
+ metadata.gz: d9413e8c99e608e82f87b4075e907eb9fd137fd9f67a2c00bb277cf5c7fc2e21
4
+ data.tar.gz: fd8be60d19ee1e2d84f53bbc16e66734eaffb9b2375f462219bd097fbdb7ef1c
5
5
  SHA512:
6
- metadata.gz: 94cdbbcb32c6d83dad78c383536dc484f08a040f5104318a3c2355b070fb915474e25027188bcaa8dfffc4222772525e4e051dfc8a1d673a08a31cd51f4d3cc2
7
- data.tar.gz: 1c0da4d2d356eb06207f889605e3c65ea0594821b7de130ebe5ce3d182917f87415fdc615d727f54f540b5a3c9c2b58d915117627b7b71c7a115045e799bc0c4
6
+ metadata.gz: 8b1e44bed24cddcce4e550047b39c849167f60d4e3ac86006365a991e70de3de3634a9de0ef90df7e7a3f93a9c255b5df271526a3731b91739726cc400c23889
7
+ data.tar.gz: f8778db86758639e8c2888a0ccd67d9209d8dac2282e422d75c18a40831c3e89a8c0cac10d8392965b8a47c01341b197dc424912470bc300e06c355e76d76415
data/CHANGELOG.md CHANGED
@@ -4,8 +4,28 @@ 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.2]
8
+
9
+ ### Changed
10
+ - Updated gem dependency for cocoapods to be minimum v1.10.1 up to anything less than v2. ([Issue #51](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/51)) [@macblazer](https://github.com/macblazer).
11
+ - Updated gem dependency for nokogiri to be minimum v1.11.2 up to anything less than v2. [@macblazer](https://github.com/macblazer).
12
+ - Updated README.md with a description of what happens with pods or Podfiles that use subspecs. ([Issue #52](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/52)) [@macblazer](https://github.com/macblazer).
13
+
14
+ ### Fixed
15
+ - Fixed parsing of a Podfile that uses CocoaPods plugins. ([PR #55](https://github.com/CycloneDX/cyclonedx-cocoapods/pull/55)) [@DwayneCoussement](https://github.com/DwayneCoussement).
16
+
17
+ ## [1.1.1]
18
+
19
+ ### Changed
20
+ - Better error messaging when a problem is encountered while gathering pod information ([Issue #48](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/48)) [@macblazer](https://github.com/macblazer).
21
+
22
+ ### Fixed
23
+ - Including a pod that has a platform-specific dependency for an unused platform no longer causes a crash ([Issue #46](https://github.com/CycloneDX/cyclonedx-cocoapods/issues/46)) [@macblazer](https://github.com/macblazer).
24
+ - Analyzing a Podfile that has no pods defined in it no longer causes a crash [@macblazer](https://github.com/macblazer).
25
+
7
26
  ## [1.1.0]
8
27
 
28
+ ### Added
9
29
  - 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
30
 
11
31
  ## [1.0.0]
data/README.md CHANGED
@@ -80,6 +80,41 @@ then these two commands were run in the checked out code directory.
80
80
  % cyclonedx-cocoapods -n "kizitonwose/PodsUpdater" -v 1.0.3 -t application --output example_bom.xml
81
81
  ```
82
82
 
83
+ ### A Note About CocoaPod Subspecs
84
+
85
+ Many CocoaPods make use of [subspec functionality](https://guides.cocoapods.org/syntax/podspec.html#subspec).
86
+ Podfiles can require whole pods, or just subspecs; pods themselves may require whole pods or subspecs of other
87
+ pods. In complex projects such as React Native apps this often results in a single pod being included as a
88
+ dependency multiple times as several of its subspecs are included individually.
89
+
90
+ *cyclonedx-cocoapods* works properly with this, and adds a dependency in the BOM output for each subspec that is
91
+ required by the Podfile and throughout the chain of dependencies. Each subspec will only appear once in the BOM
92
+ file. This gives you granular detail in the BOM of which subspecs of which pods are used. This is easiest seen
93
+ with an example.
94
+
95
+ The Podfile
96
+ ```ruby
97
+ target 'SampleProject' do
98
+ pod 'SamplePod/firstsubspec'
99
+ pod 'SamplePod/secondsubspec'
100
+ end
101
+ ```
102
+
103
+ If the SamplePod is at v2.1, running *cyclonedx-cocoapods* on this will output a BOM file with two `component`
104
+ dependencies:
105
+ - `pkg:cocoapods/SamplePod@2.1#firstsubspec` at `https://github.com/example/SamplePod`
106
+ - `pkg:cocoapods/SamplePod@2.1#secondsubspec` at `https://github.com/example/SamplePod`
107
+
108
+ [Dependency Track](https://dependencytrack.org) (DT) is a tool that many organizations use to help automate SBOM
109
+ related tasks. When uploading an SBOM that contains multiple subspecs from the same pod, or a single subspec
110
+ alongside the complete pod dependency, the initial upload will indicate a number of dependencies equal to the number
111
+ of `component` objects within the BOM. However, DT analysis then looks for unique repositories in use which will
112
+ merge all of the subspecs of a particular pod into a single entry. On later uploads to DT of the same or similar BOM
113
+ it will indicate just the number of unique repositories.
114
+
115
+ Uploading the above SamplePod BOM file to DT will initially see two dependencies. Later analysis by DT notices
116
+ that both dependencies resolve to the same repository, so DT will then only show a single dependency.
117
+
83
118
  ## Contributing
84
119
 
85
120
  To set up for local development, make a fork of this repo, make a branch on your fork named after the issue or workflow you are improving, checkout your branch, then run `bundle install`.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This file is part of CycloneDX CocoaPods
3
5
  #
@@ -26,8 +28,8 @@ module CycloneDX
26
28
  module CocoaPods
27
29
  module Source
28
30
  class CocoaPodsRepository
29
- LEGACY_REPOSITORY = 'https://github.com/CocoaPods/Specs.git'.freeze
30
- CDN_REPOSITORY = 'trunk'.freeze
31
+ LEGACY_REPOSITORY = 'https://github.com/CocoaPods/Specs.git'
32
+ CDN_REPOSITORY = 'trunk'
31
33
 
32
34
  def source_qualifier
33
35
  url == LEGACY_REPOSITORY || url == CDN_REPOSITORY ? {} : { repository_url: url }
@@ -54,8 +56,8 @@ module CycloneDX
54
56
  end
55
57
 
56
58
  class Pod
57
- CHECKSUM_ALGORITHM = 'SHA-1'.freeze
58
- HOMEPAGE_REFERENCE_TYPE = 'website'.freeze
59
+ CHECKSUM_ALGORITHM = 'SHA-1'
60
+ HOMEPAGE_REFERENCE_TYPE = 'website'
59
61
 
60
62
  def purl
61
63
  purl_name = CGI.escape(name.split('/').first)
@@ -115,7 +117,7 @@ module CycloneDX
115
117
  end
116
118
 
117
119
  class BOMBuilder
118
- NAMESPACE = 'http://cyclonedx.org/schema/bom/1.4'.freeze
120
+ NAMESPACE = 'http://cyclonedx.org/schema/bom/1.4'
119
121
 
120
122
  attr_reader :component, :pods
121
123
 
@@ -155,4 +157,4 @@ module CycloneDX
155
157
  end
156
158
  end
157
159
  end
158
- end
160
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #
3
4
  # This file is part of CycloneDX CocoaPods
4
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This file is part of CycloneDX CocoaPods
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This file is part of CycloneDX CocoaPods
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This file is part of CycloneDX CocoaPods
3
5
  #
@@ -105,4 +107,4 @@ module CycloneDX
105
107
  end
106
108
  end
107
109
  end
108
- end
110
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This file is part of CycloneDX CocoaPods
3
5
  #
@@ -33,11 +35,11 @@ module CycloneDX
33
35
 
34
36
  def attributes_for(pod:)
35
37
  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
+ raise SearchError, "No pod found named #{pod.name}; run 'pod repo update' and try again" if specification_sets.length == 0
39
+ raise SearchError, "More than one pod found named #{pod.name}; a pod in a private spec repo should not have the same name as a public pod" if specification_sets.length > 1
38
40
 
39
41
  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
42
+ raise SearchError, "Version #{pod.version} not found for pod #{pod.name}; run 'pod repo update' and try again" if paths.length == 0
41
43
 
42
44
  ::Pod::Specification.from_file(paths[0]).attributes_hash
43
45
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #
3
4
  # This file is part of CycloneDX CocoaPods
4
5
  #
@@ -19,6 +20,7 @@
19
20
  #
20
21
 
21
22
  require 'cocoapods'
23
+ require 'cocoapods-core'
22
24
  require 'logger'
23
25
 
24
26
  require_relative 'pod'
@@ -35,6 +37,23 @@ module CycloneDX
35
37
  @exclude_test_targets = exclude_test_targets
36
38
  end
37
39
 
40
+ def load_plugins(podfile_path)
41
+ podfile_contents = File.read(podfile_path)
42
+ plugin_syntax = /\s*plugin\s+['"]([^'"]+)['"]/
43
+ plugin_names = podfile_contents.scan(plugin_syntax).flatten
44
+
45
+ plugin_names.each do |plugin_name|
46
+ @logger.debug("Loading plugin #{plugin_name}")
47
+ begin
48
+ plugin_spec = Gem::Specification.find_by_name(plugin_name)
49
+ plugin_spec.activate if plugin_spec
50
+ load(plugin_spec.gem_dir + '/lib/cocoapods_plugin.rb') if plugin_spec
51
+ rescue Gem::LoadError => e
52
+ @logger.warn("Failed to load plugin #{plugin_name}. #{e.message}")
53
+ end
54
+ end
55
+ end
56
+
38
57
  def ensure_podfile_and_lock_are_present(options)
39
58
  project_dir = Pathname.new(options[:path] || Dir.pwd)
40
59
  raise PodfileParsingError, "#{options[:path]} is not a valid directory." unless File.directory?(project_dir)
@@ -47,7 +66,8 @@ module CycloneDX
47
66
 
48
67
  lockfile = ::Pod::Lockfile.from_file(options[:podfile_lock_path])
49
68
  verify_synced_sandbox(lockfile)
50
-
69
+ load_plugins(options[:podfile_path])
70
+
51
71
  return ::Pod::Podfile.from_file(options[:podfile_path]), lockfile
52
72
  end
53
73
 
@@ -88,7 +108,7 @@ module CycloneDX
88
108
  pods_hash = { }
89
109
 
90
110
  pods_used = lockfile.internal_data['PODS']
91
- pods_used.each { |pod|
111
+ pods_used&.each { |pod|
92
112
  if pod.is_a?(String)
93
113
  # Pods stored as String have no dependencies
94
114
  pod_name = pod.split.first
@@ -109,11 +129,13 @@ module CycloneDX
109
129
  original_number = 0
110
130
  # Loop adding pod dependencies until we are not adding any more dependencies to the result
111
131
  # 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.
132
+ # Note this also handles two edge cases:
133
+ # 1. Having a Podfile with no pods used.
134
+ # 2. Having a pod that has a platform-specific dependency that is unused for this Podfile.
113
135
  while result.length != original_number
114
136
  original_number = result.length
115
137
  pods_used.each { |pod_name|
116
- result.push(*pods_cache[pod_name]) unless pods_cache[pod_name].empty?
138
+ result.push(*pods_cache[pod_name]) unless !pods_cache.key?(pod_name) || pods_cache[pod_name].empty?
117
139
  }
118
140
  result = result.uniq
119
141
  pods_used = result
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # This file is part of CycloneDX CocoaPods
3
5
  #
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #
3
4
  # This file is part of CycloneDX CocoaPods
4
5
  #
@@ -20,10 +21,6 @@
20
21
 
21
22
  module CycloneDX
22
23
  module CocoaPods
23
- VERSION = '1.1.0'
24
- DEPENDENCIES = {
25
- cocoapods: '~> 1.10.1',
26
- nokogiri: '~> 1.11.2'
27
- }
24
+ VERSION = '1.1.2'
28
25
  end
29
26
  end
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.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - José González
@@ -9,36 +9,48 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-09-13 00:00:00.000000000 Z
12
+ date: 2023-06-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cocoapods
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 1.10.1
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '2.0'
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
- - - "~>"
28
+ - - ">="
26
29
  - !ruby/object:Gem::Version
27
30
  version: 1.10.1
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: nokogiri
30
36
  requirement: !ruby/object:Gem::Requirement
31
37
  requirements:
32
- - - "~>"
38
+ - - ">="
33
39
  - !ruby/object:Gem::Version
34
40
  version: 1.11.2
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: '2.0'
35
44
  type: :runtime
36
45
  prerelease: false
37
46
  version_requirements: !ruby/object:Gem::Requirement
38
47
  requirements:
39
- - - "~>"
48
+ - - ">="
40
49
  - !ruby/object:Gem::Version
41
50
  version: 1.11.2
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
42
54
  - !ruby/object:Gem::Dependency
43
55
  name: rake
44
56
  requirement: !ruby/object:Gem::Requirement