Go Registry Client used By Docker Registry UI
  • Go 99.6%
  • Makefile 0.4%
Find a file
2026-05-23 11:04:36 +00:00
.github/workflows chore(deps): update tj-actions/verify-changed-files action to v20 (#10) 2025-11-12 20:26:13 +04:00
jsoncompat perf: improve speed with jsonv2 2025-11-13 19:11:10 +04:00
testdata feat: initial commit 2025-11-10 21:16:42 +04:00
.gitignore feat: initial commit 2025-11-10 21:16:42 +04:00
.golangci.json Bump funlen limit to 70 lines to fix CI lint issue 2026-05-23 15:04:08 +04:00
.golangci.local.json Bump funlen limit to 70 lines to fix CI lint issue 2026-05-23 15:04:08 +04:00
client.go feat: add head request (#15) 2026-05-21 22:12:04 +04:00
client_test.go refactor: improve code 2025-11-12 19:19:38 +04:00
github.go perf: improve speed with jsonv2 2025-11-13 19:11:10 +04:00
github_test.go perf: improve speed with jsonv2 2025-11-13 19:11:10 +04:00
go.mod feat: initial commit 2025-11-10 21:16:42 +04:00
go.sum feat: initial commit 2025-11-10 21:16:42 +04:00
interface.go feat: add head request (#15) 2026-05-21 22:12:04 +04:00
interface_test.go refactor: improve code 2025-11-12 19:19:38 +04:00
LICENSE feat: initial commit 2025-11-10 21:16:42 +04:00
Makefile refactor: improve code style 2025-11-11 15:06:21 +04:00
README.md chore: updated coverage badge. 2026-05-23 11:04:36 +00:00
registry.go Add ParseManifestForceMediaType for manifests without top-level mediaType (Helm charts) 2026-05-23 15:04:08 +04:00
registry_test.go feat: add head request (#15) 2026-05-21 22:12:04 +04:00
renovate.json Add renovate.json 2025-11-10 17:52:19 +00:00
responses.go feat: add head request (#15) 2026-05-21 22:12:04 +04:00
types.go perf: improve speed with jsonv2 2025-11-13 19:11:10 +04:00

Go Report Card License: MIT Coverage Go Version Release Go Reference

Registry Client

A Go client library for interacting with OCI/Docker container registries.

Used by Docker Registry UI

Features

  • Full support for Docker Distribution API v2
  • OCI and Docker manifest handling
  • Built-in retry logic with exponential backoff
  • Authentication support (Basic Auth and Bearer Token)
  • Pagination support for large result sets
  • Optional logging interface
  • Health check endpoint
  • GitHub Container Registry support (user and organization packages)
  • Safe delete operations with DisableDelete flag for testing
  • uses encoding/json/v2 can be enabled using GOEXPERIMENT=jsonv2

Installation

go get github.com/eznix86/registry-client

Usage

Basic Setup

import (
    "net/http"
    registryclient "github.com/eznix86/registry-client"
)

// Create a client with basic authentication
client := &registryclient.BaseClient{
    HTTPClient: &http.Client{},
    BaseURL:    "https://registry.example.com",
    Auth: registryclient.BasicAuth{
        Username: "user",
        Password: "pass",
    },
}

// Or with bearer token
client := &registryclient.BaseClient{
    HTTPClient: &http.Client{},
    BaseURL:    "https://registry.example.com",
    Auth: registryclient.BearerAuth{
        Token: "your-token",
    },
}

Configuration Options

client := &registryclient.BaseClient{
    HTTPClient:   &http.Client{},
    BaseURL:      "https://registry.example.com",
    Auth:         auth,
    RetryBackoff: 200 * time.Millisecond,  // Initial backoff duration
    MaxAttempts:  3,                        // Maximum retry attempts
    Logger:       logger,                   // Optional logger implementation
}

Health Check

status, err := client.HealthCheck(context.Background())
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Registry status: %d\n", *status)

List Repositories

catalog, err := client.GetCatalog(context.Background(), nil)
if err != nil {
    log.Fatal(err)
}

for _, repo := range catalog.Repositories {
    fmt.Println(repo)
}

List Tags

tags, err := client.ListTags(context.Background(), "my-repo", nil)
if err != nil {
    log.Fatal(err)
}

for _, tag := range tags.Tags {
    fmt.Println(tag)
}

Get Manifest

manifest, err := client.GetManifest(context.Background(), "my-repo", "latest")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Digest: %s\n", manifest.Digest)
fmt.Printf("Media Type: %s\n", manifest.MediaType)

Get Blob (Image Config)

blob, err := client.GetBlob(context.Background(), "my-repo", "sha256:abc123...")
if err != nil {
    log.Fatal(err)
}

config, err := registryclient.ParseConfigBlob(blob.Content)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Architecture: %s\n", config.Architecture)
fmt.Printf("OS: %s\n", config.OS)

Pagination

// Get first page with 50 items
pagination := &registryclient.PaginationParams{
    N: 50,
}

catalog, err := client.GetCatalog(context.Background(), pagination)
if err != nil {
    log.Fatal(err)
}

// Get next page
if catalog.HasMore {
    pagination.Last = catalog.Last
    next, err := client.GetCatalog(context.Background(), pagination)
    // ...
}

Check Existence

// Check if manifest exists
exists, err := client.HasManifest(context.Background(), "my-repo", "latest")
if err != nil {
    log.Fatal(err)
}

// Check if blob exists
exists, err = client.HasBlob(context.Background(), "my-repo", "sha256:abc123...")
if err != nil {
    log.Fatal(err)
}

Delete Manifest

// Note: reference must be a digest, not a tag
err := client.DeleteManifest(context.Background(), "my-repo", "sha256:abc123...")
if err != nil {
    log.Fatal(err)
}

Safe Delete Testing

Use DisableDelete flag to test delete operations without actually deleting resources:

client := &registryclient.BaseClient{
    HTTPClient:    &http.Client{},
    BaseURL:       "https://registry.example.com",
    DisableDelete: true, // Prevents actual deletion, only logs
}

// This will only log the delete operation, not execute it
err := client.DeleteManifest(context.Background(), "my-repo", "sha256:abc123...")
// No error, but nothing was deleted

GitHub Container Registry

For GitHub Container Registry (ghcr.io), use GitHubClient:

import registryclient "github.com/eznix86/registry-client"

// For user packages
// Note: Pass your GitHub Personal Access Token directly (plain text)
// It will be properly encoded for ghcr.io registry access and used plain for API calls
client := registryclient.NewGitHubClient("username", "ghp_yourtoken")

// List user's container packages
catalog, err := client.GetCatalog(context.Background(), nil)
if err != nil {
    log.Fatal(err)
}

for _, pkg := range catalog.Repositories {
    fmt.Println(pkg)
}

// For organization packages
orgClient := registryclient.NewGitHubOrgClient("myorg", "ghp_yourtoken")
orgCatalog, err := orgClient.GetCatalog(context.Background(), nil)
if err != nil {
    log.Fatal(err)
}

Custom Logger

Implement the Logger interface to add logging:

type Logger interface {
    Debug(msg string, args ...any)
    Info(msg string, args ...any)
    Warn(msg string, args ...any)
    Error(msg string, args ...any)
}

API Reference

BaseClient Methods

  • HealthCheck(ctx) (int, error) - Check registry availability
  • GetCatalog(ctx, pagination) (*CatalogResponse, error) - List repositories
  • ListTags(ctx, repository, pagination) (*TagsResponse, error) - List tags for a repository
  • GetManifest(ctx, repository, reference, acceptHeaders...) (*ManifestResponse, error) - Get image manifest
  • HasManifest(ctx, repository, reference, acceptHeaders...) (bool, error) - Check if manifest exists
  • GetBlob(ctx, repository, digest) (*BlobResponse, error) - Get blob content
  • HasBlob(ctx, repository, digest) (bool, error) - Check if blob exists
  • DeleteManifest(ctx, repository, digest, acceptHeaders...) error - Delete manifest by digest

GitHubClient Methods

GitHubClient embeds BaseClient and provides the same methods, with special handling for:

  • GetCatalog(ctx, pagination) - Lists user or organization packages from GitHub API
  • DeleteManifest(ctx, repository, reference) - Deletes package versions (works with tags or digests)

Authentication

  • BasicAuth{Username, Password} - HTTP Basic Authentication
  • BearerAuth{Token} - HTTP Bearer Token Authentication

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests and ensure they pass
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Development Guidelines

  • Write clear, idiomatic Go code
  • Add tests for new functionality
  • Update documentation as needed
  • Follow existing code style and conventions
  • Ensure all tests pass before submitting PR

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

For issues and feature requests, please use the GitHub issue tracker.