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
- Variables
- func FallbackTag(subject bundle.Digest) string
- func IsLocalOnly(transport Transport) bool
- type Capabilities
- type CapabilityReporter
- type Credential
- type CredentialFunc
- type CredentialProvider
- type Descriptor
- type EvidenceStorage
- type LocalOnly
- type Manifest
- type Reference
- type ReferrerManifest
- type ReferrerTransport
- type Transport
Constants ¶
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.
const ManifestSchemaVersion = 2
ManifestSchemaVersion is the OCI image manifest schema version.
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.
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 ¶
var EmptyJSONContent = []byte("{}")
EmptyJSONContent is the body of the empty descriptor: the two bytes `{}`.
Functions ¶
func FallbackTag ¶
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.
func IsLocalOnly ¶ added in v0.2.0
IsLocalOnly reports whether a transport has promised not to use the network.
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 LocalOnly ¶ added in v0.2.0
type LocalOnly interface {
// LocalOnly reports that this transport reads and writes only local
// storage.
LocalOnly() bool
}
LocalOnly is implemented by a transport that never opens a network connection.
It is how a transport opts in to being usable offline. The interface is optional and the default is the refusing one: a transport that does not implement it is treated as network-capable, because the safe assumption about an implementation nobody here wrote is that it might dial.
Declaring it is a promise about the whole operation, not about a single method. A transport that reads from disk but consults a remote index to resolve a tag is not local-only.
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) Layer ¶
func (m *Manifest) Layer() (Descriptor, error)
Layer returns the single filesystem layer descriptor.
func (*Manifest) Validate ¶
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 ¶
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) IsRegistry ¶
IsRegistry reports whether the reference addresses a registry.
func (Reference) Locator ¶
Locator returns the scheme-specific location without any tag or digest: "registry/repository" for a registry, or the directory for a layout.
func (Reference) Target ¶
Target returns the string a transport should address: the digest when the reference has one, otherwise the tag.
func (Reference) WithDigest ¶
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.