oci

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package oci stores and retrieves DevProof subjects as OCI objects.

The local image layout implemented here is the Phase 1 transport: it is a real, spec-shaped OCI layout that other tooling can read, which makes the hardest guarantees — canonical bytes and safe expansion — testable without a registry in the picture.

Index

Constants

View Source
const (

	// MediaTypeImageIndex is the OCI index media type.
	MediaTypeImageIndex = "application/vnd.oci.image.index.v1+json"

	// AnnotationRefName is the conventional annotation carrying a tag.
	// It lives on the index, never on the subject manifest: an annotation on
	// the subject would change its digest (DP-002).
	AnnotationRefName = "org.opencontainers.image.ref.name"
)

OCI image layout file names and values, from the image-spec.

Variables

This section is empty.

Functions

This section is empty.

Types

type Index

type Index struct {
	SchemaVersion int         `json:"schemaVersion"`
	MediaType     string      `json:"mediaType"`
	Manifests     []IndexItem `json:"manifests"`
}

Index is the layout's index.json.

type IndexItem

type IndexItem struct {
	MediaType    string            `json:"mediaType"`
	Digest       string            `json:"digest"`
	Size         int64             `json:"size"`
	ArtifactType string            `json:"artifactType,omitempty"`
	Annotations  map[string]string `json:"annotations,omitempty"`
	// Subject names the manifest this one is a referrer for. A layout has no
	// referrers API, so the index is where that relationship is recorded.
	Subject string `json:"subject,omitempty"`
}

IndexItem references a manifest in the layout.

Unlike a subject manifest, an index entry may carry annotations: the index is a local directory listing, not content anybody addresses by digest, so a tag recorded here cannot change what the subject is.

func (IndexItem) Descriptor

func (i IndexItem) Descriptor() artifact.Descriptor

Descriptor returns the item as a plain descriptor.

func (IndexItem) Ref

func (i IndexItem) Ref() string

Ref returns the item's tag, if it has one.

type Layout

type Layout struct {
	// contains filtered or unexported fields
}

Layout is an OCI image layout directory.

Every operation goes through an os.Root held on the layout directory, so a blob path derived from a digest cannot escape it even if the digest string were somehow attacker-controlled.

func Create

func Create(dir string) (_ *Layout, retErr error)

Create makes a new OCI image layout at dir.

The directory must not already be a layout. Writing into an existing one would mean inheriting blobs and an index that this process never verified.

func Open

func Open(dir string) (_ *Layout, retErr error)

Open opens an existing OCI image layout.

func (*Layout) AddManifest

func (l *Layout) AddManifest(descriptor artifact.Descriptor, artifactType, tag string) error

AddManifest records a subject in the index, optionally under a tag.

A tag is written only after the manifest it names is already present, which is the local equivalent of the publication barrier a registry push observes (DP-007): a name never points at content that has not landed.

func (*Layout) AddReferrer

func (l *Layout) AddReferrer(descriptor artifact.Descriptor, artifactType, subjectDigest string) error

AddReferrer records an evidence manifest against its subject.

Unlike AddManifest this never carries a tag and never replaces an existing entry with a different digest: a subject may have several pieces of evidence, and attaching one must not remove another (DP-003).

func (*Layout) Close

func (l *Layout) Close() error

Close releases the layout's directory handle.

func (*Layout) FindManifest

func (l *Layout) FindManifest(reference string) (IndexItem, error)

FindManifest resolves a reference, which may be a digest or a tag.

A tag is resolved to a digest here and the digest is what every later step uses, so a tag that moves mid-operation cannot change what was verified (DP-007).

func (*Layout) GetBlob

func (l *Layout) GetBlob(digest canonical.Digest, limit int64) ([]byte, error)

GetBlob reads a blob, verifying it against its digest.

limit bounds the read so that a layout directory someone else can write cannot force an unbounded allocation.

func (*Layout) Index

func (l *Layout) Index() (*Index, error)

Index reads index.json.

func (*Layout) OpenBlob

func (l *Layout) OpenBlob(digest canonical.Digest) (io.ReadCloser, int64, error)

OpenBlob returns a streaming reader over a blob.

The caller is responsible for verifying the digest as it reads; this exists for the layer, which is too large to hold in memory just to check it once.

func (*Layout) Path

func (l *Layout) Path() string

Path returns the layout's absolute path.

func (*Layout) PutBlob

func (l *Layout) PutBlob(content []byte) (canonical.Digest, error)

PutBlob stores content under its digest.

The digest is recomputed from the bytes rather than trusted from the caller, because a blob filed under the wrong name is a blob that will later verify against a descriptor it does not match. Writing is atomic: content lands at a temporary name, is synced, and is renamed into place, so a crash never leaves a truncated blob at a digest-shaped path where a reader would take its name as proof of its content.

func (*Layout) PutBlobStream

func (l *Layout) PutBlobStream(content io.Reader, want canonical.Digest, size int64) (retErr error)

PutBlobStream stores a blob by streaming it, verifying as it goes.

The layer can be far larger than memory, and reading it into a slice just to hash it once would make peak memory track payload size. Instead the content is hashed while it is written to a temporary file, and the file is published under its digest only once the digest is known to be the expected one.

want is the digest the caller expects. A blob is never filed under a digest it does not have, so a source that served different bytes is caught here rather than becoming a corrupt layout.

func (*Layout) SetIndex

func (l *Layout) SetIndex(items []IndexItem) error

SetIndex replaces index.json.

type LayoutTransport

type LayoutTransport struct {
	// contains filtered or unexported fields
}

LayoutTransport exposes local OCI image layouts through the same contract as a registry.

Having one contract is what keeps the publication rules — blobs before the manifest, read back before tagging, tag last — in one place. A local destination that had its own code path would be the one where those rules quietly diverged, and it is the path most people develop against.

func NewLayoutTransport

func NewLayoutTransport() *LayoutTransport

NewLayoutTransport returns a transport for local layouts.

func (*LayoutTransport) Attach

Attach stores an evidence blob and the referrer manifest naming it.

func (*LayoutTransport) Close

func (t *LayoutTransport) Close() error

Close releases every layout this transport opened.

func (*LayoutTransport) Fetch

Fetch returns the content a descriptor names.

func (*LayoutTransport) LocalOnly added in v0.2.0

func (t *LayoutTransport) LocalOnly() bool

LocalOnly reports that this transport never opens a network connection.

An OCI image layout is a directory. Every operation here is a file operation against it, so an offline client can use this transport and only this one (DP-013).

func (*LayoutTransport) Push

Push stores content under its descriptor.

func (*LayoutTransport) Record

func (t *LayoutTransport) Record(ref artifact.Reference, target artifact.Descriptor) error

Record registers a manifest in the index without assigning a tag.

A layout has no way to enumerate manifests other than its index, so an untagged subject still has to be recorded or it would be unreachable. This is layout-specific: a registry keeps a manifest addressable by digest with no index entry at all.

func (*LayoutTransport) Referrers

Referrers lists evidence attached to a subject in a layout.

A layout has no referrers API, so every manifest the index lists is read and asked what it is a referrer for. The answer comes from the subject descriptor inside the manifest, which is where the OCI image specification puts the relationship and where every other implementation looks.

The index also carries a "subject" member on each entry, which this package writes and the layout specification does not define. It is a convenience for anyone reading index.json, and it used to be the only thing consulted -- so a generic copy or rewrite that produced a perfectly valid index silently made attached evidence undiscoverable while leaving the manifests that hold the real relationship untouched.

This is a real set, unlike the registry fallback tag, so the storage mode reported is the referrers one.

func (*LayoutTransport) Resolve

Resolve freezes a reference to one descriptor.

func (*LayoutTransport) Scheme

func (t *LayoutTransport) Scheme() string

Scheme is the reference scheme this transport handles.

func (*LayoutTransport) Tag

Tag assigns a mutable name to an already-stored manifest.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is an OCI Distribution transport.

func NewRegistry

func NewRegistry(opts RegistryOptions) *Registry

NewRegistry returns a registry transport.

func (*Registry) Attach

func (r *Registry) Attach(
	ctx context.Context,
	ref artifact.Reference,
	subject artifact.Descriptor,
	blob artifact.Descriptor,
	content io.Reader,
	artifactType string,
) (artifact.Descriptor, artifact.EvidenceStorage, error)

Attach stores an evidence blob and the referrer manifest naming it.

func (*Registry) Close

func (r *Registry) Close() error

Close releases idle connections.

func (*Registry) Fetch

Fetch returns the content a descriptor names.

func (*Registry) Push

func (r *Registry) Push(ctx context.Context, ref artifact.Reference, target artifact.Descriptor, content io.Reader) error

Push stores content under its descriptor. Content that is already present is not an error.

func (*Registry) Referrers

func (r *Registry) Referrers(
	ctx context.Context,
	ref artifact.Reference,
	subject artifact.Descriptor,
	artifactType string,
) ([]artifact.Descriptor, artifact.EvidenceStorage, error)

Referrers lists evidence attached to a subject.

Where the registry has no referrers API, the fallback tag is consulted instead and the storage mode says so. A caller that cannot accept the fallback's replace-rather-than-accumulate semantics can refuse it by policy, but only if it is told which mode answered (DP-028).

func (*Registry) Resolve

Resolve freezes a reference to one descriptor.

func (*Registry) Scheme

func (r *Registry) Scheme() string

Scheme is the reference scheme this transport handles.

func (*Registry) Tag

func (r *Registry) Tag(ctx context.Context, ref artifact.Reference, target artifact.Descriptor, tag string) error

Tag assigns a mutable name to an already-stored manifest.

type RegistryOptions

type RegistryOptions struct {
	// Credentials supplies per-host credentials. Nil means anonymous.
	Credentials artifact.CredentialProvider
	// PlainHTTP disables TLS.
	PlainHTTP bool
	// Timeout bounds a single request attempt.
	Timeout time.Duration
}

RegistryOptions configures a registry transport.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL