Skip to content

feat: migrate ORAS CLI from oras-go v2 to v3 #2008

@TerryHowe

Description

@TerryHowe

Overview

This issue tracks the full migration of the ORAS CLI from oras.land/oras-go/v2 to github.com/oras-project/oras-go/v3. The migration is broken into three phases:

  1. Mechanical API migration — import path and breaking API renames (PR feat: migrate from oras-go v2 to v3 #2002)
  2. Deprecation cleanup — remove duplicated internal code now first-class in v3
  3. New feature adoption — unlock user-facing capabilities provided by v3

Motivation

oras-go v3 introduces a new module path, several breaking API renames, and new packages that provide capabilities the ORAS CLI currently either lacks entirely or implements through duplicated custom code. The primary user-facing motivation is support for the standard containers configuration file stack:

containers/image configuration files supported by oras-go v3

Config File Location Benefit to ORAS users
containers-auth.json ~/.config/containers/auth.json Podman/Buildah/Skopeo credentials are read automatically alongside Docker config.json — no --registry-config flag needed
containers-registries.conf /etc/containers/registries.conf Registry mirrors, blocked registries, and location remapping are applied automatically on every pull — critical for air-gapped and enterprise deployments
containers-certs.d /etc/containers/certs.d/<host>/ Per-registry CA certificates and client TLS certs are loaded without --ca-file flags

Beyond the config-file ecosystem, full v3 adoption also:

  • Fixes a process-safety bug in the ORAS_CACHE path (oci.New() is not safe for concurrent process writes)
  • Removes ~300 lines of duplicated internal code (internal/cache/, internal/trace/transport.go)
  • Adds structured error messages for oras cp that distinguish source from destination failures

Phases & Timeline

Phase 1 — Mechanical API Migration (PR #2002)

Status: open (draft)

Replace all oras.land/oras-go/v2 imports with github.com/oras-project/oras-go/v3 and update all breaking call sites.

Change Status
Import path oras.land/oras-go/v2github.com/oras-project/oras-go/v3 ✅ Done
auth.Credential{}credentials.Credential{} ✅ Done
auth.EmptyCredentialcredentials.EmptyCredential ✅ Done
client.Credential =client.CredentialFunc = ✅ Done
credentials.Credential(store)store.Get ✅ Done
credentials.Login/Logoutremote.Login/Logout ✅ Done
repo.Client/PlainHTTP/HandleWarningrepo.Registry.* ✅ Done
repo.Reference.Repositoryrepo.RepositoryName ✅ Done
ref.Reference (field) → ref.GetReference() (method) ✅ Done
SetReferrersCapability() — void, no longer returns error ✅ Done

Phase 2 — Deprecation Cleanup (follow-on PRs)

Remove internal code that is now first-class in oras-go v3.

# Task Files Net LOC Notes
2.1 oci.New()oci.NewStorage() in cache option/cache.go −2 Fixes concurrent-write safety bug for shared ORAS_CACHE
2.2 Delete internal/cache/; use oras-go/content/cache internal/cache/, option/cache.go −100 Library now ships CacheReadOnlyTarget with correct oci.NewStorage() backing
2.3 Replace custom handleWarning() with remote.NewWarningLogger() option/remote.go −25 Requires slog→logrus bridge (~15 lines) since v3 uses *slog.Logger
2.4 Replace internal/trace/transport.go with remote.NewLoggingTransport() via ClientBuilder.Logger internal/trace/, option/remote.go −160 Same header scrubbing + body cap; adds request IDs for concurrent correlation

Phase 3 — New Feature Adoption (follow-on PRs)

3.1 ClientBuilder + properties.Registry in NewRepository()/NewRegistry()

Replace the 40+ line manual assembly of tls.Config → http.Transport → retry.Transport → auth.Client with ClientBuilder, which handles TLS, retry, credentials, user-agent, and debug logging in one place.

3.2 config.LoadConfigs() — Full Ecosystem Config Stack

Use config.LoadConfigs() as the baseline for registry configuration, then override with CLI flags. This is the key change that unlocks the containers config-file ecosystem:

config.LoadConfigs()
  ├── Docker config.json          (credentials)
  ├── containers/auth.json        (Podman/Buildah/Skopeo credentials)
  ├── containers/registries.conf  (mirrors, blocked registries, location rewrites)
  └── containers/certs.d/         (per-registry TLS certificates)

CLI flags continue to take highest priority — no change in behavior for users who specify flags explicitly.

Capabilities unlocked at zero additional CLI surface:

  • Podman users: podman login-saved credentials work automatically
  • Enterprise/air-gapped: registries.conf mirrors tried on every pull, no config needed
  • Operators: per-registry CA certs from certs.d load without --ca-file

Future flags (separate PRs):

  • --registries-config — override path to registries.conf
  • --policy-file — override path to policy.json

3.3 oras.CopyError Structured Error Handling

Wrap oras.Copy() failures with *oras.CopyError to produce actionable messages distinguishing source from destination failures in oras cp, oras push, oras pull, and oras attach.


Phase 4 — Future Work (separate design required)

Capability oras-go Package Notes
Policy enforcement (--policy-file) registry/remote/policy Requires UX design for insecureAcceptAnything / reject / signedBy rules
OpenPGP signature verification registry/remote/signature Depends on registries.d config and lookaside store support
objects package for push/pack objects Higher-level alternative to PackManifest; consider for oras push simplification

Implementation Order

# Task Unblocked By
1 PR #2002 — mechanical API migration
2 oci.New()oci.NewStorage() PR #2002
3 Delete internal/cache/ step 2
4 slog→logrus bridge (internal/logutil/) PR #2002
5 remote.NewWarningLogger() step 4
6 ClientBuilder in NewRepository()/NewRegistry() steps 4, 5
7 config.LoadConfigs() full config stack step 6
8 remote.NewLoggingTransport() via builder.Logger step 6
9 oras.CopyError structured errors PR #2002

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions