Skip to content

Latest commit

 

History

History
198 lines (154 loc) · 6.82 KB

File metadata and controls

198 lines (154 loc) · 6.82 KB

AGENTS.md

This file provides guidance to agents when working with code in this repository.

Commands

# Build (all checks + tests)
mvn clean install

# Quick build (skip tests, formatting, license checks)
mvn clean install -Pquick-build

# Unit tests only
mvn test

# Run a specific test class
mvn test -Dtest=RegistryTest

# Integration tests (requires Docker/Podman for Testcontainers)
mvn verify

# Check and apply code formatting (Palantir Java Format via Spotless)
mvn spotless:check
mvn spotless:apply

# Check and fix Apache 2.0 license headers
mvn license:check-file-header
mvn license:format

# Generate JavaDoc (failOnWarnings=true — keep Javadoc clean)
mvn javadoc:javadoc

Architecture

oras-java is a Java SDK for ORAS (OCI Registry as Storage), enabling applications to push and pull OCI artifacts to/from OCI-conformant registries.

Module Layout

Single-module Maven project. Main packages under src/main/java/land/oras/:

Package Purpose
land.oras Core API — Registry, OCILayout, OCI, data models
land.oras.auth Authentication providers and HTTP client
land.oras.utils Constants, JSON/TOML/YAML utils, digest, compression, archive
land.oras.exception OrasException and OCI error model

Core Abstraction

OCI<T> is a sealed abstract class that defines operations shared between remote registries and local layouts:

  • Registry extends OCI<ContainerRef> — remote registry operations (push/pull blobs and manifests, list tags/repos/referrers). This is the main entry point for most users. Built via Registry.Builder.
  • OCILayout extends OCI<LayoutRef> — local OCI layout on disk. Built via OCILayout.Builder.

Data Models

All OCI data models live in the root land.oras package and are serialized/deserialized with Jackson. They are annotated with @OrasModel and use @JsonPropertyOrder to ensure deterministic JSON output (required for digest stability).

Class hierarchy

Descriptor is a sealed class with four permitted subtypes:

Descriptor (sealed)
├── Config      — the manifest's config object (often the empty config: {})
├── Layer       — a single content layer within a manifest
├── Manifest    — an OCI image manifest (schemaVersion, config, layers, subject, annotations)
└── Index       — an OCI image index / multi-arch manifest list (schemaVersion, manifests[])

Common fields on Descriptor: mediaType, digest, size, artifactType, annotations. Additional fields:

  • Manifest adds: schemaVersion, config (Config), layers (List<Layer>), subject (Subject)
  • Index adds: schemaVersion, manifests (List<ManifestDescriptor>)
  • Layer / Config add: data (optional base64 inline content)

Supporting classes (not subtypes of Descriptor):

  • ManifestDescriptor — an entry inside an Index.manifests[] list; carries mediaType, digest, size, annotations, artifactType, platform
  • Subject — the referrer target inside a Manifest; same shape as a descriptor
  • ContainerRef — parses [registry/]namespace/repository[:tag][@digest] with regex validation
  • LayoutRef — reference inside a local OCI layout (path + tag/digest)
  • LocalPath — wraps a local file or directory for push operations
  • Annotations, Platform, ArtifactType — thin value-objects

All models are immutable-style; use with*() methods to derive modified copies.

OCI JSON shapes

OCI Image Index (index.json at the root of an OCI layout):

{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:cb1d49ba...",
      "size": 556,
      "annotations": {
        "org.opencontainers.image.created": "2025-03-08T08:20:56Z",
        "org.opencontainers.image.ref.name": "latest"
      },
      "artifactType": "foo/bar"
    }
  ]
}

OCI Image Manifest (stored as a blob, referenced by the index):

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "artifactType": "foo/bar",
  "config": {
    "mediaType": "application/vnd.oci.empty.v1+json",
    "digest": "sha256:44136fa3...",
    "size": 2,
    "data": "e30="
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar",
      "digest": "sha256:98ea6e4f...",
      "size": 3,
      "annotations": { "org.opencontainers.image.title": "hi.txt" }
    }
  ],
  "annotations": { "org.opencontainers.image.created": "2025-03-08T08:20:56Z" }
}

Manifest with subject (referrer — attached to another manifest via the Referrers API):

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "artifactType": "application/vnd.text.file.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.empty.v1+json",
    "digest": "sha256:44136fa3...",
    "size": 2,
    "data": "e30="
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar",
      "digest": "sha256:e094bc80...",
      "size": 4,
      "annotations": { "org.opencontainers.image.title": "hi2.txt" }
    }
  ],
  "subject": {
    "mediaType": "application/vnd.oci.image.manifest.v1+json",
    "digest": "sha256:bb329f10...",
    "size": 554
  },
  "annotations": { "org.opencontainers.image.created": "2025-04-07T14:54:25Z" }
}

The empty config blob ({}, base64 e30=, digest sha256:44136fa3...) is used as the standard no-op config for non-image ORAS artifacts.

Authentication

AuthProvider interface with implementations:

  • AuthStoreAuthenticationProvider — reads ~/.docker/config.json or $XDG_RUNTIME_DIR/containers/auth.json
  • UsernamePasswordProvider, BearerTokenProvider, NoAuthProvider

HttpClient integrates AuthProvider and handles token caching (Caffeine) with automatic refresh.

Testing

  • Unit tests (*Test.java): Use WireMock for HTTP mocking and Testcontainers (ZotContainer) for in-process OCI registry. Parallel execution via @Execution(ExecutionMode.CONCURRENT).
  • Integration tests (*ITCase.java): Run against real external registries. Require credentials and Docker/Podman.

Test resources with OCI layout fixtures live in src/test/resources/oci/.

Key Dependencies

  • Jackson 3.x (JSON/TOML/YAML)
  • Micrometer (metrics)
  • Caffeine (token caching)
  • Commons Compress + Zstd-JNI (archive/compression)
  • BouncyCastle (cryptography)
  • JSpecify (null-safety annotations — use @Nullable/@NonNull where appropriate)
  • JUnit Jupiter + Testcontainers + WireMock + Mockito (tests)

Code Style

  • Java 17, formatted with Palantir Java Format (enforced via mvn spotless:apply)
  • All source files require an Apache 2.0 license header (enforced via mvn license:format)
  • JavaDoc must compile without warnings (failOnWarnings=true)
  • CI tests against Java 17, 21, and 25