Class: Dependabot::Opentofu::RegistryClient
- Inherits:
-
Object
- Object
- Dependabot::Opentofu::RegistryClient
- Extended by:
- T::Sig
- Defined in:
- lib/dependabot/opentofu/registry_client.rb
Overview
Opentofu::RegistryClient is a basic API client to interact with a OpenTofu registry: api.opentofu.org/
Constant Summary collapse
- ARCHIVE_EXTENSIONS =
Archive extensions supported by OpenTofu for HTTP URLs opentofu.org/docs/language/modules/sources/#http-urls
T.let( %w(.zip .bz2 .tar.bz2 .tar.tbz2 .tbz2 .gz .tar.gz .tgz .xz .tar.xz .txz).freeze, T::Array[String] )
- PUBLIC_HOSTNAME =
"registry.opentofu.org"- API_BASE_URL =
"api.opentofu.org"
Class Method Summary collapse
Instance Method Summary collapse
- #all_module_versions(identifier:) ⇒ Object
- #all_provider_versions(identifier:) ⇒ Object
-
#initialize(hostname: PUBLIC_HOSTNAME, credentials: []) ⇒ RegistryClient
constructor
A new instance of RegistryClient.
- #service_url_for_registry(service_key) ⇒ Object
- #source(dependency:) ⇒ Object
Constructor Details
#initialize(hostname: PUBLIC_HOSTNAME, credentials: []) ⇒ RegistryClient
Returns a new instance of RegistryClient.
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/dependabot/opentofu/registry_client.rb', line 27 def initialize(hostname: PUBLIC_HOSTNAME, credentials: []) @hostname = hostname @api_base_url = T.let(API_BASE_URL, String) @tokens = T.let( credentials.each_with_object({}) do |item, memo| memo[item["host"]] = item["token"] if item["type"] == "opentofu_registry" end, T::Hash[String, String] ) end |
Class Method Details
.get_proxied_source(raw_source) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/dependabot/opentofu/registry_client.rb', line 44 def self.get_proxied_source(raw_source) return raw_source unless raw_source.start_with?("http") uri = URI.parse(T.must(raw_source.split(%r{(?<!:)//}).first)) return raw_source if ARCHIVE_EXTENSIONS.any? { |ext| uri.path&.end_with?(ext) } return raw_source if URI.parse(raw_source).query&.include?("archive=") url = T.must(raw_source.split(%r{(?<!:)//}).first) + "?opentofu-get=1" host = URI.parse(raw_source).host response = Dependabot::RegistryClient.get(url: url) raise PrivateSourceAuthenticationFailure, host if response.status == 401 return T.must(response.headers["X-OpenTofu-Get"]) if response.headers["X-OpenTofu-Get"] doc = Nokogiri::XML(response.body) doc.css("meta").find do |tag| tag.attributes&.fetch("name", nil)&.value == "opentofu-get" end&.attributes&.fetch("content", nil)&.value rescue Excon::Error::Socket, Excon::Error::Timeout => e raise PrivateSourceAuthenticationFailure, host if e..include?("no address for") raw_source end |
Instance Method Details
#all_module_versions(identifier:) ⇒ Object
99 100 101 102 103 104 105 106 |
# File 'lib/dependabot/opentofu/registry_client.rb', line 99 def all_module_versions(identifier:) base_url = service_url_for_registry("modules.v1") response = http_get!(URI.join(base_url, "#{identifier}/versions")) JSON.parse(response.body) .fetch("modules").first.fetch("versions") .map { |release| version_class.new(release.fetch("version")) } end |
#all_provider_versions(identifier:) ⇒ Object
80 81 82 83 84 85 86 87 88 89 |
# File 'lib/dependabot/opentofu/registry_client.rb', line 80 def all_provider_versions(identifier:) base_url = service_url_for_registry("providers.v1") response = http_get!(URI.join(base_url, "#{identifier}/versions")) JSON.parse(response.body) .fetch("versions") .map { |release| version_class.new(release.fetch("version")) } rescue Excon::Error raise error("Could not fetch provider versions") end |
#service_url_for_registry(service_key) ⇒ Object
150 151 152 153 154 |
# File 'lib/dependabot/opentofu/registry_client.rb', line 150 def service_url_for_registry(service_key) url_for_registry(services.fetch(service_key)) rescue KeyError raise Dependabot::PrivateSourceAuthenticationFailure, "Host does not support required OpenTofu-native service" end |
#source(dependency:) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/dependabot/opentofu/registry_client.rb', line 117 def source(dependency:) type = T.must(dependency.requirements.first)[:source][:type] base_url = url_for_api("/registry/docs/") case type when "module", "modules", "registry" download_url = URI.join(base_url, "modules/#{dependency.name}/#{dependency.version}/download") response = http_get(download_url) return nil unless response.status == 204 source_url = response.headers.fetch("X-OpenTofu-Get") source_url = URI.join(download_url, source_url) if source_url.start_with?("/", "./", "../") source_url = RegistryClient.get_proxied_source(source_url) if source_url when "provider", "providers" url = URI.join(base_url, "providers/#{dependency.name}/v#{dependency.version}/index.json") response = http_get(url) return nil unless response.status == 200 source_url = JSON.parse(response.body).dig("docs", "index", "edit_link") end Source.from_url(source_url) if source_url rescue JSON::ParserError, Excon::Error::Timeout nil end |