artifact

package
v0.1.0-rc.1 Latest Latest
Warning

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

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

Documentation

Overview

Package artifact holds the OCI-facing types DevProof exchanges with registries and local layouts: descriptors, references, and the image manifest that is a bundle's subject.

These types are deliberately minimal. They carry the OCI fields DevProof actually uses and no others, because every field present in a subject manifest is a field that contributes to its digest.

Index

Constants

View Source
const (
	// SchemeRegistry addresses an OCI Distribution registry.
	SchemeRegistry = "oci"
	// SchemeLayout addresses a local OCI image layout directory.
	SchemeLayout = "oci-layout"
)

URI schemes DevProof accepts for a bundle location.

View Source
const ManifestSchemaVersion = 2

ManifestSchemaVersion is the OCI image manifest schema version.

View Source
const (
	MediaTypeEmptyJSON = "application/vnd.oci.empty.v1+json"
)

OCI 1.1 empty descriptor, for an artifact manifest with no meaningful config. The digest and content are fixed by the spec.

View Source
const MediaTypeImageManifest = "application/vnd.oci.image.manifest.v1+json"

MediaTypeImageManifest is the OCI image manifest media type. A bundle's subject is an ordinary OCI image manifest, so that registries and generic tooling handle it without knowing anything about DevProof.

Variables

View Source
var EmptyJSONContent = []byte("{}")

EmptyJSONContent is the body of the empty descriptor: the two bytes `{}`.

Functions

func FallbackTag

func FallbackTag(subject bundle.Digest) string

FallbackTag returns the tag evidence for a subject is stored under when a registry has no referrers API.

The scheme is `sha256-<hex>.evidence`: one tag for one subject. A registry without the referrers API cannot express a set, and encoding an index into the tag would make "which evidence exists" depend on a read-modify-write race that has no locking. Replacement is the honest behavior, and it is reported rather than hidden.

Types

type Capabilities

type Capabilities struct {
	// ReferrersAPI reports whether the OCI referrers API is available.
	// Where it is not, evidence discovery falls back to a tag scheme, which
	// has weaker concurrency guarantees.
	ReferrersAPI bool
}

Capabilities reports what a location supports.

It is reported rather than probed at the point of use so that a policy can refuse a registry whose storage mode it does not accept, before anything is published there.

type CapabilityReporter

type CapabilityReporter interface {
	Capabilities(ctx context.Context, ref Reference) (Capabilities, error)
}

CapabilityReporter is implemented by transports that can describe a location's storage mode.

type Credential

type Credential struct {
	Username string
	Password string
	// Token is a bearer or identity token, used when Username and Password
	// are empty.
	Token string
}

Credential authenticates to a registry.

It carries no host: a credential is selected for a host by the provider, and a credential that named its own host could be returned for a different one.

func (Credential) IsZero

func (c Credential) IsZero() bool

IsZero reports whether the credential is empty, meaning anonymous access.

type CredentialFunc

type CredentialFunc func(ctx context.Context, registry string) (Credential, error)

CredentialFunc adapts a function to CredentialProvider.

func (CredentialFunc) Credential

func (f CredentialFunc) Credential(ctx context.Context, registry string) (Credential, error)

Credential implements CredentialProvider.

type CredentialProvider

type CredentialProvider interface {
	Credential(ctx context.Context, registry string) (Credential, error)
}

CredentialProvider supplies registry credentials.

Lookup is by host so that a credential is scoped to the registry it was issued for. A provider that returned the same credential for every host would send a token for one registry to another, which is the disclosure DP-013 exists to prevent.

Returning a zero Credential means anonymous access, which is not an error: public registries exist.

var AnonymousCredentials CredentialProvider = CredentialFunc(
	func(context.Context, string) (Credential, error) { return Credential{}, nil },
)

AnonymousCredentials is a provider that never supplies a credential.

type Descriptor

type Descriptor struct {
	MediaType string `json:"mediaType"`
	Digest    string `json:"digest"`
	Size      int64  `json:"size"`
}

Descriptor identifies content by digest, size, and media type.

The digest is a string in OCI form rather than a parsed value because a descriptor is a wire type: it must round-trip byte-identically, including a digest this build might not be able to parse. Use ParsedDigest to get a validated value.

func DescriptorFor

func DescriptorFor(mediaType string, content []byte) Descriptor

DescriptorFor builds a descriptor covering content.

func EmptyDescriptor

func EmptyDescriptor() Descriptor

EmptyDescriptor returns the OCI 1.1 empty config descriptor.

func (Descriptor) ParsedDigest

func (d Descriptor) ParsedDigest() (bundle.Digest, error)

ParsedDigest validates and returns the descriptor's digest.

func (Descriptor) Validate

func (d Descriptor) Validate() error

Validate checks that a descriptor is well formed.

func (Descriptor) VerifyContent

func (d Descriptor) VerifyContent(content []byte) error

VerifyContent checks content against the descriptor's digest and size.

Both are checked, and the size first: a descriptor whose size disagrees with its content is a signal on its own, and reporting "wrong length" is more useful than reporting a digest mismatch that a caller then has to diagnose.

type EvidenceStorage

type EvidenceStorage string

EvidenceStorage reports how evidence was found or stored.

const (
	// StorageReferrers is the OCI referrers API. It expresses a set, so
	// several evidence objects can coexist for one subject.
	StorageReferrers EvidenceStorage = "referrers"
	// StorageTagFallback is the tag scheme used where a registry has no
	// referrers API. It holds one object per subject and replaces rather
	// than accumulates (DP-028).
	StorageTagFallback EvidenceStorage = "tag-fallback"
)

type Manifest

type Manifest struct {
	SchemaVersion int          `json:"schemaVersion"`
	MediaType     string       `json:"mediaType"`
	ArtifactType  string       `json:"artifactType"`
	Config        Descriptor   `json:"config"`
	Layers        []Descriptor `json:"layers"`
}

Manifest is a bundle's OCI subject.

There is no Subject field and no Annotations field, and their absence is the point rather than an omission. A subject that could carry annotations could carry a build timestamp or a builder name, and those would land in the digest — so two builds of identical content would stop having identical identity (DP-002). Evidence carries that information instead, attached as a referrer that names this manifest's digest.

func NewManifest

func NewManifest(config, layer Descriptor) *Manifest

NewManifest assembles a format v1 subject from its two blob descriptors.

func (*Manifest) Format

func (m *Manifest) Format() (bundle.Format, bool)

Format reports the bundle format this manifest declares.

func (*Manifest) Layer

func (m *Manifest) Layer() (Descriptor, error)

Layer returns the single filesystem layer descriptor.

func (*Manifest) Validate

func (m *Manifest) Validate() error

Validate checks the manifest against the format v1 shape.

Cardinality is checked as strictly as the media types. A second layer would be invisible to the config inventory, which describes one archive, so a consumer that materialized both would end up with files that passed verification without ever being verified.

type Reference

type Reference struct {
	// Scheme is SchemeRegistry or SchemeLayout.
	Scheme string

	// Registry is the host, for a registry reference.
	Registry string
	// Repository is the repository path, for a registry reference.
	Repository string
	// Path is the layout directory, for a layout reference.
	Path string

	// Tag is the mutable name, if one was given.
	Tag string
	// Digest is the immutable identity, if one was given.
	Digest string
}

Reference names a bundle location.

A Reference distinguishes a tag from a digest because the difference is the whole of DP-007: a tag is a pointer someone else can move, a digest is the content. Every operation resolves a tag exactly once and works from the digest afterwards, so a tag that moves mid-operation cannot change what was verified.

func ParseReference

func ParseReference(raw string) (Reference, error)

ParseReference parses a bundle location.

A bare reference with no scheme is treated as a registry reference, which is what every other OCI tool does. A reference with no registry host is an error rather than a Docker Hub default: silently reaching out to a registry nobody named is exactly the ambient behavior DP-012 excludes.

func (Reference) IsDigest

func (r Reference) IsDigest() bool

IsDigest reports whether the reference names immutable content.

func (Reference) IsRegistry

func (r Reference) IsRegistry() bool

IsRegistry reports whether the reference addresses a registry.

func (Reference) Locator

func (r Reference) Locator() string

Locator returns the scheme-specific location without any tag or digest: "registry/repository" for a registry, or the directory for a layout.

func (Reference) String

func (r Reference) String() string

String renders the reference in its canonical form.

func (Reference) Target

func (r Reference) Target() string

Target returns the string a transport should address: the digest when the reference has one, otherwise the tag.

func (Reference) WithDigest

func (r Reference) WithDigest(digest string) Reference

WithDigest returns a copy pinned to a digest, dropping any tag.

This is how a resolved tag stops being a tag. Every step after resolution takes the pinned reference, so there is no later code path that could consult the name again (DP-007).

type ReferrerManifest

type ReferrerManifest struct {
	SchemaVersion int               `json:"schemaVersion"`
	MediaType     string            `json:"mediaType"`
	ArtifactType  string            `json:"artifactType"`
	Config        Descriptor        `json:"config"`
	Layers        []Descriptor      `json:"layers"`
	Subject       *Descriptor       `json:"subject"`
	Annotations   map[string]string `json:"annotations,omitempty"`
}

ReferrerManifest builds the OCI manifest that attaches evidence to a subject.

Unlike a bundle's subject manifest, this one carries a `subject` field — that field is what makes it a referrer — and its own digest is not a bundle identity. Attaching one cannot change what it points at (DP-003).

func NewReferrerManifest

func NewReferrerManifest(subject, blob Descriptor, artifactType string) *ReferrerManifest

NewReferrerManifest assembles a referrer for one evidence blob.

func (*ReferrerManifest) EvidenceBlob

func (m *ReferrerManifest) EvidenceBlob() (Descriptor, error)

EvidenceBlob returns the descriptor of the evidence this referrer carries.

func (*ReferrerManifest) Validate

func (m *ReferrerManifest) Validate() error

Validate checks a referrer manifest's shape.

type ReferrerTransport

type ReferrerTransport interface {
	Transport

	// Referrers lists evidence attached to a subject, filtered by artifact
	// type. The reported storage mode tells a caller whether the answer is a
	// set or a single replaceable slot.
	Referrers(ctx context.Context, ref Reference, subject Descriptor, artifactType string) ([]Descriptor, EvidenceStorage, error)

	// Attach stores an evidence blob and the referrer manifest naming it.
	//
	// Attach must never modify the subject. That is the guarantee that lets
	// evidence be added, renewed, or copied without changing what it
	// describes (DP-003).
	Attach(ctx context.Context, ref Reference, subject Descriptor, blob Descriptor, content io.Reader, artifactType string) (Descriptor, EvidenceStorage, error)
}

ReferrerTransport is a transport that can attach and discover evidence.

It is a separate interface rather than methods on Transport because a transport that cannot do this is still useful, and widening Transport would break every external implementation to add a capability most do not need.

type Transport

type Transport interface {
	// Scheme is the reference scheme this transport handles.
	Scheme() string

	// Resolve freezes a reference to one descriptor.
	//
	// This is where a tag stops being a tag. Everything afterwards works
	// from the returned descriptor, so a tag that moves mid-operation cannot
	// change what was fetched or verified (DP-007).
	Resolve(ctx context.Context, ref Reference) (Descriptor, error)

	// Fetch returns the content a descriptor names.
	//
	// The caller verifies the bytes against the descriptor. A transport that
	// verified internally would still have to be checked by the caller,
	// because the caller cannot know whether it did.
	Fetch(ctx context.Context, ref Reference, target Descriptor) (io.ReadCloser, error)

	// Push stores content under its descriptor.
	//
	// Push is idempotent: content that is already present is not an error.
	// Storage is content-addressed, so a second push of the same descriptor
	// can only be the same bytes.
	Push(ctx context.Context, ref Reference, target Descriptor, content io.Reader) error

	// Tag assigns a mutable name to an already-stored manifest.
	//
	// A transport may assume the manifest is present; the SDK does not call
	// this until it has read the manifest back and compared its descriptor.
	Tag(ctx context.Context, ref Reference, target Descriptor, tag string) error

	// Close releases connections and handles.
	Close() error
}

Transport stores and retrieves OCI objects at one kind of location.

The interface is deliberately small. Adding a method breaks every external implementation, so capability is added through optional subinterfaces — see ReferrerTransport — rather than by growing this one.

A Transport moves bytes and nothing else. It does not decide the order blobs are published in, when a tag may be assigned, or whether content is acceptable; those are the SDK's, and keeping them out of here means a custom transport cannot weaken them.

Jump to

Keyboard shortcuts

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