Class: Gem::Guardian::RubygemsClient

Inherits:
Object
  • Object
show all
Defined in:
lib/gem/guardian/rubygems_client.rb

Overview

Reads checksum metadata from RubyGems.org and downloads gem artifacts. rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: TrustedPublishingProvenance

Constant Summary collapse

SOURCE_COMMIT_PATTERN =

Matches the Source Commit field on the RubyGems provenance page.

%r{Source Commit\s+([A-Za-z0-9._/-]+@[A-Za-z0-9._-]+)}i
BUILD_FILE_PATTERN =

Matches the Build File field on the RubyGems provenance page.

/Build File\s+([^\s]+)/i
LOG_ENTRY_PATTERN =

Matches the transparency log URL shown on the RubyGems provenance page.

%r{transparency log entry\s*(https?://[^\s]+)}i
SHA256_PATTERN =

Matches the SHA256 checksum shown on the RubyGems provenance page.

/SHA 256 checksum\s*([a-f0-9]{64})/i
WORKFLOW_PATTERN =

Matches the provenance workflow label shown on the RubyGems provenance page.

/
  Built and signed on\s+
  ([A-Za-z0-9 ._-]+?)
  (?:\s+Build summary|\s+Source Commit|\z)
/ix
DEFAULT_HOST =

Default RubyGems.org endpoint used by the client.

"https://rubygems.org"

Instance Method Summary collapse

Constructor Details

#initialize(host: DEFAULT_HOST, http: Net::HTTP) ⇒ RubygemsClient

Returns a new instance of RubygemsClient.



36
37
38
39
# File 'lib/gem/guardian/rubygems_client.rb', line 36

def initialize(host: DEFAULT_HOST, http: Net::HTTP)
  @host = host.delete_suffix("/")
  @http = http
end

Instance Method Details

#download_gem(dependency, destination) ⇒ Object

Downloads the .gem file for +dependency+ into +destination+.



62
63
64
65
66
67
68
# File 'lib/gem/guardian/rubygems_client.rb', line 62

def download_gem(dependency, destination)
  body = get("/downloads/#{dependency.gem_filename}")
  File.binwrite(destination, body)
  destination
rescue StandardError => e
  raise ArtifactFetchError, "Could not fetch #{dependency.gem_filename}: #{e.message}"
end

#expected_sha256(dependency) ⇒ Object

Returns the expected SHA256 checksum for +dependency+.



42
43
44
45
46
47
48
49
50
51
# File 'lib/gem/guardian/rubygems_client.rb', line 42

def expected_sha256(dependency)
  version = matching_version(dependency)
  sha = version && version_checksum(version)
  if blank?(sha)
    raise ChecksumNotFound,
          "No SHA256 found for #{dependency.name} #{dependency.version} #{dependency.platform}"
  end

  sha.downcase
end

#trusted_publishing_provenance(dependency) ⇒ Object

Returns trusted publishing provenance data for +dependency+ when RubyGems exposes it.



54
55
56
57
58
59
# File 'lib/gem/guardian/rubygems_client.rb', line 54

def trusted_publishing_provenance(dependency)
  version = matching_version(dependency)
  version && provenance_for(version) ||
    attestation_api_provenance(dependency) ||
    version_page_provenance(dependency)
end