From 53bfd509056a91b0a5cfea63b1237f9359eabd36 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 18 Dec 2024 07:52:12 -0500 Subject: [PATCH 1/8] feat: optionally output to json resolves #62 Signed-off-by: Jeremy Long --- lib/cyclonedx/cocoapods/bom_builder.rb | 158 ++++++++++++++++++++++++- lib/cyclonedx/cocoapods/cli_runner.rb | 11 +- 2 files changed, 161 insertions(+), 8 deletions(-) diff --git a/lib/cyclonedx/cocoapods/bom_builder.rb b/lib/cyclonedx/cocoapods/bom_builder.rb index ad8f496..150b22e 100644 --- a/lib/cyclonedx/cocoapods/bom_builder.rb +++ b/lib/cyclonedx/cocoapods/bom_builder.rb @@ -149,7 +149,57 @@ def add_to_bom(xml, manifest_path, trim_strings_length = 0) end end + def to_json_component(manifest_path, trim_strings_length = 0) + { + type: "library", + "bom-ref": purl, + author: trim_strings_length.zero? ? author : author&.slice(0, trim_strings_length), + publisher: trim_strings_length.zero? ? author : author&.slice(0, trim_strings_length), + name: name, + version: version.to_s, + description: description, + hashes: checksum ? [{ alg: CHECKSUM_ALGORITHM, content: checksum }] : nil, + licenses: license ? [license.to_json_component] : nil, + purl: trim_strings_length.zero? ? purl : purl.slice(0, trim_strings_length), + externalReferences: generate_json_external_references, + evidence: generate_json_evidence(manifest_path) + }.compact + end + + def generate_json_external_references + refs = [] + refs << { type: HOMEPAGE_REFERENCE_TYPE, url: homepage } if homepage + refs.empty? ? nil : refs + end + + def generate_json_evidence(manifest_path) + { + identity: { + field: 'purl', + confidence: 0.6, + methods: [ + { + technique: 'manifest-analysis', + confidence: 0.6, + value: manifest_path + } + ] + } + } + end + class License + def to_json_component + { + license: { + id: identifier_type == :id ? identifier : nil, + name: identifier_type == :name ? identifier : nil, + text: text, + url: url + }.compact + } + end + def add_to_bom(xml) xml.license do xml.id identifier if identifier_type == :id @@ -186,6 +236,26 @@ def add_to_bom(xml) xml.purl bomref end end + + def to_json_component + { + type: type, + 'bom-ref': bomref, + group: group, + name: name, + version: version, + externalReferences: generate_json_external_references + }.compact + end + + private + + def generate_json_external_references + refs = [] + refs << { type: 'build-system', url: build_system } if build_system + refs << { type: 'vcs', url: vcs } if vcs + refs.empty? ? nil : refs + end end # Represents manufacturer information in a CycloneDX BOM @@ -201,8 +271,28 @@ def add_to_bom(xml) end end + def to_json_component + return nil if all_attributes_nil? + + { + name: name, + url: url, + contact: [generate_json_contact].compact + }.compact + end + private + def generate_json_contact + return nil if contact_info_nil? + + { + name: contact_name, + email: email, + phone: phone + }.compact + end + def all_attributes_nil? [name, url, contact_name, email, phone].all?(&:nil?) end @@ -241,7 +331,7 @@ def initialize(pods:, manifest_path:, component: nil, dependencies: nil, manufac @manufacturer = manufacturer end - def bom(version: 1, trim_strings_length: 0) + def bom(version: 1, trim_strings_length: 0, format: :xml) unless version.to_i.positive? raise ArgumentError, "Incorrect version: #{version} should be an integer greater than 0" @@ -252,24 +342,80 @@ def bom(version: 1, trim_strings_length: 0) "Incorrect string length: #{trim_strings_length} should be an integer greater than 0" end - unchecked_bom(version: version, trim_strings_length: trim_strings_length) - end + unless [:xml, :json].include?(format) + raise ArgumentError, + "Incorrect format: #{format} should be either :xml or :json" + end + unchecked_bom(version: version, trim_strings_length: trim_strings_length, format: format) + end private # does not verify parameters because the public method does that. - def unchecked_bom(version: 1, trim_strings_length: 0) + def unchecked_bom(version:, trim_strings_length:, format:) + case format + when :json + generate_json(version: version, trim_strings_length: trim_strings_length) + when :xml + generate_xml(version: version, trim_strings_length: trim_strings_length) + end + end + + def generate_xml(version:, trim_strings_length:) Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| xml.bom(xmlns: NAMESPACE, version: version.to_i.to_s, serialNumber: "urn:uuid:#{SecureRandom.uuid}") do bom_metadata(xml) - bom_components(xml, pods, manifest_path, trim_strings_length) - bom_dependencies(xml, dependencies) end end.to_xml end + def generate_json(version:, trim_strings_length:) + { + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + bomFormat: "CycloneDX", + specVersion: version.to_s, + serialNumber: "urn:uuid:#{SecureRandom.uuid}", + version: 1, + metadata: generate_json_metadata, + components: generate_json_components(trim_strings_length), + dependencies: generate_json_dependencies + }.to_json + end + + private + + def generate_json_metadata + { + timestamp: Time.now.getutc.strftime('%Y-%m-%dT%H:%M:%SZ'), + tools: { + components: [{ + type: "application", + group: "CycloneDX", + name: "cyclonedx-cocoapods", + version: VERSION + }] + }, + component: component&.to_json_component, + manufacturer: manufacturer&.to_json_component + }.compact + end + + def generate_json_components(trim_strings_length) + pods.map { |pod| pod.to_json_component(manifest_path, trim_strings_length) } + end + + def generate_json_dependencies + return nil unless dependencies + + dependencies.map do |ref, deps| + { + ref: ref, + dependsOn: deps.sort + } + end + end def bom_components(xml, pods, manifest_path, trim_strings_length) xml.components do pods.each do |pod| diff --git a/lib/cyclonedx/cocoapods/cli_runner.rb b/lib/cyclonedx/cocoapods/cli_runner.rb index cd9616a..4006793 100644 --- a/lib/cyclonedx/cocoapods/cli_runner.rb +++ b/lib/cyclonedx/cocoapods/cli_runner.rb @@ -38,6 +38,7 @@ class CLIRunner def run setup_logger # Needed in case we have errors while processing CLI parameters options = parse_options + determine_output_format(options) setup_logger(verbose: options[:verbose]) @logger.debug "Running cyclonedx-cocoapods with options: #{options}" @@ -78,7 +79,8 @@ def parse_options parsed_options[:path] = path end options.on('-o', '--output bom_file_path', - 'Path to output the bom.xml file to (default: "bom.xml")') do |bom_file_path| + 'Path to output the bom file to (default: "bom.xml"); ' \ + 'if a *.json file is specified the output format will be json') do |bom_file_path| parsed_options[:bom_file_path] = bom_file_path end options.on('-b', '--bom-version bom_version', Integer, @@ -163,6 +165,10 @@ def parse_options parsed_options end + def determine_output_format(options) + options[:format] = options[:bom_file_path]&.end_with?('.json') ? :json : :xml + end + def analyze(options) analyzer, dependencies, lockfile, podfile, pods = analyze_podfile(options) podspec = analyze_podspec(options) @@ -203,7 +209,8 @@ def build_and_write_bom(options, component, manufacturer, pods, manifest_path, d builder = BOMBuilder.new(pods: pods, manifest_path: manifest_path, component: component, manufacturer: manufacturer, dependencies: dependencies) bom = builder.bom(version: options[:bom_version] || 1, - trim_strings_length: options[:trim_strings_length] || 0) + trim_strings_length: options[:trim_strings_length] || 0, + format: options[:format]) write_bom_to_file(bom: bom, options: options) end From 9f69edd44215105d17fb18ded6a5c32f35f35a3e Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 18 Dec 2024 08:16:04 -0500 Subject: [PATCH 2/8] style: codacy warnings Signed-off-by: Jeremy Long --- .rubocop.yml | 7 ++++++- lib/cyclonedx/cocoapods/bom_builder.rb | 25 +++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 00a5c64..457ac32 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -35,7 +35,12 @@ Metrics/BlockLength: # Allow some long methods because breaking them up doesn't help anything. Metrics/MethodLength: - AllowedMethods: ['parse_options', 'add_to_bom', 'append_all_pod_dependencies', 'xml_add_evidence'] + AllowedMethods: + - 'parse_options' + - 'add_to_bom' + - 'append_all_pod_dependencies' + - 'xml_add_evidence' + - !ruby/regexp /^generate_json.*/ Metrics/AbcSize: AllowedMethods: ['parse_options', 'add_to_bom', 'source_for_pod'] diff --git a/lib/cyclonedx/cocoapods/bom_builder.rb b/lib/cyclonedx/cocoapods/bom_builder.rb index 150b22e..a43390a 100644 --- a/lib/cyclonedx/cocoapods/bom_builder.rb +++ b/lib/cyclonedx/cocoapods/bom_builder.rb @@ -153,14 +153,14 @@ def to_json_component(manifest_path, trim_strings_length = 0) { type: "library", "bom-ref": purl, - author: trim_strings_length.zero? ? author : author&.slice(0, trim_strings_length), - publisher: trim_strings_length.zero? ? author : author&.slice(0, trim_strings_length), + author: trim(author, trim_strings_length), + publisher: trim(author, trim_strings_length), name: name, version: version.to_s, description: description, hashes: checksum ? [{ alg: CHECKSUM_ALGORITHM, content: checksum }] : nil, licenses: license ? [license.to_json_component] : nil, - purl: trim_strings_length.zero? ? purl : purl.slice(0, trim_strings_length), + purl: purl, externalReferences: generate_json_external_references, evidence: generate_json_evidence(manifest_path) }.compact @@ -209,6 +209,12 @@ def add_to_bom(xml) end end end + + private + + def trim(str, trim_strings_length) + trim_strings_length.zero? ? str : str&.slice(0, trim_strings_length) + end end class Component @@ -349,6 +355,7 @@ def bom(version: 1, trim_strings_length: 0, format: :xml) unchecked_bom(version: version, trim_strings_length: trim_strings_length, format: format) end + private # does not verify parameters because the public method does that. @@ -373,8 +380,8 @@ def generate_xml(version:, trim_strings_length:) def generate_json(version:, trim_strings_length:) { - "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", - bomFormat: "CycloneDX", + '$schema': 'https://cyclonedx.org/schema/bom-1.6.schema.json', + bomFormat: 'CycloneDX', specVersion: version.to_s, serialNumber: "urn:uuid:#{SecureRandom.uuid}", version: 1, @@ -384,16 +391,14 @@ def generate_json(version:, trim_strings_length:) }.to_json end - private - def generate_json_metadata { timestamp: Time.now.getutc.strftime('%Y-%m-%dT%H:%M:%SZ'), tools: { components: [{ - type: "application", - group: "CycloneDX", - name: "cyclonedx-cocoapods", + type: 'application', + group: 'CycloneDX', + name: 'cyclonedx-cocoapods', version: VERSION }] }, From c69824916a849537a9912a4219299e3b2e0eae12 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 18 Dec 2024 09:14:11 -0500 Subject: [PATCH 3/8] style: fix codacy warnings Signed-off-by: Jeremy Long --- .rubocop.yml | 4 +++- lib/cyclonedx/cocoapods/bom_builder.rb | 29 ++++++++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 457ac32..9e26475 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -40,7 +40,9 @@ Metrics/MethodLength: - 'add_to_bom' - 'append_all_pod_dependencies' - 'xml_add_evidence' - - !ruby/regexp /^generate_json.*/ + - 'generate_json_metadata' + - 'generate_json_evidence' + - 'to_json_component' Metrics/AbcSize: AllowedMethods: ['parse_options', 'add_to_bom', 'source_for_pod'] diff --git a/lib/cyclonedx/cocoapods/bom_builder.rb b/lib/cyclonedx/cocoapods/bom_builder.rb index a43390a..84d02c4 100644 --- a/lib/cyclonedx/cocoapods/bom_builder.rb +++ b/lib/cyclonedx/cocoapods/bom_builder.rb @@ -151,15 +151,15 @@ def add_to_bom(xml, manifest_path, trim_strings_length = 0) def to_json_component(manifest_path, trim_strings_length = 0) { - type: "library", - "bom-ref": purl, + 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: checksum ? [{ alg: CHECKSUM_ALGORITHM, content: checksum }] : nil, - licenses: license ? [license.to_json_component] : nil, + hashes: generate_json_hashes, + licenses: generate_json_licenses, purl: purl, externalReferences: generate_json_external_references, evidence: generate_json_evidence(manifest_path) @@ -212,6 +212,14 @@ def add_to_bom(xml) private + def generate_json_licenses + license ? [license.to_json_component] : nil + end + + def generate_json_hashes + checksum ? [{ alg: CHECKSUM_ALGORITHM, content: checksum }] : nil + end + def trim(str, trim_strings_length) trim_strings_length.zero? ? str : str&.slice(0, trim_strings_length) end @@ -338,6 +346,13 @@ def initialize(pods:, manifest_path:, component: nil, dependencies: nil, manufac end def bom(version: 1, trim_strings_length: 0, format: :xml) + validate_bom_args(version, trim_strings_length, format) + unchecked_bom(version: version, trim_strings_length: trim_strings_length, format: format) + end + + private + + def validate_bom_args(version, trim_strings_length, format) unless version.to_i.positive? raise ArgumentError, "Incorrect version: #{version} should be an integer greater than 0" @@ -348,16 +363,12 @@ def bom(version: 1, trim_strings_length: 0, format: :xml) "Incorrect string length: #{trim_strings_length} should be an integer greater than 0" end - unless [:xml, :json].include?(format) + unless %i[xml json].include?(format) raise ArgumentError, "Incorrect format: #{format} should be either :xml or :json" end - - unchecked_bom(version: version, trim_strings_length: trim_strings_length, format: format) end - private - # does not verify parameters because the public method does that. def unchecked_bom(version:, trim_strings_length:, format:) case format From 4812926672ff8b24ae44ce71ef9d0e65b7e37681 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Wed, 18 Dec 2024 10:15:26 -0500 Subject: [PATCH 4/8] style: fix codacy warnings Signed-off-by: Jeremy Long --- lib/cyclonedx/cocoapods/bom_builder.rb | 32 +++++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/cyclonedx/cocoapods/bom_builder.rb b/lib/cyclonedx/cocoapods/bom_builder.rb index 84d02c4..e8104a4 100644 --- a/lib/cyclonedx/cocoapods/bom_builder.rb +++ b/lib/cyclonedx/cocoapods/bom_builder.rb @@ -346,27 +346,31 @@ def initialize(pods:, manifest_path:, component: nil, dependencies: nil, manufac end def bom(version: 1, trim_strings_length: 0, format: :xml) - validate_bom_args(version, trim_strings_length, format) + validate_version(version) + validate_trim_length(trim_strings_length) + validate_format(format) + unchecked_bom(version: version, trim_strings_length: trim_strings_length, format: format) end private - def validate_bom_args(version, trim_strings_length, format) - unless version.to_i.positive? - raise ArgumentError, - "Incorrect version: #{version} should be an integer greater than 0" - end + def validate_version(version) + return if version.to_i.positive? - unless trim_strings_length.is_a?(Integer) && (trim_strings_length.positive? || trim_strings_length.zero?) - raise ArgumentError, - "Incorrect string length: #{trim_strings_length} should be an integer greater than 0" - end + raise ArgumentError, "Incorrect version: #{version} should be an integer greater than 0" + end - unless %i[xml json].include?(format) - raise ArgumentError, - "Incorrect format: #{format} should be either :xml or :json" - end + def validate_trim_length(trim_strings_length) + return if trim_strings_length.is_a?(Integer) && (trim_strings_length.positive? || trim_strings_length.zero?) + + raise ArgumentError, "Incorrect string length: #{trim_strings_length} should be an integer greater than 0" + end + + def validate_format(format) + return if %i[xml json].include?(format) + + raise ArgumentError, "Incorrect format: #{format} should be either :xml or :json" end # does not verify parameters because the public method does that. From b76e3e9837b1efc2fbb380e93b6c00669ff47c1e Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 21 Dec 2024 08:32:15 -0500 Subject: [PATCH 5/8] feat: add json tests Signed-off-by: Jeremy Long --- .rubocop.yml | 1 + lib/cyclonedx/cocoapods/bom_builder.rb | 23 +- spec/cyclonedx/cocoapods/bom_builder_spec.rb | 536 ++++++++++++++++++- 3 files changed, 549 insertions(+), 11 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9e26475..fdec64a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -43,6 +43,7 @@ Metrics/MethodLength: - 'generate_json_metadata' - 'generate_json_evidence' - 'to_json_component' + - 'to_json_manufacturer' Metrics/AbcSize: AllowedMethods: ['parse_options', 'add_to_bom', 'source_for_pod'] diff --git a/lib/cyclonedx/cocoapods/bom_builder.rb b/lib/cyclonedx/cocoapods/bom_builder.rb index e8104a4..2d679c5 100644 --- a/lib/cyclonedx/cocoapods/bom_builder.rb +++ b/lib/cyclonedx/cocoapods/bom_builder.rb @@ -258,6 +258,7 @@ def to_json_component group: group, name: name, version: version, + purl: bomref, externalReferences: generate_json_external_references }.compact end @@ -285,13 +286,13 @@ def add_to_bom(xml) end end - def to_json_component + def to_json_manufacturer return nil if all_attributes_nil? { name: name, url: url, - contact: [generate_json_contact].compact + contact: generate_json_contact }.compact end @@ -300,11 +301,13 @@ def to_json_component def generate_json_contact return nil if contact_info_nil? - { - name: contact_name, - email: email, - phone: phone - }.compact + [ + { + name: contact_name, + email: email, + phone: phone + }.compact + ] end def all_attributes_nil? @@ -397,9 +400,9 @@ def generate_json(version:, trim_strings_length:) { '$schema': 'https://cyclonedx.org/schema/bom-1.6.schema.json', bomFormat: 'CycloneDX', - specVersion: version.to_s, + specVersion: '1.6', serialNumber: "urn:uuid:#{SecureRandom.uuid}", - version: 1, + version: version.to_s, metadata: generate_json_metadata, components: generate_json_components(trim_strings_length), dependencies: generate_json_dependencies @@ -418,7 +421,7 @@ def generate_json_metadata }] }, component: component&.to_json_component, - manufacturer: manufacturer&.to_json_component + manufacturer: manufacturer&.to_json_manufacturer }.compact end diff --git a/spec/cyclonedx/cocoapods/bom_builder_spec.rb b/spec/cyclonedx/cocoapods/bom_builder_spec.rb index 548993a..8172a39 100644 --- a/spec/cyclonedx/cocoapods/bom_builder_spec.rb +++ b/spec/cyclonedx/cocoapods/bom_builder_spec.rb @@ -42,6 +42,12 @@ pod.add_to_bom(xml, 'unused.lock') end.to_xml) end + let(:json) do + pod.to_json_component('unused.lock') + end + let(:json_short) do + pod.to_json_component('unused.lock', 7) + end let(:shortXML) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| @@ -54,21 +60,46 @@ expect(xml.at('/component')).not_to be_nil expect(xml.at('/component')['type']).to eql('library') end + context 'for JSON' do + it 'should generate a component of type library' do + expect(json[:type]).not_to be_nil + expect(json[:type]).to eql('library') + end + end it 'should generate a correct component name' do expect(xml.at('/component/name')).not_to be_nil expect(xml.at('/component/name').text).to eql(pod.name) end + context 'for JSON' do + it 'should generate a correct component name' do + expect(json[:name]).not_to be_nil + expect(json[:name]).to eql(pod.name) + end + end it 'should generate a correct component version' do expect(xml.at('/component/version')).not_to be_nil expect(xml.at('/component/version').text).to eql(pod.version.to_s) end + context 'for JSON' do + it 'should generate a correct component version' do + expect(json[:version]).not_to be_nil + expect(json[:version]).to eql(pod.version.to_s) + end + end + it 'should generate a correct component purl' do expect(xml.at('/component/purl')).not_to be_nil expect(xml.at('/component/purl').text).to eql(pod.purl) end + context 'for JSON' do + it 'should generate a correct component purl' do + expect(json[:purl]).not_to be_nil + expect(json[:purl]).to eql(pod.purl) + end + end context 'when shortening to a limited string length' do it 'should truncate the purl to the right number of characters' do @@ -82,6 +113,13 @@ expect(xml.at('/component/author')).to be_nil expect(xml.at('/component/publisher')).to be_nil end + + context 'for JSON' do + it 'shouldn\'t generate a component author' do + expect(json[:author]).to be_nil + expect(json[:publisher]).to be_nil + end + end end context 'when having an author' do @@ -96,6 +134,15 @@ expect(xml.at('/component/publisher').text).to eql(pod.author) end + context 'for JSON' do + it 'should generate a correct component author' do + expect(json[:author]).not_to be_nil + expect(json[:author]).to eql(pod.author) + expect(json[:publisher]).not_to be_nil + expect(json[:publisher]).to eql(pod.author) + end + end + context 'when shortening to a limited string length' do it 'should truncate the author to the right number of characters' do expect(shortXML.at('/component/author')).not_to be_nil @@ -103,6 +150,15 @@ expect(shortXML.at('/component/publisher')).not_to be_nil expect(shortXML.at('/component/publisher').text).to eql('Darth V') end + + context 'for JSON' do + it 'should truncate the author to the right number of characters' do + expect(json_short[:author]).not_to be_nil + expect(json_short[:author]).to eql('Darth V') + expect(json_short[:publisher]).not_to be_nil + expect(json_short[:publisher]).to eql('Darth V') + end + end end end @@ -110,6 +166,12 @@ it 'shouldn\'t generate a component description' do expect(xml.at('/component/description')).to be_nil end + + context 'for JSON' do + it 'shouldn\'t generate a component description' do + expect(json[:description]).to be_nil + end + end end context 'when having a description' do @@ -121,6 +183,13 @@ expect(xml.at('/component/description')).not_to be_nil expect(xml.at('/component/description').text).to eql(pod.description) end + + context 'for JSON' do + it 'should generate a correct component description' do + expect(json[:description]).not_to be_nil + expect(json[:description]).to eql(pod.description) + end + end end context 'when not having a checksum' do @@ -129,6 +198,12 @@ it 'shouldn\'t generate a component hash' do expect(xml.at('/component/hashes')).to be_nil end + + context 'for JSON' do + it 'shouldn\'t generate a component hash' do + expect(json[:hashes]).to be_nil + end + end end context 'when having a checksum' do @@ -138,12 +213,24 @@ expect(xml.at('/component/hashes/hash')['alg']).to eq(described_class::CHECKSUM_ALGORITHM) expect(xml.at('/component/hashes/hash').text).to eql(pod.checksum) end + context 'for JSON' do + it 'should generate a correct component hash' do + expect(json[:hashes]).not_to be_nil + expect(json[:hashes][0][:alg]).to eq(described_class::CHECKSUM_ALGORITHM) + expect(json[:hashes][0][:content]).to eql(pod.checksum) + end + end end context 'when not having a license' do it 'shouldn\'t generate a license list' do expect(xml.at('/component/licenses')).to be_nil end + context 'for JSON' do + it 'shouldn\'t generate a license list' do + expect(json[:licenses]).to be_nil + end + end end context 'when having a license' do @@ -154,6 +241,11 @@ it 'should generate a child licenses node' do expect(xml.at('/component/licenses')).not_to be_nil end + context 'for JSON' do + it 'should generate a correct license list' do + expect(json[:licenses]).not_to be_nil + end + end it 'should properly delegate license node generation' do license_generated_from_pod = xml.xpath('/component/licenses/license')[0] @@ -170,6 +262,11 @@ it 'shouldn\'t generate an external references list' do expect(xml.at('/component/externalReferences')).to be_nil end + context 'for JSON' do + it 'shouldn\'t generate an external references list' do + expect(json[:externalReferences]).to be_nil + end + end end context 'when having a homepage' do @@ -185,8 +282,238 @@ expect(xml.at('/component/externalReferences/reference/url')).not_to be_nil expect(xml.at('/component/externalReferences/reference/url').text).to eq(homepage) end + + context 'for JSON' do + it 'should properly generate a component external references list' do + expect(json[:externalReferences]).not_to be_nil + expect(json[:externalReferences].length).to eq(1) + expect(json[:externalReferences][0][:type]).to eq(described_class::HOMEPAGE_REFERENCE_TYPE) + expect(json[:externalReferences][0][:url]).to eq(homepage) + end + end end end + + + context 'when generating a pod component in a BOM for JSON' do + it 'should generate a root component of type library' do + expect(xml.at('/component')).not_to be_nil + expect(xml.at('/component')['type']).to eql('library') + end + context 'for JSON' do + it 'should generate a root component of type library' do + expect(json[:type]).to eql('library') + end + end + + it 'should generate a correct component name' do + expect(xml.at('/component/name')).not_to be_nil + expect(xml.at('/component/name').text).to eql(pod.name) + end + + context 'for JSON' do + it 'should generate a correct component name' do + expect(json[:name]).to eql(pod.name) + end + end + + it 'should generate a correct component version' do + expect(xml.at('/component/version')).not_to be_nil + expect(xml.at('/component/version').text).to eql(pod.version.to_s) + end + + context 'for JSON' do + it 'should generate a correct component version' do + expect(json[:version]).to eql(pod.version.to_s) + end + end + + it 'should generate a correct component purl' do + expect(xml.at('/component/purl')).not_to be_nil + expect(xml.at('/component/purl').text).to eql(pod.purl) + end + context 'for JSON' do + it 'should generate a correct component purl' do + expect(json[:purl]).to eql(pod.purl) + end + end + + context 'when shortening to a limited string length' do + it 'should truncate the purl to the right number of characters' do + expect(shortXML.at('/component/purl')).not_to be_nil + expect(shortXML.at('/component/purl').text).to eql('pkg:coc') + end + end + + context 'when not having an author' do + it 'shouldn\'t generate a component author' do + expect(xml.at('/component/author')).to be_nil + expect(xml.at('/component/publisher')).to be_nil + end + context 'for JSON' do + it 'shouldn\'t generate a component author' do + expect(json[:author]).to be_nil + expect(json[:publisher]).to be_nil + end + end + end + + context 'when having an author' do + let(:pod) do + described_class.new(name: pod_name, version: pod_version, checksum: checksum).populate(author: author) + end + + it 'should generate a correct component author' do + expect(xml.at('/component/author')).not_to be_nil + expect(xml.at('/component/author').text).to eql(pod.author) + expect(xml.at('/component/publisher')).not_to be_nil + expect(xml.at('/component/publisher').text).to eql(pod.author) + end + context 'for JSON' do + it 'should generate a correct component author' do + expect(json[:author]).to eql(pod.author) + expect(json[:publisher]).to eql(pod.author) + end + end + + context 'when shortening to a limited string length' do + it 'should truncate the author to the right number of characters' do + expect(shortXML.at('/component/author')).not_to be_nil + expect(shortXML.at('/component/author').text).to eql('Darth V') + expect(shortXML.at('/component/publisher')).not_to be_nil + expect(shortXML.at('/component/publisher').text).to eql('Darth V') + end + context 'for JSON' do + it 'should truncate the author to the right number of characters' do + expect(json_short[:author]).to eql('Darth V') + expect(json_short[:publisher]).to eql('Darth V') + end + end + end + end + + context 'when not having a description' do + it 'shouldn\'t generate a component description' do + expect(xml.at('/component/description')).to be_nil + end + context 'for JSON' do + it 'shouldn\'t generate a component description' do + expect(json[:description]).to be_nil + end + end + end + + context 'when having a description' do + let(:pod) do + described_class.new(name: pod_name, version: pod_version, checksum: checksum).populate(summary: summary) + end + + it 'should generate a correct component description' do + expect(xml.at('/component/description')).not_to be_nil + expect(xml.at('/component/description').text).to eql(pod.description) + end + context 'for JSON' do + it 'should generate a correct component description' do + expect(json[:description]).to eql(pod.description) + end + end + end + + context 'when not having a checksum' do + let(:pod) { described_class.new(name: pod_name, version: pod_version) } + + it 'shouldn\'t generate a component hash' do + expect(xml.at('/component/hashes')).to be_nil + end + context 'for JSON' do + it 'shouldn\'t generate a component hash' do + expect(json[:hashes]).to be_nil + end + end + end + + context 'when having a checksum' do + it 'should generate a correct component hash' do + expect(xml.at('/component/hashes/hash')).not_to be_nil + # CocoaPods always uses SHA-1 + expect(xml.at('/component/hashes/hash')['alg']).to eq(described_class::CHECKSUM_ALGORITHM) + expect(xml.at('/component/hashes/hash').text).to eql(pod.checksum) + end + context 'for JSON' do + it 'should generate a correct component hash' do + expect(json[:hashes]).to eq([{ alg: described_class::CHECKSUM_ALGORITHM, content: pod.checksum }]) + end + end + end + + context 'when not having a license' do + it 'shouldn\'t generate a license list' do + expect(xml.at('/component/licenses')).to be_nil + end + context 'for JSON' do + it 'shouldn\'t generate a license list' do + expect(json[:licenses]).to be_nil + end + end + end + + context 'when having a license' do + let(:pod) do + described_class.new(name: pod_name, version: pod_version, checksum: checksum).populate(license: 'MIT') + end + + it 'should generate a child licenses node' do + expect(xml.at('/component/licenses')).not_to be_nil + end + context 'for JSON' do + it 'should generate a child licenses node' do + expect(json[:licenses]).to eq([{ license: { id: 'MIT' } }]) + end + end + + it 'should properly delegate license node generation' do + license_generated_from_pod = xml.xpath('/component/licenses/license')[0] + + license = Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| + pod.license.add_to_bom(xml) + end.to_xml).at('/license') + + expect(license_generated_from_pod).to be_equivalent_to(license) + end + end + + context 'when not having a homepage' do + it 'shouldn\'t generate an external references list' do + expect(xml.at('/component/externalReferences')).to be_nil + end + context 'for JSON' do + it 'shouldn\'t generate an external references list' do + expect(json[:externalReferences]).to be_nil + end + end + end + + context 'when having a homepage' do + let(:pod) do + described_class.new(name: pod_name, version: pod_version, checksum: checksum).populate(homepage: homepage) + end + + it 'should properly generate a component external references list' do + expect(xml.at('/component/externalReferences')).not_to be_nil + expect(xml.at('/component/externalReferences/reference')).not_to be_nil + actual = xml.at('/component/externalReferences/reference')['type'] + expect(actual).to eq(described_class::HOMEPAGE_REFERENCE_TYPE) + expect(xml.at('/component/externalReferences/reference/url')).not_to be_nil + expect(xml.at('/component/externalReferences/reference/url').text).to eq(homepage) + end + context 'for JSON' do + it 'should properly generate a component external references list' do + expect(json[:externalReferences]).to eq([{ type: described_class::HOMEPAGE_REFERENCE_TYPE, url: homepage }]) + end + end + end + end + end RSpec.describe CycloneDX::CocoaPods::Pod::License do @@ -198,21 +525,41 @@ license.add_to_bom(xml) end.to_xml) end + let(:json) do + license.to_json_component() + end it 'should generate a root license element' do expect(xml.at('/license')).not_to be_nil end + context 'for JSON' do + it 'should generate a root license element' do + expect(json[:license]).not_to be_nil + end + end it 'should generate a correct license identifier' do expect(xml.at('/license/id')).not_to be_nil expect(xml.at('/license/id').text).to eq(license.identifier) expect(xml.at('/license/name')).to be_nil end + context 'for JSON' do + it 'should generate a correct license identifier' do + expect(json[:license][:id]).to eq(license.identifier) + expect(json[:license][:name]).to be_nil + end + end it 'should not create text or url elements' do expect(xml.at('/license/text')).to be_nil expect(xml.at('/license/url')).to be_nil end + context 'for JSON' do + it 'should not create text or url elements' do + expect(json[:license][:text]).to be_nil + expect(json[:license][:url]).to be_nil + end + end context 'which includes text' do let(:license) do @@ -225,6 +572,11 @@ expect(xml.at('/license/text')).not_to be_nil expect(xml.at('/license/text').text).to eq(license.text) end + context 'for JSON' do + it 'should create text element' do + expect(json[:license][:text]).to eq(license.text) + end + end end context 'which includes url' do @@ -238,6 +590,11 @@ expect(xml.at('/license/url')).not_to be_nil expect(xml.at('/license/url').text).to eq(license.url) end + context 'for JSON' do + it 'should create text element' do + expect(json[:license][:url]).to eq(license.url) + end + end end end end @@ -266,6 +623,9 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end + let(:json) do + component.to_json_component() + end it_behaves_like 'component' @@ -274,6 +634,12 @@ expect(xml.at('/component')['bom-ref']).to eq('pkg:generic/Application@1.3.5') expect(xml.at('/component/purl').text).to eq('pkg:generic/Application@1.3.5') end + context 'for JSON' do + it 'should not generate any group element' do + expect(json[:group]).to be_nil + expect(json[:'bom-ref']).to eq('pkg:generic/Application@1.3.5') + end + end end context 'without a group and type library' do @@ -313,6 +679,9 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end + let(:json) do + component.to_json_component() + end it_behaves_like 'component' @@ -322,6 +691,13 @@ expect(xml.at('/component')['bom-ref']).to eq('pkg:generic/application-group/Application@1.3.5') expect(xml.at('/component/purl').text).to eq('pkg:generic/application-group/Application@1.3.5') end + context 'for JSON' do + it 'should generate a proper group element' do + expect(json[:group]).to eq(component.group) + expect(json[:'bom-ref']).to eq('pkg:generic/application-group/Application@1.3.5') + expect(json[:purl]).to eq('pkg:generic/application-group/Application@1.3.5') + end + end end ## this test is just for completeness, the group is not used for libraries @@ -332,6 +708,9 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end + let(:json) do + component.to_json_component() + end it_behaves_like 'component' @@ -341,6 +720,12 @@ expect(xml.at('/component')['bom-ref']).to eq('pkg:generic/application-group/Application@1.3.5') expect(xml.at('/component/purl').text).to eq('pkg:generic/application-group/Application@1.3.5') end + context 'for JSON' do + it 'should generate a proper group element' do + expect(json[:group]).to eq(component.group) + expect(json[:'bom-ref']).to eq('pkg:generic/application-group/Application@1.3.5') + end + end end context 'with a vcs' do @@ -351,6 +736,9 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end + let(:json) do + component.to_json_component() + end it_behaves_like 'component' @@ -361,6 +749,13 @@ expect(xml.at('/component/externalReferences/reference')['type']).to eq('vcs') expect(xml.at('/component/externalReferences/reference/url').text).to eq(component.vcs) end + context 'for JSON' do + it 'should generate a proper external references for vcs' do + expect(json[:group]).to eq(component.group) + expect(json[:'bom-ref']).to eq('pkg:generic/application-group/Application@1.3.5') + expect(json[:externalReferences]).to eq([{ type: 'vcs', url: component.vcs }]) + end + end end context 'with a build system' do @@ -371,6 +766,9 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end + let(:json) do + component.to_json_component() + end it_behaves_like 'component' @@ -381,6 +779,13 @@ expect(xml.at('/component/externalReferences/reference')['type']).to eq('build-system') expect(xml.at('/component/externalReferences/reference/url').text).to eq(component.build_system) end + context 'for JSON' do + it 'should generate a proper external reference element for build-systems' do + expect(json[:group]).to eq(component.group) + expect(json[:'bom-ref']).to eq('pkg:generic/application-group/Application@1.3.5') + expect(json[:externalReferences]).to eq([{ type: 'build-system', url: component.build_system }]) + end + end end end end @@ -391,6 +796,11 @@ it 'should generate a root manufacturer element' do expect(xml.at('/manufacturer')).not_to be_nil end + context 'for JSON' do + it 'should generate a root manufacturer element' do + expect(json).not_to be_nil + end + end it 'should generate proper manufacturer information' do expect(xml.at('/manufacturer/name')).not_to be_nil if manufacturer.name @@ -398,6 +808,12 @@ expect(xml.at('/manufacturer/url')).not_to be_nil if manufacturer.url expect(xml.at('/manufacturer/url')&.text).to eq(manufacturer.url) if manufacturer.url end + context 'for JSON' do + it 'should generate proper manufacturer information' do + expect(json[:name]).to eq(manufacturer.name) if manufacturer.name + expect(json[:url]).to eq(manufacturer.url) if manufacturer.url + end + end end context 'without contact information' do @@ -405,12 +821,19 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| manufacturer.add_to_bom(xml) }.to_xml) end - + let(:json) do + manufacturer.to_json_manufacturer() + end it_behaves_like 'manufacturer' it 'should not generate any contact element' do expect(xml.at('/manufacturer/contact')).to be_nil end + context 'for JSON' do + it 'should not generate any contact element' do + expect(json[:contact]).to be_nil + end + end end context 'with contact information' do @@ -426,6 +849,9 @@ let(:xml) do Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| manufacturer.add_to_bom(xml) }.to_xml) end + let(:json) do + manufacturer.to_json_manufacturer() + end it_behaves_like 'manufacturer' @@ -435,6 +861,13 @@ expect(xml.at('/manufacturer/contact/email').text).to eq(manufacturer.email) expect(xml.at('/manufacturer/contact/phone').text).to eq(manufacturer.phone) end + context 'for JSON' do + it 'should generate proper contact elements' do + expect(json[:contact][0][:name]).to eq(manufacturer.contact_name) + expect(json[:contact][0][:email]).to eq(manufacturer.email) + expect(json[:contact][0][:phone]).to eq(manufacturer.phone) + end + end end end end @@ -888,4 +1321,105 @@ it_behaves_like 'bom_generator' end end + + context 'when generating a JSON BOM' do + let(:pods) do + { + 'Alamofire' => '5.6.2', + 'FirebaseAnalytics' => '7.10.0', + 'RxSwift' => '5.1.2', + 'Realm' => '5.5.1', + 'MSAL' => '1.2.1', + 'MSAL/app-lib' => '1.2.1' + }.map do |name, version| + pod = CycloneDX::CocoaPods::Pod.new(name: name, version: version) + pod.populate(author: 'Chewbacca') + pod + end + end + let(:bom_builder) { described_class.new(pods: pods, manifest_path: 'sample_manifest.lock') } + let(:version) { Random.rand(1..100) } + let(:bom_json) { JSON.parse(bom_builder.bom(version: version, format: :json), symbolize_names: true) } + + it 'should generate proper root level attributes' do + expect(bom_json[:bomFormat]).to eq('CycloneDX') + expect(bom_json[:specVersion]).to eq('1.6') + expect(bom_json[:version]).to eq(version.to_s) + expect(bom_json[:serialNumber]).to match(/urn:uuid:.*/) + end + + it 'should include metadata with timestamp and tools' do + expect(bom_json[:metadata][:timestamp]).not_to be_nil + expect(bom_json[:metadata][:tools][:components][0][:group]).to eq('CycloneDX') + expect(bom_json[:metadata][:tools][:components][0][:name]).to eq('cyclonedx-cocoapods') + expect(bom_json[:metadata][:tools][:components][0][:version]).to eq(CycloneDX::CocoaPods::VERSION) + end + + it 'should generate components in alphabetical order' do + component_purls = bom_json[:components].map { |c| c[:purl] } + expect(component_purls).to eq(component_purls.sort) + end + + it 'should properly generate pod components' do + expect(bom_json[:components].length).to eq(pods.length) + expect(bom_json[:components].first).to include( + type: 'library', + name: 'Alamofire', + version: '5.6.2', + author: 'Chewbacca', + publisher: 'Chewbacca', + purl: 'pkg:cocoapods/Alamofire@5.6.2' + ) + end + + context 'when asked to shorten strings' do + let(:short_json) { JSON.parse(bom_builder.bom(version: version, format: :json, trim_strings_length: 6), symbolize_names: true) } + + it 'should properly trim the author, publisher, and purl' do + expect(short_json[:components].first).to include( + author: 'Chewba', + publisher: 'Chewba', + purl: 'pkg:cocoapods/Alamofire@5.6.2' + ) + end + end + + context 'with dependencies' do + let(:component) do + CycloneDX::CocoaPods::Component.new( + name: 'Application', + version: '1.3.5', + type: 'application' + ) + end + let(:dependencies) do + { + 'pkg:cocoapods/Alamofire@5.6.2' => [], + 'pkg:cocoapods/MSAL@1.2.1' => ['pkg:cocoapods/MSAL@1.2.1#app-lib'], + 'pkg:cocoapods/FirebaseAnalytics@7.10.0' => [], + 'pkg:cocoapods/RxSwift@5.1.2' => [], + 'pkg:cocoapods/Realm@5.5.1' => [] + } + end + let(:bom_builder) do + described_class.new( + component: component, + manifest_path: 'sample_manifest.lock', + pods: pods, + dependencies: dependencies + ) + end + + it 'should generate dependencies in alphabetical order' do + dependency_refs = bom_json[:dependencies].map { |d| d[:ref] } + expect(dependency_refs).to eq(dependency_refs.sort) + end + + it 'should properly generate nested dependencies' do + msal_dependency = bom_json[:dependencies].find { |d| d[:ref] == 'pkg:cocoapods/MSAL@1.2.1' } + expect(msal_dependency[:dependsOn]).to eq(['pkg:cocoapods/MSAL@1.2.1#app-lib']) + end + end + end + end From bc2789d431fca896ea4a3d2f0b8d592336cec9a8 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 21 Dec 2024 08:44:17 -0500 Subject: [PATCH 6/8] style: fix codacy warnings Signed-off-by: Jeremy Long --- spec/cyclonedx/cocoapods/bom_builder_spec.rb | 37 ++++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/spec/cyclonedx/cocoapods/bom_builder_spec.rb b/spec/cyclonedx/cocoapods/bom_builder_spec.rb index 8172a39..140d47d 100644 --- a/spec/cyclonedx/cocoapods/bom_builder_spec.rb +++ b/spec/cyclonedx/cocoapods/bom_builder_spec.rb @@ -294,7 +294,6 @@ end end - context 'when generating a pod component in a BOM for JSON' do it 'should generate a root component of type library' do expect(xml.at('/component')).not_to be_nil @@ -513,7 +512,6 @@ end end end - end RSpec.describe CycloneDX::CocoaPods::Pod::License do @@ -526,7 +524,7 @@ end.to_xml) end let(:json) do - license.to_json_component() + license.to_json_component end it 'should generate a root license element' do @@ -624,7 +622,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end let(:json) do - component.to_json_component() + component.to_json_component end it_behaves_like 'component' @@ -822,7 +820,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| manufacturer.add_to_bom(xml) }.to_xml) end let(:json) do - manufacturer.to_json_manufacturer() + manufacturer.to_json_manufacturer end it_behaves_like 'manufacturer' @@ -875,7 +873,7 @@ RSpec.describe CycloneDX::CocoaPods::BOMBuilder do context 'when generating a BOM' do # Important: these pods are NOT in alphabetical order; they will be sorted in output - let(:pods) do + let(:pods) do { 'Alamofire' => '5.6.2', 'FirebaseAnalytics' => '7.10.0', @@ -1323,7 +1321,7 @@ end context 'when generating a JSON BOM' do - let(:pods) do + let(:pods) do { 'Alamofire' => '5.6.2', 'FirebaseAnalytics' => '7.10.0', @@ -1363,24 +1361,25 @@ it 'should properly generate pod components' do expect(bom_json[:components].length).to eq(pods.length) expect(bom_json[:components].first).to include( - type: 'library', - name: 'Alamofire', - version: '5.6.2', - author: 'Chewbacca', - publisher: 'Chewbacca', - purl: 'pkg:cocoapods/Alamofire@5.6.2' - ) + type: 'library', + name: 'Alamofire', + version: '5.6.2', + author: 'Chewbacca', + publisher: 'Chewbacca', + purl: 'pkg:cocoapods/Alamofire@5.6.2' + ) end context 'when asked to shorten strings' do - let(:short_json) { JSON.parse(bom_builder.bom(version: version, format: :json, trim_strings_length: 6), symbolize_names: true) } + let(:short_json) { JSON.parse(bom_builder.bom(version: version, format: :json, trim_strings_length: 6), + symbolize_names: true) } it 'should properly trim the author, publisher, and purl' do expect(short_json[:components].first).to include( - author: 'Chewba', - publisher: 'Chewba', - purl: 'pkg:cocoapods/Alamofire@5.6.2' - ) + author: 'Chewba', + publisher: 'Chewba', + purl: 'pkg:cocoapods/Alamofire@5.6.2' + ) end end From aeb5e47757bad96ae8c415b4af36472b237e52ec Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 21 Dec 2024 08:52:26 -0500 Subject: [PATCH 7/8] style: fix codacy warnings Signed-off-by: Jeremy Long --- spec/cyclonedx/cocoapods/bom_builder_spec.rb | 27 +++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/spec/cyclonedx/cocoapods/bom_builder_spec.rb b/spec/cyclonedx/cocoapods/bom_builder_spec.rb index 140d47d..d312e7a 100644 --- a/spec/cyclonedx/cocoapods/bom_builder_spec.rb +++ b/spec/cyclonedx/cocoapods/bom_builder_spec.rb @@ -678,7 +678,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end let(:json) do - component.to_json_component() + component.to_json_component end it_behaves_like 'component' @@ -707,7 +707,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end let(:json) do - component.to_json_component() + component.to_json_component end it_behaves_like 'component' @@ -735,7 +735,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end let(:json) do - component.to_json_component() + component.to_json_component end it_behaves_like 'component' @@ -765,7 +765,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| component.add_to_bom(xml) }.to_xml) end let(:json) do - component.to_json_component() + component.to_json_component end it_behaves_like 'component' @@ -848,7 +848,7 @@ Nokogiri::XML(Nokogiri::XML::Builder.new(encoding: 'UTF-8') { |xml| manufacturer.add_to_bom(xml) }.to_xml) end let(:json) do - manufacturer.to_json_manufacturer() + manufacturer.to_json_manufacturer end it_behaves_like 'manufacturer' @@ -1371,15 +1371,19 @@ end context 'when asked to shorten strings' do - let(:short_json) { JSON.parse(bom_builder.bom(version: version, format: :json, trim_strings_length: 6), - symbolize_names: true) } + let(:short_json) { + JSON.parse( + bom_builder.generate_json(version: version, trim_strings_length: 6), + symbolize_names: true + ) + } it 'should properly trim the author, publisher, and purl' do expect(short_json[:components].first).to include( - author: 'Chewba', - publisher: 'Chewba', - purl: 'pkg:cocoapods/Alamofire@5.6.2' - ) + author: 'Chewba', + publisher: 'Chewba', + purl: 'pkg:cocoapods/Alamofire@5.6.2' + ) end end @@ -1420,5 +1424,4 @@ end end end - end From f33c7f311a85e970f49c2a0c5f66870d448a2bf0 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 21 Dec 2024 08:57:36 -0500 Subject: [PATCH 8/8] style: fix codacy warnings Signed-off-by: Jeremy Long --- spec/cyclonedx/cocoapods/bom_builder_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/cyclonedx/cocoapods/bom_builder_spec.rb b/spec/cyclonedx/cocoapods/bom_builder_spec.rb index d312e7a..ff3cfa9 100644 --- a/spec/cyclonedx/cocoapods/bom_builder_spec.rb +++ b/spec/cyclonedx/cocoapods/bom_builder_spec.rb @@ -1371,12 +1371,12 @@ end context 'when asked to shorten strings' do - let(:short_json) { + let(:short_json) do JSON.parse( - bom_builder.generate_json(version: version, trim_strings_length: 6), + bom_builder.bom(version: version, format: :json, trim_strings_length: 6), symbolize_names: true ) - } + end it 'should properly trim the author, publisher, and purl' do expect(short_json[:components].first).to include(