Class: Equilibrium::RegistryClient
- Inherits:
-
Object
- Object
- Equilibrium::RegistryClient
- Defined in:
- lib/equilibrium/registry_client.rb
Overview
Registry client for Docker Registry v2 API
Supports fetching container image tags from various registry providers. Currently designed for registries that allow anonymous access (like public GCR).
Google Container Registry (GCR) Pros and Cons: ✅ Pros: Simple anonymous access for public repos, provides digest info via non-standard 'manifest' field ❌ Cons: Being deprecated in favor of Artifact Registry, non-standard API extensions may not be portable
Other registries require complex authentication and don't provide manifest field, making it difficult to get digest information without separate API calls per tag:
- GitHub Container Registry (GHCR): Requires Bearer token auth
- Docker Hub: Requires token exchange auth flow
- AWS ECR Public: Requires AWS credentials even for public repos
Note: The 'manifest' field in responses is a non-standard extension only provided
by some registries (like GCR). Most registries follow the Docker Registry v2 spec
which only returns 'name' and 'tags' fields. To get digest information, separate
calls to /v2/
PAGINATION ANALYSIS (August 2025): Current implementation fetches ALL tags in single API call. Analysis of production registries:
- apm-inject: 29 tags
- dd-lib-dotnet-init: 31 tags
- dd-lib-java-init: 18 tags
- dd-lib-js-init: 56 tags (largest)
- dd-lib-php-init: 10 tags
- dd-lib-python-init: 27 tags
- dd-lib-ruby-init: 19 tags Total: 190 tags across all registries
GCR PAGINATION RESEARCH FINDINGS:
- DOCUMENTED LIMIT: 10,000 items for format-specific API requests Source: https://cloud.google.com/artifact-registry/quotas
- NO PAGINATION SUPPORT: GCR ignores Docker Registry v2 pagination parameters ('n', 'last') Source: https://stackoverflow.com/questions/38307259 (unresolved since 2016)
- ALL-OR-NOTHING: Returns complete tag lists up to 10k limit, then truncates unpredictably
- NO PER-PAGE LIMIT: Not documented, not applicable due to lack of pagination support
RECOMMENDATION: Current single-request approach is sufficient. Implementation complexity for pagination: 3-4 hours with minimal benefit. Consider only if individual repositories approach thousands of tags.
Defined Under Namespace
Classes: Error
Instance Attribute Summary collapse
-
#uri ⇒ Object
readonly
Returns the value of attribute uri.
Instance Method Summary collapse
-
#initialize(registry) ⇒ RegistryClient
constructor
A new instance of RegistryClient.
- #tagged_digests ⇒ Object
Constructor Details
#initialize(registry) ⇒ RegistryClient
57 58 59 60 |
# File 'lib/equilibrium/registry_client.rb', line 57 def initialize(registry) @registry = registry @uri = URI(build_api_url(registry)) end |
Instance Attribute Details
#uri ⇒ Object (readonly)
Returns the value of attribute uri.
55 56 57 |
# File 'lib/equilibrium/registry_client.rb', line 55 def uri @uri end |
Instance Method Details
#tagged_digests ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/equilibrium/registry_client.rb', line 62 def tagged_digests http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.read_timeout = 30 http.open_timeout = 10 response = http.request(Net::HTTP::Get.new(uri)) raise Error, "API request failed: #{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess) data = JSON.parse(response.body).tap do |json| SchemaValidator.validate!(json, Equilibrium::Schemas::REGISTRY_API_RESPONSE, error_prefix: "Registry API response validation failed") end # Data is already validated by schema, safe to process = data["tags"] # The 'manifest' field is a non-standard extension provided by some registries (like GCR) # Most registries (GHCR, Docker Hub, ECR) only return 'name' and 'tags' per Docker Registry v2 spec # When manifest data is missing, digest information is not available from the tags endpoint manifests = data.fetch("manifest") # Build mapping from tag names to their SHA256 digests # Only works when registry provides non-standard 'manifest' field in tags response tag_to_digest = manifests.each_with_object({}) do |(digest, manifest_info), mapping| = manifest_info["tag"] .each { |tag| mapping[tag] = digest } end # Validate that all_tags from API response matches tag_to_digest keys = .to_set = tag_to_digest.keys.to_set unless == raise Error, "Tag mismatch: API tags #{all_tags_set.to_a.sort} != manifest tags #{manifest_tags_set.to_a.sort}" end tag_to_digest end |