diff --git a/cyclonedx-ruby.gemspec b/cyclonedx-ruby.gemspec index d781f84..6338768 100644 --- a/cyclonedx-ruby.gemspec +++ b/cyclonedx-ruby.gemspec @@ -11,8 +11,8 @@ Gem::Specification.new do |spec| spec.license = "Apache-2.0" spec.executables << "cyclonedx-ruby" spec.add_dependency('json', '~> 2.2') - spec.add_dependency('nokogiri', '~> 1.8') - spec.add_dependency('ostruct', '~> 0.1') + spec.add_dependency('rexml', '~> 3.2') + spec.add_dependency('bundler', '~> 1.17') spec.add_dependency('rest-client', '~> 2.0') spec.add_development_dependency 'rake', '~> 12' spec.add_development_dependency 'rspec', '~> 3.7' diff --git a/lib/bom_builder.rb b/lib/bom_builder.rb index 47f8f12..b172924 100644 --- a/lib/bom_builder.rb +++ b/lib/bom_builder.rb @@ -2,10 +2,10 @@ require "fileutils" require "json" require "logger" -require "nokogiri" require "optparse" require "ostruct" require "rest_client" +require "rexml/document" require 'securerandom' require_relative "bom_helpers" diff --git a/lib/bom_helpers.rb b/lib/bom_helpers.rb index 0386696..af5ebb4 100644 --- a/lib/bom_helpers.rb +++ b/lib/bom_helpers.rb @@ -7,48 +7,70 @@ def random_urn_uuid() end def build_bom(gems) - builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml| - attributes = {"xmlns" => "http://cyclonedx.org/schema/bom/1.1", "version" => "1", "serialNumber" => random_urn_uuid} - xml.bom(attributes) do - xml.components { - gems.each do |gem| - xml.component("type" => "library") { - xml.name gem["name"] - xml.version gem["version"] - xml.description gem["description"] - xml.hashes{ - xml.hash_ gem["hash"], :alg => "SHA-256" - } - if gem["license_id"] - xml.licenses { - xml.license{ - xml.id gem["license_id"] - } - } - elsif gem["license_name"] - xml.licenses { - xml.license{ - xml.name gem["license_name"] - } - } - end - xml.purl gem["purl"] - } - end - } + + xml_doc = REXML::Document.new('') + bom_xml_element = xml_doc.add_element "bom", {"xmlns" => "http://cyclonedx.org/schema/bom/1.0", "version"=>"1", "serialNumber" => random_urn_uuid} + components_xml_element = bom_xml_element.add_element "components" + + gems.each do |gem| + component_xml_element = components_xml_element.add_element "component", {"type" => "library"} + + name_xml_element = component_xml_element.add_element "name" + name_xml_element.text = gem["name"] + + version_xml_element = component_xml_element.add_element "version" + version_xml_element.text = gem["version"] + + description_xml_element = component_xml_element.add_element "description" + description_xml_element.text = gem["description"] + + hashes_xml_element = component_xml_element.add_element "hashes" + hash_xml_element = hashes_xml_element.add_element "hash", {"alg" => "SHA-256"} + hash_xml_element.text = gem["hash"] + + if gem["license_id"] || gem["license_name"] + licenses_xml_element = component_xml_element.add_element "licenses" + + license_xml_element = licenses_xml_element.add_element "license" + + if gem["license_id"] + license_id_xml_element = license_xml_element.add_element "id" + license_id_xml_element.text = gem["license_id"] + elsif gem["license_name"] + license_name_xml_element = license_xml_element.add_element "id" + license_name_xml_element.text = gem["license_name"] + end end - end - builder.to_xml -end + + purl_xml_element = component_xml_element.add_element "purl" + purl_xml_element.text = gem["purl"] + end + + output="" + xml_doc.write(output=output) + output +end def get_gem(name, version) url = "https://rubygems.org/api/v1/versions/#{name}.json" + max_retries = 3 + retry_count = 0 + delay = 1 + begin response = RestClient.get(url) body = JSON.parse(response.body) - body.select {|item| item["number"] == version.to_s}.first - rescue - @logger.warn("#{name} couldn't be fetched") - return nil + gem_details = body.select {|item| item["number"] == version.to_s}.first + return gem_details if gem_details + rescue => e + if max_retries > retry_count + @logger.warn("gem #{name} could NOT be fetched. Error was: #{e.message}. Retrying #{max_retries - retry_count} more time(s)...") + sleep delay + retry_count + retry_count += 1 + retry + else + @logger.warn("gem #{name} could NOT be fetched. Error was: #{e.message}. Gave up after retrying #{max_retries} times!") + return nil + end end -end \ No newline at end of file +end \ No newline at end of file