Class: CycloneDX::CocoaPods::Pod

Inherits:
Object
  • Object
show all
Defined in:
lib/cyclonedx/cocoapods/pod.rb,
lib/cyclonedx/cocoapods/license.rb,
lib/cyclonedx/cocoapods/bom_builder.rb,
lib/cyclonedx/cocoapods/pod_attributes.rb

Defined Under Namespace

Classes: License

Constant Summary collapse

CHECKSUM_ALGORITHM =
'SHA-1'
HOMEPAGE_REFERENCE_TYPE =
'website'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, version:, source: nil, checksum: nil) ⇒ Pod

Returns a new instance of Pod.

Raises:

  • (ArgumentError)


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cyclonedx/cocoapods/pod.rb', line 46

def initialize(name:, version:, source: nil, checksum: nil)
  raise ArgumentError, 'Name must be non-empty' if name.nil? || name.to_s.empty?
  raise ArgumentError, "Name shouldn't contain spaces" if name.to_s.include?(' ')
  raise ArgumentError, "Name shouldn't start with a dot" if name.to_s.start_with?('.')

  # `pod create` also enforces no plus sign, but more than 500 public pods have a plus in the root name.
  # https://github.com/CocoaPods/CocoaPods/blob/9461b346aeb8cba6df71fd4e71661688138ec21b/lib/cocoapods/command/lib/create.rb#L35

  Gem::Version.new(version) # To check that the version string is well formed
  raise ArgumentError, 'Invalid pod source' unless source.nil? || source.respond_to?(:source_qualifier)
  raise ArgumentError, "#{checksum} is not valid SHA-1 hash" unless checksum.nil? || checksum =~ /[a-fA-F0-9]{40}/

  @name = name.to_s
  @version = version
  @source = source
  @checksum = checksum
end

Instance Attribute Details

#authorObject (readonly)

xs:normalizedString



39
40
41
# File 'lib/cyclonedx/cocoapods/pod.rb', line 39

def author
  @author
end

#checksumObject (readonly)

cyclonedx.org/docs/1.6/xml/#type_hashValue (We only use SHA-1 hashes - length == 40)



37
38
39
# File 'lib/cyclonedx/cocoapods/pod.rb', line 37

def checksum
  @checksum
end

#descriptionObject (readonly)

xs:normalizedString



41
42
43
# File 'lib/cyclonedx/cocoapods/pod.rb', line 41

def description
  @description
end

#homepageObject (readonly)



35
36
37
# File 'lib/cyclonedx/cocoapods/pod.rb', line 35

def homepage
  @homepage
end

#licenseObject (readonly)

cyclonedx.org/docs/1.6/xml/#type_licenseType We don’t currently support several licenses or license expressions spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/



44
45
46
# File 'lib/cyclonedx/cocoapods/pod.rb', line 44

def license
  @license
end

#nameObject (readonly)

xs:normalizedString



29
30
31
# File 'lib/cyclonedx/cocoapods/pod.rb', line 29

def name
  @name
end

#sourceObject (readonly)

Anything responding to :source_qualifier



33
34
35
# File 'lib/cyclonedx/cocoapods/pod.rb', line 33

def source
  @source
end

#versionObject (readonly)

xs:normalizedString



31
32
33
# File 'lib/cyclonedx/cocoapods/pod.rb', line 31

def version
  @version
end

Instance Method Details

#add_to_bom(xml, manifest_path, trim_strings_length = 0) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 125

def add_to_bom(xml, manifest_path, trim_strings_length = 0)
  xml.component(type: 'library', 'bom-ref': purl) do
    xml_add_author(xml, trim_strings_length)
    xml.name_ name
    xml.version version.to_s
    # Use `dump` to escape non-printing characters, then remove the starting/trailing double-quotes from `dump`.
    xml.description { xml.cdata description.dump[1..-2] } unless description.nil?
    unless checksum.nil?
      xml.hashes do
        xml.hash_(checksum, alg: CHECKSUM_ALGORITHM)
      end
    end
    unless license.nil?
      xml.licenses do
        license.add_to_bom(xml)
      end
    end
    if trim_strings_length.zero?
      xml.purl purl
    else
      xml.purl purl.slice(0, trim_strings_length)
    end
    xml_add_homepage(xml)

    xml_add_evidence(xml, manifest_path)
  end
end

#complete_information_from_sourceObject



84
85
86
# File 'lib/cyclonedx/cocoapods/pod_attributes.rb', line 84

def complete_information_from_source
  populate(source.attributes_for(pod: self))
end

#generate_json_evidence(manifest_path) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 176

def generate_json_evidence(manifest_path)
  {
    identity: {
      field: 'purl',
      confidence: 0.6,
      methods: [
        {
          technique: 'manifest-analysis',
          confidence: 0.6,
          value: manifest_path
        }
      ]
    }
  }
end

#generate_json_external_referencesObject



170
171
172
173
174
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 170

def generate_json_external_references
  refs = []
  refs << { type: HOMEPAGE_REFERENCE_TYPE, url: homepage } if homepage
  refs.empty? ? nil : refs
end

#populate(attributes) ⇒ Object



68
69
70
71
72
73
74
75
# File 'lib/cyclonedx/cocoapods/pod.rb', line 68

def populate(attributes)
  attributes.transform_keys!(&:to_sym)
  populate_author(attributes)
  populate_description(attributes)
  populate_license(attributes)
  populate_homepage(attributes)
  self
end

#purlObject



78
79
80
81
82
83
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 78

def purl
  purl_name = CGI.escape(name.split('/').first)
  src_qualifier = source_qualifier
  subpath = purl_subpath
  "pkg:cocoapods/#{purl_name}@#{CGI.escape(version.to_s)}#{src_qualifier}#{subpath}"
end

#purl_subpathObject



70
71
72
73
74
75
76
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 70

def purl_subpath
  return '' unless name.split('/').length > 1

  "##{name.split('/').drop(1).map do |component|
        CGI.escape(component)
      end.join('/')}"
end

#root_nameObject



64
65
66
# File 'lib/cyclonedx/cocoapods/pod.rb', line 64

def root_name
  @name.split('/').first
end

#source_qualifierObject



62
63
64
65
66
67
68
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 62

def source_qualifier
  return '' if source.nil? || source.source_qualifier.empty?

  "?#{source.source_qualifier.map do |key, value|
        "#{key}=#{CGI.escape(value)}"
      end.join('&')}"
end

#to_json_component(manifest_path, trim_strings_length = 0) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 153

def to_json_component(manifest_path, trim_strings_length = 0)
  {
    type: 'library',
    'bom-ref': purl,
    author: trim(author, trim_strings_length),
    publisher: trim(author, trim_strings_length),
    name: name,
    version: version.to_s,
    description: description,
    hashes: generate_json_hashes,
    licenses: generate_json_licenses,
    purl: purl,
    externalReferences: generate_json_external_references,
    evidence: generate_json_evidence(manifest_path)
  }.compact
end

#to_sObject



77
78
79
# File 'lib/cyclonedx/cocoapods/pod.rb', line 77

def to_s
  "Pod<#{name}, #{version}>"
end

#xml_add_author(xml, trim_strings_length) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 85

def xml_add_author(xml, trim_strings_length)
  return if author.nil?

  if trim_strings_length.zero?
    xml.author author
    xml.publisher author
  else
    xml.author author.slice(0, trim_strings_length)
    xml.publisher author.slice(0, trim_strings_length)
  end
end

#xml_add_evidence(xml, manifest_path) ⇒ Object

Add evidence of the purl identity. See github.com/CycloneDX/guides/blob/main/SBOM/en/0x60-Evidence.md for more info



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 109

def xml_add_evidence(xml, manifest_path)
  xml.evidence do
    xml.identity do
      xml.field 'purl'
      xml.confidence '0.6'
      xml.methods_ do
        xml.method_ do
          xml.technique 'manifest-analysis'
          xml.confidence '0.6'
          xml.value manifest_path
        end
      end
    end
  end
end

#xml_add_homepage(xml) ⇒ Object



97
98
99
100
101
102
103
104
105
# File 'lib/cyclonedx/cocoapods/bom_builder.rb', line 97

def xml_add_homepage(xml)
  return if homepage.nil?

  xml.externalReferences do
    xml.reference(type: HOMEPAGE_REFERENCE_TYPE) do
      xml.url homepage
    end
  end
end