Skip to content

Add OCI skills registry client for push/pull operations#20

Merged
JAORMX merged 2 commits intomainfrom
oci-skills-registry-client
Feb 6, 2026
Merged

Add OCI skills registry client for push/pull operations#20
JAORMX merged 2 commits intomainfrom
oci-skills-registry-client

Conversation

@JAORMX
Copy link
Contributor

@JAORMX JAORMX commented Feb 6, 2026

Summary

  • Implement the RegistryClient interface with an ORAS-based Registry type for pushing/pulling skill OCI artifacts to/from registries (GHCR, ECR, Docker Hub, etc.)
  • Leverages oras.CopyGraph and oras.Copy for recursive content traversal instead of reimplementing the graph walk manually
  • Introduces a thin storeAdapter that bridges the local Store with ORAS content interfaces, and a validatingTarget wrapper for security enforcement on the pull path

Design

storeAdapter wraps *Store to satisfy oras.Target:

  • Routes Push/Fetch/Exists by media type to PutManifest/GetManifest vs PutBlob/GetBlob
  • Resolve reads manifest content to build a full ocispec.Descriptor
  • Verifies digest integrity on Push

validatingTarget wraps any oras.Target with security validation on Push:

  • Per-item size limits: 1MB manifests, 100MB blobs
  • Lying descriptor defense: reads actual content and checks real size
  • Negative size rejection
  • Digest integrity verification
  • Structure limits: max 32 manifests per index, max 64 layers per manifest

Registry uses functional options (WithPlainHTTP, WithCredentialStore) and an injectable newTarget factory for testability.

Testing

  • Injectable newTarget factory allows integration tests to use memory.Store as a mock registry — no HTTP server needed
  • Full Push/Pull round-trip tests for both single manifests and multi-platform indexes
  • storeAdapter unit tests for Push/Fetch/Exists/Resolve/Tag
  • validatingTarget tests for oversized content, lying descriptors, negative size, and manifest count limits
  • All tests use t.Context() and t.Parallel()

Dependencies added

  • oras.land/oras-go/v2 — ORAS library for registry operations
  • github.com/opencontainers/image-spec — OCI descriptor/manifest types

Test plan

  • task passes (lint + test, 0 issues)
  • task license-check passes
  • Package coverage at 75.3% (above 70% threshold)
  • Integration tests verify manifest and index round-trips
  • Go expert and security expert reviews: 0 critical, all moderate findings addressed

Closes #15

🤖 Generated with Claude Code

Implement the RegistryClient interface with an ORAS-based Registry type
that supports pushing and pulling skill OCI artifacts to/from registries
(GHCR, ECR, Docker Hub, etc.).

Key design choices:
- Functional options (WithPlainHTTP, WithCredentialStore) for library use
- sizeLimitedStore uses explicit composition (not embedding) to avoid
  exposing unguarded write methods on the underlying memory.Store
- Defense-in-depth size enforcement: sizeLimitedStore checks during
  oras.Copy, plus re-validation when reading back from memory
- Manifest/layer count limits (32 manifests per index, 64 layers per
  manifest) to prevent resource exhaustion from fan-out attacks
- Negative descriptor size rejection
- Injectable newTarget factory enables integration testing with in-memory
  stores instead of requiring a real HTTP registry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JAORMX JAORMX marked this pull request as draft February 6, 2026 16:26
Replace ~350 lines of manual staging/storing code with ORAS's built-in
oras.CopyGraph (push) and oras.Copy (pull). Introduce storeAdapter to
bridge the local Store with ORAS content interfaces.

Key changes:
- storeAdapter wraps Store, routing by media type to PutManifest/PutBlob
- validatingTarget enforces size/count limits on the pull path
- oras.CopyGraph handles recursive graph traversal for push
- oras.Copy handles recursive pull with automatic tagging
- Removed SetPlainHTTP mutable setter (WithPlainHTTP option suffices)
- Removed all manual staging/storing helpers

Review findings addressed:
- Compile-time interface assertions for storeAdapter and validatingTarget
- Exists distinguishes not-found from real I/O errors
- Digest integrity verification in both storeAdapter and validatingTarget
- Size cap on storeAdapter.Push (defense-in-depth)
- Comment clarifying double-tag behavior in Pull

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JAORMX JAORMX marked this pull request as ready for review February 6, 2026 18:19
@JAORMX JAORMX requested review from jhrozek and rdimitrov February 6, 2026 18:22
@JAORMX JAORMX merged commit d2f369f into main Feb 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OCI Skills Library: Registry client (ORAS push/pull)

2 participants