catalog

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2026 License: Apache-2.0 Imports: 36 Imported by: 0

Documentation

Overview

Package catalog provides artifact storage and retrieval for scafctl.

The catalog system manages solutions, providers, and auth handlers as OCI artifacts, enabling versioned storage, distribution, and dependency management.

Catalog Types

There are two types of catalogs:

  • Local catalog: Built-in catalog stored at XDG data path, always available
  • Remote catalog: OCI registry-based catalog for distribution

Built-in Local Catalog

The local catalog is always available and is first in resolution order. It uses the XDG-compliant path from paths.CatalogDir():

  • Linux: ~/.local/share/scafctl/catalog/
  • macOS: ~/.local/share/scafctl/catalog/
  • Windows: %LOCALAPPDATA%\scafctl\catalog\

The local catalog stores artifacts as OCI artifacts in OCI Image Layout format, providing content-addressable storage with full OCI compatibility.

Registry

The Registry manages multiple catalogs with a defined resolution order:

  1. Built-in local catalog (always first)
  2. Configured remote catalogs (in config order)

This enables seamless artifact resolution across local and remote sources.

Artifact Types

Currently supported artifact types:

  • Solutions: YAML configuration files (application/vnd.scafctl.solution.v1+yaml)
  • Providers: go-plugin binaries exposing providers (application/vnd.scafctl.provider.v1+binary)
  • Auth Handlers: go-plugin binaries exposing auth handlers (application/vnd.scafctl.auth-handler.v1+binary)

Example Usage

// Create a registry with the built-in local catalog
reg, err := catalog.NewRegistry(logger)
if err != nil {
    return err
}

// Build a solution into the local catalog
ref := catalog.Reference{
    Kind:    catalog.ArtifactKindSolution,
    Name:    "my-solution",
    Version: semver.MustParse("1.0.0"),
}
info, err := reg.Local().Store(ctx, ref, content, nil, annotations, false)

// Resolve an artifact (checks local first, then configured catalogs)
content, info, err := reg.Fetch(ctx, ref)

Index

Constants

View Source
const (

	// AnnotationTitle is the human-readable title.
	AnnotationTitle = "org.opencontainers.image.title"

	// AnnotationDescription is a longer description.
	AnnotationDescription = "org.opencontainers.image.description"

	// AnnotationVersion is the version (semver).
	AnnotationVersion = "org.opencontainers.image.version"

	// AnnotationCreated is the creation timestamp (RFC 3339).
	AnnotationCreated = "org.opencontainers.image.created"

	// AnnotationAuthors is the contact for the image.
	AnnotationAuthors = "org.opencontainers.image.authors"

	// AnnotationSource is the URL to get source code.
	AnnotationSource = "org.opencontainers.image.source"

	// AnnotationDocumentation is the URL for documentation.
	AnnotationDocumentation = "org.opencontainers.image.documentation"

	// AnnotationVendor is the vendor name.
	AnnotationVendor = "org.opencontainers.image.vendor"

	// AnnotationArtifactType is the scafctl artifact type ("solution", "provider", or "auth-handler").
	AnnotationArtifactType = "dev.scafctl.artifact.type"

	// AnnotationArtifactName is the artifact name.
	AnnotationArtifactName = "dev.scafctl.artifact.name"

	// AnnotationCategory is the solution category.
	AnnotationCategory = "dev.scafctl.solution.category"

	// AnnotationTags is a comma-separated list of tags.
	AnnotationTags = "dev.scafctl.solution.tags"

	// AnnotationMaintainers is a JSON array of maintainer objects.
	AnnotationMaintainers = "dev.scafctl.solution.maintainers"

	// AnnotationRequires is the dependency specifications (future).
	AnnotationRequires = "dev.scafctl.solution.requires"

	// AnnotationDisplayName is the human-friendly display name.
	AnnotationDisplayName = "dev.scafctl.solution.displayName"

	// AnnotationProviders is a comma-separated list of provider names (provider artifacts only).
	AnnotationProviders = "dev.scafctl.plugin.providers"

	// AnnotationPlatform is the target platform (provider/auth-handler artifacts only, e.g., "linux/amd64").
	AnnotationPlatform = "dev.scafctl.plugin.platform"

	// AnnotationOrigin records how a local artifact was obtained.
	// Values: "built", "pulled from <catalog>", "auto-cached from <catalog>".
	// This key carries provenance metadata only. Its exact storage location
	// depends on the catalog implementation, so it must not be assumed to be
	// descriptor-only or digest-stable.
	AnnotationOrigin = "dev.scafctl.artifact.origin"
)

OCI annotation keys.

View Source
const (
	// MediaTypeSolutionManifest is the manifest media type for solution artifacts.
	MediaTypeSolutionManifest = "application/vnd.oci.image.manifest.v1+json"

	// MediaTypeSolutionContent is the content layer media type for solution YAML.
	MediaTypeSolutionContent = "application/vnd.scafctl.solution.v1+yaml"

	// MediaTypeSolutionConfig is the config blob media type for solution metadata.
	MediaTypeSolutionConfig = "application/vnd.scafctl.solution.config.v1+json"

	// MediaTypeSolutionBundle is the content layer media type for solution bundle tar archives.
	MediaTypeSolutionBundle = "application/vnd.scafctl.solution.bundle.v1+tar"

	// MediaTypeSolutionBundleManifest is the media type for deduplicated bundle manifests (v2).
	MediaTypeSolutionBundleManifest = "application/vnd.scafctl.solution.bundle-manifest.v2+json"

	// MediaTypeSolutionBundleBlob is the media type for individual file blobs in deduplicated bundles (v2).
	MediaTypeSolutionBundleBlob = "application/vnd.scafctl.solution.bundle-blob.v2+octet-stream"

	// MediaTypeSolutionBundleSmallTar is the media type for grouped small files in deduplicated bundles (v2).
	MediaTypeSolutionBundleSmallTar = "application/vnd.scafctl.solution.bundle-small.v2+tar"

	// MediaTypeProviderManifest is the manifest media type for provider artifacts.
	MediaTypeProviderManifest = "application/vnd.oci.image.manifest.v1+json"

	// MediaTypeProviderBinary is the content layer media type for provider binaries.
	MediaTypeProviderBinary = "application/vnd.scafctl.provider.v1+binary"

	// MediaTypeProviderConfig is the config blob media type for provider metadata.
	MediaTypeProviderConfig = "application/vnd.scafctl.provider.config.v1+json"

	// MediaTypeAuthHandlerManifest is the manifest media type for auth handler artifacts.
	MediaTypeAuthHandlerManifest = "application/vnd.oci.image.manifest.v1+json"

	// MediaTypeAuthHandlerBinary is the content layer media type for auth handler binaries.
	MediaTypeAuthHandlerBinary = "application/vnd.scafctl.auth-handler.v1+binary"

	// MediaTypeAuthHandlerConfig is the config blob media type for auth handler metadata.
	MediaTypeAuthHandlerConfig = "application/vnd.scafctl.auth-handler.config.v1+json"
)

OCI media types for scafctl artifacts.

View Source
const (
	// LocalCatalogName is the name of the built-in local catalog.
	LocalCatalogName = "local"
)
View Source
const OCILayoutVersion = "1.0.0"

OCILayoutVersion is the OCI image layout version.

View Source
const RegistryUsernameACR = "00000000-0000-0000-0000-000000000000"

RegistryUsernameACR is the Azure Container Registry username for token auth. ACR uses a zero-GUID as the username when authenticating with an Entra token.

View Source
const RegistryUsernameDefault = "oauth2accesstoken"

RegistryUsernameDefault is the default username for OAuth2 token-based registry auth.

Variables

View Source
var ErrArtifactExists = errors.New("artifact already exists")

ErrArtifactExists is returned when storing an artifact that already exists.

View Source
var ErrArtifactNotFound = errors.New("artifact not found")

ErrArtifactNotFound is returned when an artifact cannot be found.

View Source
var ErrInvalidReference = errors.New("invalid reference")

ErrInvalidReference is returned when a reference is malformed.

View Source
var ErrPlatformNotFound = errors.New("platform not found")

ErrPlatformNotFound is returned when no matching platform is found in an image index.

View Source
var SupportedPluginPlatforms = []string{
	"linux/amd64",
	"linux/arm64",
	"darwin/amd64",
	"darwin/arm64",
	"windows/amd64",
}

SupportedPluginPlatforms is the list of platforms supported for plugin artifacts.

Functions

func BridgeAuthToRegistry added in v0.7.0

func BridgeAuthToRegistry(ctx context.Context, handler auth.Handler, registryHost, scope string) (string, string, error)

BridgeAuthToRegistry converts an auth handler's token into OCI registry credentials. Each registry type expects a specific username/password convention:

  • GitHub (ghcr.io): username=<github-username>, password=<access-token>
  • GCP (gcr.io, *.pkg.dev): username=oauth2accesstoken, password=<access-token>
  • Entra (*.azurecr.io): username=00000000-0000-0000-0000-000000000000, password=<access-token>
  • Generic OAuth2: username=oauth2accesstoken (or custom registryUsername), password=<access-token>

func ConfigMediaTypeForKind

func ConfigMediaTypeForKind(kind ArtifactKind) string

ConfigMediaTypeForKind returns the config media type for an artifact kind.

func GetTags

func GetTags(annotations map[string]string) []string

GetTags parses the tags annotation into a slice.

func IncludePreReleaseFromContext added in v0.9.0

func IncludePreReleaseFromContext(ctx context.Context) bool

IncludePreReleaseFromContext returns true if pre-release versions should be included when resolving the latest version.

func IndexPlatforms added in v0.6.0

func IndexPlatforms(index *ocispec.Index) []string

IndexPlatforms returns the list of platforms in an OCI image index.

func InferAuthHandler added in v0.7.0

func InferAuthHandler(registryHost string, customHandlers []config.CustomOAuth2Config) string

InferAuthHandler maps a registry host to a built-in or custom auth handler name. Returns empty string if no handler can be inferred for the registry.

func InferDefaultScope added in v0.8.0

func InferDefaultScope(registryHost string) string

InferDefaultScope returns the default OAuth scope for a known registry host. Returns empty string if no default scope is known for the registry.

func IsArtifactNotFoundError

func IsArtifactNotFoundError(err error) bool

IsArtifactNotFoundError is an alias for IsNotFound.

func IsBuiltinHandlerName added in v0.7.0

func IsBuiltinHandlerName(name string) bool

IsBuiltinHandlerName returns true if the name conflicts with a built-in handler.

func IsExists

func IsExists(err error) bool

IsExists returns true if the error indicates an artifact already exists.

func IsImageIndex added in v0.6.0

func IsImageIndex(desc ocispec.Descriptor) bool

IsImageIndex returns true if the descriptor has image index media type.

func IsInvalidReference

func IsInvalidReference(err error) bool

IsInvalidReference returns true if the error indicates an invalid reference.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound returns true if the error indicates an artifact was not found.

func IsPlatformNotFound added in v0.6.0

func IsPlatformNotFound(err error) bool

IsPlatformNotFound returns true if the error indicates a missing platform.

func IsPreRelease added in v0.9.0

func IsPreRelease(v *semver.Version) bool

IsPreRelease returns true if the semver version has a pre-release suffix (e.g., 1.0.0-beta.1, 2.0.0-alpha).

func IsSupportedPlatform added in v0.6.0

func IsSupportedPlatform(platform string) bool

IsSupportedPlatform returns true if the platform string is in the supported list.

func IsValidDigest

func IsValidDigest(digest string) bool

IsValidDigest checks if a string is a valid OCI digest.

func IsValidName

func IsValidName(name string) bool

IsValidName checks if a name follows the naming convention. Names must be lowercase alphanumeric with hyphens, starting with a letter.

func IsValidTagChar added in v0.6.0

func IsValidTagChar(ch rune) bool

IsValidTagChar returns true if the rune is valid for an OCI tag.

func LooksLikeCatalogURL added in v0.6.0

func LooksLikeCatalogURL(s string) bool

LooksLikeCatalogURL returns true if the string looks like a URL/registry rather than a simple catalog name. A URL contains "." (domain separator) or ":" (port separator), or starts with a scheme prefix.

func LooksLikeRemoteReference added in v0.8.0

func LooksLikeRemoteReference(ref string) bool

LooksLikeRemoteReference returns true if the reference appears to be a remote registry reference. Remote references contain a registry host with a dot (e.g., "ghcr.io"), a port (e.g., "localhost:5000"), or start with "oci://". Plain paths like "configs/solution" return false.

func MatchPlatform added in v0.6.0

func MatchPlatform(index *ocispec.Index, platform string) (*ocispec.Descriptor, error)

MatchPlatform selects the manifest descriptor from an OCI image index that matches the requested platform. Returns an error if no match is found.

func MediaTypeForKind

func MediaTypeForKind(kind ArtifactKind) string

MediaTypeForKind returns the content media type for an artifact kind.

func NormalizeRegistryHost

func NormalizeRegistryHost(host string) string

NormalizeRegistryHost normalizes common registry hostnames.

func OCIPlatformString added in v0.6.0

func OCIPlatformString(p *ocispec.Platform) string

OCIPlatformString converts an OCI Platform struct to a "os/arch" string.

func ParseCatalogURL added in v0.6.0

func ParseCatalogURL(rawURL string) (registry, repository string)

ParseCatalogURL parses a catalog URL into registry and repository parts, stripping any scheme prefix (oci://, https://, http://).

Examples:

  • "ghcr.io/myorg/scafctl" -> registry: "ghcr.io", repository: "myorg/scafctl"
  • "ghcr.io/myorg" -> registry: "ghcr.io", repository: "myorg"
  • "localhost:5000" -> registry: "localhost:5000", repository: ""

func ParseNameVersion added in v0.6.0

func ParseNameVersion(input string) (string, string)

ParseNameVersion splits "name@version" into (name, version). If no @ is present, returns (input, ""). Handles digest references (e.g., "name@sha256:abc123").

func PlatformToOCI added in v0.6.0

func PlatformToOCI(platform string) (*ocispec.Platform, error)

PlatformToOCI converts a platform string like "linux/amd64" to an OCI Platform struct.

func ResolveCatalogURL added in v0.6.0

func ResolveCatalogURL(ctx context.Context, catalogFlag string) (string, error)

ResolveCatalogURL resolves a catalog URL from a flag value or config defaults.

Resolution order:

  1. If catalogFlag is a URL (contains "." or ":"), use it directly.
  2. If catalogFlag is a non-empty string, treat it as a catalog name and look it up in config.
  3. If catalogFlag is empty, use the default catalog from config.

Returns the resolved catalog URL string, or an error if no catalog can be resolved.

func ValidateAlias added in v0.6.0

func ValidateAlias(alias string) error

ValidateAlias checks that an alias tag is valid for use as a non-version tag. It must not be empty, must not be a valid semver version, and must only contain characters valid in OCI tags ([a-zA-Z0-9_.-]).

func WithIncludePreRelease added in v0.9.0

func WithIncludePreRelease(ctx context.Context) context.Context

WithIncludePreRelease returns a context that includes pre-release versions when resolving the latest version from a catalog.

Types

type AnnotationBuilder

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

AnnotationBuilder helps construct annotation maps.

func NewAnnotationBuilder

func NewAnnotationBuilder() *AnnotationBuilder

NewAnnotationBuilder creates a new annotation builder.

func (*AnnotationBuilder) Build

func (b *AnnotationBuilder) Build() map[string]string

Build returns the annotation map.

func (*AnnotationBuilder) Set

func (b *AnnotationBuilder) Set(key, value string) *AnnotationBuilder

Set adds an annotation if the value is non-empty.

func (*AnnotationBuilder) SetTags

func (b *AnnotationBuilder) SetTags(tags []string) *AnnotationBuilder

SetTags adds tags as a comma-separated annotation.

type ArtifactCacher added in v0.6.0

type ArtifactCacher interface {
	// Get retrieves cached content and bundle data.
	// Returns (nil, nil, false, nil) on cache miss. Returns an error on read failure.
	Get(kind, name, version string) (content, bundleData []byte, ok bool, err error)
	// Put stores artifact content and bundle data in the cache.
	Put(kind, name, version, digest string, content, bundleData []byte) error
}

ArtifactCacher defines the interface for an artifact cache used by SolutionResolver. This interface allows caching downloaded catalog artifacts to reduce repeated fetches.

type ArtifactExistsError

type ArtifactExistsError struct {
	Reference Reference
	Catalog   string
}

ArtifactExistsError provides details about a duplicate artifact.

func (*ArtifactExistsError) Error

func (e *ArtifactExistsError) Error() string

Error implements the error interface.

func (*ArtifactExistsError) Unwrap

func (e *ArtifactExistsError) Unwrap() error

Unwrap returns the base error for errors.Is support.

type ArtifactInfo

type ArtifactInfo struct {
	// Reference is the artifact identifier.
	Reference Reference `json:"reference" yaml:"reference" doc:"Artifact reference"`

	// Tag is the OCI tag label (e.g. "1.0.0", "stable", "latest").
	// For version tags this matches Reference.Version; for aliases it holds
	// the alias string.
	Tag string `json:"tag" yaml:"tag" doc:"OCI tag label"`

	// Digest is the content digest (sha256:...).
	Digest string `json:"digest" yaml:"digest" doc:"Content digest"`

	// CreatedAt is when the artifact was stored.
	CreatedAt time.Time `json:"createdAt" yaml:"createdAt" doc:"Storage timestamp"`

	// Size is the artifact size in bytes.
	Size int64 `json:"size" yaml:"size" doc:"Size in bytes"`

	// Annotations are OCI annotations from the manifest.
	Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty" doc:"OCI annotations"`

	// Catalog is the name of the catalog this artifact came from.
	Catalog string `json:"catalog" yaml:"catalog" doc:"Source catalog name"`
}

ArtifactInfo contains metadata about a stored artifact.

type ArtifactKind

type ArtifactKind string

ArtifactKind represents the type of artifact stored in the catalog.

const (
	// ArtifactKindSolution represents a solution artifact.
	ArtifactKindSolution ArtifactKind = "solution"

	// ArtifactKindProvider represents a provider artifact (go-plugin binary exposing providers).
	ArtifactKindProvider ArtifactKind = "provider"

	// ArtifactKindAuthHandler represents an auth handler artifact (go-plugin binary exposing auth handlers).
	ArtifactKindAuthHandler ArtifactKind = "auth-handler"
)

func InferKindFromLocalCatalog added in v0.6.0

func InferKindFromLocalCatalog(ctx context.Context, localCatalog *LocalCatalog, name, version string) (ArtifactKind, error)

InferKindFromLocalCatalog searches the local catalog to determine an artifact's kind. It tries each known artifact kind in order and returns the first match.

func InferKindFromRemote added in v0.8.0

func InferKindFromRemote(ctx context.Context, remoteCatalog *RemoteCatalog, name, version string) (ArtifactKind, error)

InferKindFromRemote resolves an artifact's kind by trying each known kind against the remote catalog. For each kind it attempts to resolve the tag; the first successful resolve wins. This avoids fetching the full manifest and works even when the artifact has no scafctl-specific annotations.

If no known kind matches, it returns an error rather than guessing a fallback kind.

func ParseArtifactKind

func ParseArtifactKind(s string) (ArtifactKind, bool)

ParseArtifactKind parses a string into an ArtifactKind. Returns empty string and false if the input is not a valid kind.

func ParseArtifactKindFromPlural

func ParseArtifactKindFromPlural(s string) (ArtifactKind, bool)

ParseArtifactKindFromPlural parses a pluralized path segment into an ArtifactKind. E.g., "solutions" -> ArtifactKindSolution, "providers" -> ArtifactKindProvider

func ValidatePluginKind added in v0.6.0

func ValidatePluginKind(kindStr string) (ArtifactKind, error)

ValidatePluginKind validates that the given kind string is a valid plugin kind (provider or auth-handler). Returns the parsed ArtifactKind or an error.

func (ArtifactKind) IsValid

func (k ArtifactKind) IsValid() bool

IsValid returns true if the artifact kind is valid.

func (ArtifactKind) Plural

func (k ArtifactKind) Plural() string

Plural returns the pluralized form of the artifact kind (for repository paths).

func (ArtifactKind) String

func (k ArtifactKind) String() string

String returns the string representation of the artifact kind.

type ArtifactNotFoundError

type ArtifactNotFoundError struct {
	Reference Reference
	Catalog   string // Optional: which catalog was checked
}

ArtifactNotFoundError provides details about a missing artifact.

func (*ArtifactNotFoundError) Error

func (e *ArtifactNotFoundError) Error() string

Error implements the error interface.

func (*ArtifactNotFoundError) Unwrap

func (e *ArtifactNotFoundError) Unwrap() error

Unwrap returns the base error for errors.Is support.

type Catalog

type Catalog interface {
	// Name returns the catalog identifier (e.g., "local", "company-registry").
	Name() string

	// Store saves an artifact to the catalog.
	// For solutions with bundled files, bundleData contains the tar archive.
	// If bundleData is nil, only the primary content layer is stored.
	// Returns ErrArtifactExists if the version already exists (use force to overwrite).
	Store(ctx context.Context, ref Reference, content, bundleData []byte, annotations map[string]string, force bool) (ArtifactInfo, error)

	// Fetch retrieves an artifact's primary content from the catalog.
	// Returns ErrArtifactNotFound if the artifact doesn't exist.
	Fetch(ctx context.Context, ref Reference) ([]byte, ArtifactInfo, error)

	// FetchWithBundle retrieves an artifact's primary content and bundle layer.
	// The bundle layer contains bundled files as a tar archive.
	// If the artifact has no bundle layer, bundleData is nil.
	// Returns ErrArtifactNotFound if the artifact doesn't exist.
	FetchWithBundle(ctx context.Context, ref Reference) (content, bundleData []byte, info ArtifactInfo, err error)

	// Resolve finds the best matching version for a reference.
	// If no version is specified, returns the highest semver version.
	// Returns ErrArtifactNotFound if no matching artifact exists.
	Resolve(ctx context.Context, ref Reference) (ArtifactInfo, error)

	// List returns all artifacts matching the criteria.
	// If name is empty, returns all artifacts of the specified kind.
	List(ctx context.Context, kind ArtifactKind, name string) ([]ArtifactInfo, error)

	// Exists checks if an artifact exists in the catalog.
	Exists(ctx context.Context, ref Reference) (bool, error)

	// Delete removes an artifact from the catalog.
	// Returns ErrArtifactNotFound if the artifact doesn't exist.
	Delete(ctx context.Context, ref Reference) error
}

Catalog defines the interface for artifact storage. Both local and remote catalogs implement this interface.

func RemoteCatalogsFromContext added in v0.8.0

func RemoteCatalogsFromContext(ctx context.Context, lgr logr.Logger) []Catalog

RemoteCatalogsFromContext builds Catalog instances for every OCI remote catalog in the application config. These are suitable for passing to WithResolverRemoteCatalogs so the SolutionResolver can auto-pull artifacts that are not in the local catalog.

Catalogs that fail to initialise (e.g. missing credentials) are silently skipped — the resolver will simply not search them.

type ChainCatalog added in v0.5.0

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

ChainCatalog tries each catalog in order, returning the first successful result. It implements the Catalog interface for read operations (Fetch, Resolve, List, Exists). Write operations (Store, Delete) are forwarded to the first catalog in the chain.

func BuildCatalogChain added in v0.5.0

func BuildCatalogChain(cfg *config.Config, authRegistry *auth.Registry, logger logr.Logger) (*ChainCatalog, error)

BuildCatalogChain creates a ChainCatalog from the application configuration. It always includes the local catalog first, then adds configured remote catalogs of type "oci". It returns the constructed chain catalog and any error encountered during initialization. If authRegistry is provided, catalogs with an authProvider field will use the corresponding auth handler for dynamic token injection.

func NewChainCatalog added in v0.5.0

func NewChainCatalog(logger logr.Logger, catalogs ...Catalog) (*ChainCatalog, error)

NewChainCatalog creates a ChainCatalog that tries catalogs in order. At least one catalog must be provided.

func (*ChainCatalog) Catalogs added in v0.5.0

func (c *ChainCatalog) Catalogs() []Catalog

Catalogs returns the underlying catalogs.

func (*ChainCatalog) Delete added in v0.5.0

func (c *ChainCatalog) Delete(ctx context.Context, ref Reference) error

Delete delegates to the first catalog.

func (*ChainCatalog) Exists added in v0.5.0

func (c *ChainCatalog) Exists(ctx context.Context, ref Reference) (bool, error)

Exists returns true if the artifact exists in any catalog.

func (*ChainCatalog) Fetch added in v0.5.0

func (c *ChainCatalog) Fetch(ctx context.Context, ref Reference) ([]byte, ArtifactInfo, error)

Fetch tries each catalog in order, returning the first successful result.

func (*ChainCatalog) FetchWithBundle added in v0.5.0

func (c *ChainCatalog) FetchWithBundle(ctx context.Context, ref Reference) ([]byte, []byte, ArtifactInfo, error)

FetchWithBundle tries each catalog in order.

func (*ChainCatalog) List added in v0.5.0

func (c *ChainCatalog) List(ctx context.Context, kind ArtifactKind, name string) ([]ArtifactInfo, error)

List returns artifacts from all catalogs (deduplicated by name+version).

func (*ChainCatalog) Name added in v0.5.0

func (c *ChainCatalog) Name() string

Name returns a composite name.

func (*ChainCatalog) Resolve added in v0.5.0

func (c *ChainCatalog) Resolve(ctx context.Context, ref Reference) (ArtifactInfo, error)

Resolve tries each catalog in order, returning the first successful result.

func (*ChainCatalog) Store added in v0.5.0

func (c *ChainCatalog) Store(ctx context.Context, ref Reference, content, bundleData []byte, annotations map[string]string, force bool) (ArtifactInfo, error)

Store delegates to the first catalog.

type CopyOptions

type CopyOptions struct {
	// TargetName overrides the artifact name in the target catalog
	TargetName string

	// Force overwrites existing artifacts
	Force bool

	// OnProgress reports copy progress
	OnProgress func(desc ocispec.Descriptor)
}

CopyOptions configures a copy operation between catalogs.

type CredentialStore

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

CredentialStore provides OCI registry credentials from docker config. It supports both static credentials and docker credential helpers, with a fallback to scafctl's native credential store.

func NewCredentialStore

func NewCredentialStore(logger logr.Logger) (*CredentialStore, error)

NewCredentialStore creates a credential store from the default docker config. It looks for config in the following order: 1. $DOCKER_CONFIG/config.json 2. ~/.docker/config.json 3. $XDG_RUNTIME_DIR/containers/auth.json (podman rootless) 4. ~/.config/containers/auth.json (podman) 5. /run/containers/$UID/auth.json (podman rootless fallback)

func (*CredentialStore) Credential

func (c *CredentialStore) Credential(ctx context.Context, host string) (auth.Credential, error)

Credential returns the auth credential for a registry host. This implements the auth.CredentialFunc signature for oras-go.

func (*CredentialStore) CredentialFunc

func (c *CredentialStore) CredentialFunc() auth.CredentialFunc

CredentialFunc returns an auth.CredentialFunc for use with oras-go.

type InvalidReferenceError

type InvalidReferenceError struct {
	Input   string
	Message string
}

InvalidReferenceError provides details about an invalid reference.

func (*InvalidReferenceError) Error

func (e *InvalidReferenceError) Error() string

Error implements the error interface.

func (*InvalidReferenceError) Unwrap

func (e *InvalidReferenceError) Unwrap() error

Unwrap returns the base error for errors.Is support.

type LoadResult

type LoadResult struct {
	// Reference is the artifact that was loaded.
	Reference Reference `json:"reference" yaml:"reference"`
	// Digest is the manifest digest.
	Digest string `json:"digest" yaml:"digest"`
	// Size is the artifact content size in bytes.
	Size int64 `json:"size" yaml:"size"`
	// CreatedAt is when the artifact was originally created.
	CreatedAt time.Time `json:"createdAt" yaml:"createdAt"`
}

LoadResult contains information about the load operation.

type LocalCatalog

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

LocalCatalog implements Catalog using a local OCI layout store.

func NewLocalCatalog

func NewLocalCatalog(logger logr.Logger) (*LocalCatalog, error)

NewLocalCatalog creates a catalog at the XDG data path. The path is determined by paths.CatalogDir().

func NewLocalCatalogAt

func NewLocalCatalogAt(path string, logger logr.Logger) (*LocalCatalog, error)

NewLocalCatalogAt creates a catalog at a custom path. Use this for testing or custom installations.

func (*LocalCatalog) Delete

func (c *LocalCatalog) Delete(ctx context.Context, ref Reference) error

Delete removes an artifact from the catalog.

func (*LocalCatalog) Exists

func (c *LocalCatalog) Exists(ctx context.Context, ref Reference) (bool, error)

Exists checks if an artifact exists in the catalog.

func (*LocalCatalog) Fetch

func (c *LocalCatalog) Fetch(ctx context.Context, ref Reference) ([]byte, ArtifactInfo, error)

Fetch retrieves an artifact from the catalog.

func (*LocalCatalog) FetchByPlatform added in v0.6.0

func (c *LocalCatalog) FetchByPlatform(ctx context.Context, ref Reference, platform string) ([]byte, ArtifactInfo, error)

FetchByPlatform fetches a plugin binary for the given platform from an artifact that may be stored as either a single-platform manifest or a multi-platform image index. It transparently handles both cases.

func (*LocalCatalog) FetchDedup

func (c *LocalCatalog) FetchDedup(ctx context.Context, ref Reference) (solutionYAML, manifestJSON []byte, layerFetcher func(layer int) ([]byte, error), info ArtifactInfo, err error)

FetchDedup retrieves a deduplicated (v2) bundle by fetching all layers. Returns the solution YAML, bundle manifest JSON, and a layer fetcher that can retrieve individual layers by index.

func (*LocalCatalog) FetchWithBundle

func (c *LocalCatalog) FetchWithBundle(ctx context.Context, ref Reference) ([]byte, []byte, ArtifactInfo, error)

FetchWithBundle retrieves an artifact's primary content and bundle layer. If the artifact has no bundle layer, bundleData is nil.

func (*LocalCatalog) List

func (c *LocalCatalog) List(ctx context.Context, kind ArtifactKind, name string) ([]ArtifactInfo, error)

List returns all artifacts matching the criteria.

func (*LocalCatalog) ListPlatforms added in v0.6.0

func (c *LocalCatalog) ListPlatforms(ctx context.Context, ref Reference) ([]string, error)

ListPlatforms returns the platforms available for a multi-platform artifact. If the artifact is single-platform, returns nil.

func (*LocalCatalog) Load

func (c *LocalCatalog) Load(ctx context.Context, inputPath string, force bool) (LoadResult, error)

Load imports an artifact from an OCI Image Layout tar archive. Returns ErrArtifactExists if artifact already exists and force is false.

func (*LocalCatalog) Name

func (c *LocalCatalog) Name() string

Name returns "local".

func (*LocalCatalog) Path

func (c *LocalCatalog) Path() string

Path returns the catalog directory path.

func (*LocalCatalog) Prune

func (c *LocalCatalog) Prune(ctx context.Context) (PruneResult, error)

Prune removes orphaned blobs and manifests from the catalog. Orphaned content is any blob or manifest not referenced by a tagged artifact.

func (*LocalCatalog) Resolve

func (c *LocalCatalog) Resolve(ctx context.Context, ref Reference) (ArtifactInfo, error)

Resolve finds the best matching version for a reference.

func (*LocalCatalog) Save

func (c *LocalCatalog) Save(ctx context.Context, name, version, outputPath string) (SaveResult, error)

Save exports an artifact to an OCI Image Layout tar archive. If version is empty, exports the latest version.

func (*LocalCatalog) Store

func (c *LocalCatalog) Store(ctx context.Context, ref Reference, content, bundleData []byte, annotations map[string]string, force bool) (ArtifactInfo, error)

Store saves an artifact to the catalog. For solutions with bundled files, bundleData contains the tar archive. If bundleData is nil, only the primary content layer is stored.

func (*LocalCatalog) StoreDedup

func (c *LocalCatalog) StoreDedup(ctx context.Context, ref Reference, solutionYAML, manifestJSON, smallTar []byte, blobLayers [][]byte, annotations map[string]string, force bool) (ArtifactInfo, error)

StoreDedup saves a solution with content-addressable deduplicated layers. manifestJSON is the bundle manifest (v2), smallTar is grouped small files, and blobLayers are individual large file blobs with their media types.

func (*LocalCatalog) StoreMultiPlatform added in v0.6.0

func (c *LocalCatalog) StoreMultiPlatform(ctx context.Context, ref Reference, platformBinaries []PlatformBinary, annotations map[string]string, force bool) (ArtifactInfo, error)

StoreMultiPlatform stores a set of platform-specific plugin binaries as an OCI image index (fat manifest). Each entry in platformBinaries maps a platform string (e.g. "linux/amd64") to the raw binary data. The resulting image index is tagged under the normal kind/name:version scheme.

This replaces any existing single-platform artifact at the same reference.

func (*LocalCatalog) Tag

func (c *LocalCatalog) Tag(ctx context.Context, ref Reference, alias string) (string, error)

Tag creates an alias tag for an existing artifact. The source reference must have a version or digest to resolve. The alias is a freeform string (e.g., "stable", "production"). Returns the previous version string if the alias already existed (empty otherwise).

type NativeCredential added in v0.7.0

type NativeCredential struct {
	Username          string `json:"username"`
	Password          string `json:"password,omitempty"`          //nolint:gosec // stored encrypted via secretsStore when available; JSON field retained for legacy migration
	ContainerAuthFile string `json:"containerAuthFile,omitempty"` // path to the container auth file written on login
}

NativeCredential represents a stored registry credential. When a secrets store is available, the Password field is empty in the JSON file and the actual password is retrieved from the encrypted secrets store at runtime. Legacy entries that contain a plaintext password in JSON are still readable.

type NativeCredentialStore added in v0.7.0

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

NativeCredentialStore manages scafctl-native OCI registry credentials. Credentials are stored at <XDG_CONFIG_HOME>/scafctl/registries.json. When a secrets store is available, passwords are stored encrypted there instead of in the JSON file. Legacy entries with plaintext JSON passwords remain readable.

func NewNativeCredentialStore added in v0.7.0

func NewNativeCredentialStore() *NativeCredentialStore

NewNativeCredentialStore creates a new native credential store without an encrypted secrets backend. Passwords fall back to the plaintext JSON field. Callers that have access to a pre-configured secrets store (e.g. the shared store created in root.go) should use NewNativeCredentialStoreWithSecretsStore so that settings such as RequireSecureKeyring are honoured.

func NewNativeCredentialStoreWithPath added in v0.7.0

func NewNativeCredentialStoreWithPath(path string) *NativeCredentialStore

NewNativeCredentialStoreWithPath creates a native credential store at a custom path. The secrets store is not initialised so passwords are stored in plaintext JSON. This is intended for testing only.

func NewNativeCredentialStoreWithSecretsStore added in v0.7.0

func NewNativeCredentialStoreWithSecretsStore(secretsStore secrets.Store) *NativeCredentialStore

NewNativeCredentialStoreWithSecretsStore creates a new native credential store using the provided, pre-configured secrets store for encrypted password storage. Use this constructor whenever a secrets store is available so that centralised security settings (RequireSecureKeyring, logger) are honoured.

func (*NativeCredentialStore) DeleteAll added in v0.7.0

func (s *NativeCredentialStore) DeleteAll() error

DeleteAll removes all stored credentials.

func (*NativeCredentialStore) DeleteContainerAuth added in v0.7.0

func (s *NativeCredentialStore) DeleteContainerAuth(host string) error

DeleteContainerAuth removes a credential from the container auth file. It uses the path stored in the credential entry so deletion always targets the same file that was written during login. This is a best-effort operation.

func (*NativeCredentialStore) DeleteCredential added in v0.7.0

func (s *NativeCredentialStore) DeleteCredential(host string) error

DeleteCredential removes the credential for the given registry host. The host is normalized so that Docker Hub variants resolve to the canonical key.

func (*NativeCredentialStore) GetCredential added in v0.7.0

func (s *NativeCredentialStore) GetCredential(host string) (*NativeCredential, error)

GetCredential returns the credential for the given registry host. The host is normalized so that Docker Hub variants resolve to a canonical key. When a secrets store is available, the password is retrieved from encrypted storage.

func (*NativeCredentialStore) ListCredentialEntries added in v0.7.0

func (s *NativeCredentialStore) ListCredentialEntries() (map[string]NativeCredential, error)

ListCredentialEntries returns all stored registry hosts and their full credential entries. When a secrets store is available, passwords are retrieved from encrypted storage.

func (*NativeCredentialStore) ListCredentials added in v0.7.0

func (s *NativeCredentialStore) ListCredentials() (map[string]string, error)

ListCredentials returns all stored registry hosts and their usernames.

func (*NativeCredentialStore) Path added in v0.7.0

func (s *NativeCredentialStore) Path() string

Path returns the file path of the credential store.

func (*NativeCredentialStore) SetCredential added in v0.7.0

func (s *NativeCredentialStore) SetCredential(host, username, password, containerAuthFile string) error

SetCredential stores a credential for the given registry host. The host is normalized so that Docker Hub variants are stored under a canonical key. containerAuthFile is the path to the container auth file written during login, or empty if no container auth file was written. When a secrets store is available the password is stored encrypted; only the username and metadata are written to the JSON file.

func (*NativeCredentialStore) WriteContainerAuth added in v0.7.0

func (s *NativeCredentialStore) WriteContainerAuth(host, username, password string) (string, error)

WriteContainerAuth writes a credential to the container auth file for Docker/Podman interop. The file is detected in order: 1. $REGISTRY_AUTH_FILE environment variable 2. ~/.config/containers/auth.json 3. ~/.docker/config.json Returns the resolved file path on success so callers can persist it. This is a best-effort operation; callers should treat errors as warnings.

type OCITarReader

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

OCITarReader reads OCI Image Layout format from a tar archive.

func NewOCITarReader

func NewOCITarReader(r io.Reader) (*OCITarReader, error)

NewOCITarReader reads an OCI tar archive into memory.

func (*OCITarReader) Blobs

func (r *OCITarReader) Blobs() map[string][]byte

Blobs returns all blobs in the archive.

func (*OCITarReader) GetBlob

func (r *OCITarReader) GetBlob(digest string) ([]byte, bool)

GetBlob returns a specific blob by digest.

func (*OCITarReader) HasValidLayout

func (r *OCITarReader) HasValidLayout() bool

HasValidLayout returns true if the archive has a valid oci-layout file.

func (*OCITarReader) Index

func (r *OCITarReader) Index() (*ocispec.Index, error)

Index returns the parsed index.json.

type OCITarWriter

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

OCITarWriter writes OCI Image Layout format to a tar archive.

func NewOCITarWriter

func NewOCITarWriter(w io.Writer) *OCITarWriter

NewOCITarWriter creates a new OCI tar writer.

func (*OCITarWriter) Close

func (w *OCITarWriter) Close() error

Close closes the tar writer.

func (*OCITarWriter) WriteBlob

func (w *OCITarWriter) WriteBlob(digestStr string, data []byte) error

WriteBlob writes a blob to the blobs/sha256/ directory.

func (*OCITarWriter) WriteIndex

func (w *OCITarWriter) WriteIndex(index ocispec.Index) error

WriteIndex writes the index.json file.

func (*OCITarWriter) WriteOCILayout

func (w *OCITarWriter) WriteOCILayout() error

WriteOCILayout writes the oci-layout file.

type PlatformAwareCatalog added in v0.6.0

type PlatformAwareCatalog interface {
	Catalog

	// FetchByPlatform fetches a plugin binary for the given platform,
	// transparently handling both single-platform manifests and
	// multi-platform image indexes.
	FetchByPlatform(ctx context.Context, ref Reference, platform string) ([]byte, ArtifactInfo, error)

	// ListPlatforms returns the platforms available for a multi-platform artifact.
	// Returns nil if the artifact is single-platform.
	ListPlatforms(ctx context.Context, ref Reference) ([]string, error)
}

PlatformAwareCatalog extends Catalog with multi-platform image index support. Catalogs that store multi-platform artifacts (e.g. LocalCatalog) implement this interface to allow transparent platform-specific fetching.

type PlatformBinary added in v0.6.0

type PlatformBinary struct {
	// Platform in OCI format, e.g. "linux/amd64".
	Platform string `json:"platform" yaml:"platform" doc:"Target platform in os/arch format"`

	// Data is the raw binary content.
	Data []byte `json:"-" yaml:"-"`
}

PlatformBinary pairs a platform string (e.g. "linux/amd64") with the raw plugin binary for that platform.

func ReadPlatformBinaries added in v0.6.0

func ReadPlatformBinaries(ctx context.Context, platformPaths map[string]string) ([]PlatformBinary, error)

ReadPlatformBinaries validates platform names, resolves file paths to absolute paths, stats each file (rejecting directories), reads binary data, and returns PlatformBinary entries ready for storage.

platformPaths maps platform strings (e.g., "linux/amd64") to file paths. Returns an error if any platform is unsupported, path doesn't exist, path is a directory, or file data is empty or unreadable.

type PlatformNotFoundError added in v0.6.0

type PlatformNotFoundError struct {
	Platform  string   // The requested platform (e.g. "linux/amd64")
	Available []string // Available platforms in the index
}

PlatformNotFoundError provides details about a missing platform in an image index.

func (*PlatformNotFoundError) Error added in v0.6.0

func (e *PlatformNotFoundError) Error() string

Error implements the error interface.

func (*PlatformNotFoundError) Unwrap added in v0.6.0

func (e *PlatformNotFoundError) Unwrap() error

Unwrap returns the base error for errors.Is support.

type PluginFetcher added in v0.5.0

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

PluginFetcher fetches plugin binaries from a catalog with platform awareness. It resolves plugin references, selects the appropriate platform variant via the OCI image index (preferred) or AnnotationPlatform annotation (fallback), and returns the raw binary data.

func NewPluginFetcher added in v0.5.0

func NewPluginFetcher(catalog Catalog, logger logr.Logger) *PluginFetcher

NewPluginFetcher creates a PluginFetcher backed by the given catalog.

func (*PluginFetcher) FetchPlugin added in v0.5.0

func (f *PluginFetcher) FetchPlugin(ctx context.Context, name string, kind ArtifactKind, version, platform string) ([]byte, ArtifactInfo, error)

FetchPlugin fetches a plugin binary for the given platform. It uses the following resolution strategy:

  1. If the catalog implements PlatformAwareCatalog, use FetchByPlatform which handles OCI image indexes (fat manifests) transparently.
  2. Otherwise, fall back to listing artifacts and matching the AnnotationPlatform annotation on individual manifests.
  3. If no platform-specific artifact is found, attempt a direct fetch (single-platform fallback).

func (*PluginFetcher) ResolvePlugin added in v0.5.0

func (f *PluginFetcher) ResolvePlugin(ctx context.Context, name string, kind ArtifactKind, versionConstraint string) (ArtifactInfo, error)

ResolvePlugin resolves a plugin by name, kind, and version constraint, returning its artifact info. If versionConstraint is empty, the latest version is returned.

type PruneResult

type PruneResult struct {
	// RemovedManifests is the number of orphaned manifests removed
	RemovedManifests int `json:"removedManifests" yaml:"removedManifests"`
	// RemovedBlobs is the number of orphaned blobs removed
	RemovedBlobs int `json:"removedBlobs" yaml:"removedBlobs"`
	// ReclaimedBytes is the total bytes freed
	ReclaimedBytes int64 `json:"reclaimedBytes" yaml:"reclaimedBytes"`
}

PruneResult contains statistics from a prune operation.

type Reference

type Reference struct {
	// Kind is the type of artifact (solution, provider, or auth-handler).
	Kind ArtifactKind `json:"kind" yaml:"kind" doc:"Artifact type"`

	// Name is the artifact identifier (e.g., "my-solution").
	Name string `json:"name" yaml:"name" doc:"Artifact name"`

	// Version is the semantic version (e.g., 1.2.3). Nil means "latest".
	Version *semver.Version `json:"version,omitempty" yaml:"version,omitempty" doc:"Semantic version"`

	// Digest is the content digest for pinning (e.g., "sha256:abc123...").
	// If set, takes precedence over Version for resolution.
	Digest string `json:"digest,omitempty" yaml:"digest,omitempty" doc:"Content digest for pinning"`
}

Reference uniquely identifies an artifact in the catalog.

func ParseReference

func ParseReference(kind ArtifactKind, input string) (Reference, error)

ParseReference parses a reference string into a Reference struct. Supported formats:

  • "name" - artifact name only (version resolved to latest)
  • "name@1.2.3" - artifact with specific version
  • "name@sha256:abc..." - artifact with specific digest

func (Reference) HasDigest

func (r Reference) HasDigest() bool

HasDigest returns true if the reference has a digest specified.

func (Reference) HasVersion

func (r Reference) HasVersion() bool

HasVersion returns true if the reference has a version specified.

func (Reference) String

func (r Reference) String() string

String returns the canonical reference string (e.g., "my-solution@1.2.3").

func (Reference) VersionOrDigest added in v0.8.0

func (r Reference) VersionOrDigest() string

VersionOrDigest returns a display string for the reference identifier. Prefers Version.String() when set, falls back to Digest, then "unknown".

type ReferrerInfo added in v0.8.0

type ReferrerInfo struct {
	// ArtifactType is the media type or artifactType of the referrer.
	ArtifactType string `json:"artifactType" yaml:"artifactType"`

	// Digest is the referrer manifest digest.
	Digest string `json:"digest" yaml:"digest"`

	// Size is the referrer manifest size.
	Size int64 `json:"size" yaml:"size"`

	// Annotations from the referrer manifest.
	Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
}

ReferrerInfo describes an artifact attached to a subject via OCI referrers.

type Registry

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

Registry manages multiple catalogs and provides unified access. The local catalog is always first in resolution order.

func NewRegistry

func NewRegistry(logger logr.Logger) (*Registry, error)

NewRegistry creates a registry with the built-in local catalog.

func NewRegistryWithLocal

func NewRegistryWithLocal(local *LocalCatalog, logger logr.Logger) *Registry

NewRegistryWithLocal creates a registry with a custom local catalog. Use for testing with a custom catalog directory.

func (*Registry) AddCatalog

func (r *Registry) AddCatalog(catalog Catalog)

AddCatalog adds a catalog to the registry. Catalogs are searched in the order they are added (after local).

func (*Registry) Catalogs

func (r *Registry) Catalogs() []Catalog

Catalogs returns all registered catalogs.

func (*Registry) Fetch

func (r *Registry) Fetch(ctx context.Context, ref Reference) ([]byte, ArtifactInfo, error)

Fetch retrieves an artifact from the first catalog that has it. If cacheRemoteArtifacts is enabled, artifacts fetched from remote catalogs are automatically stored in the local catalog for subsequent offline access.

func (*Registry) FetchWithBundle

func (r *Registry) FetchWithBundle(ctx context.Context, ref Reference) ([]byte, []byte, ArtifactInfo, error)

FetchWithBundle retrieves an artifact with its bundle layer from the first catalog that has it. If cacheRemoteArtifacts is enabled, artifacts fetched from remote catalogs are automatically stored in the local catalog for subsequent offline access.

func (*Registry) List

func (r *Registry) List(ctx context.Context, kind ArtifactKind, name string) ([]ArtifactInfo, error)

List returns all artifacts matching the criteria from all catalogs.

func (*Registry) Local

func (r *Registry) Local() *LocalCatalog

Local returns the built-in local catalog.

func (*Registry) Resolve

func (r *Registry) Resolve(ctx context.Context, ref Reference) (ArtifactInfo, error)

Resolve finds an artifact in the first catalog that has it. Searches catalogs in order: local first, then configured catalogs.

func (*Registry) SetCacheRemoteArtifacts added in v0.3.0

func (r *Registry) SetCacheRemoteArtifacts(enabled bool)

SetCacheRemoteArtifacts enables or disables auto-caching of remote catalog fetches into the local catalog. When enabled, artifacts fetched from remote catalogs are automatically stored locally so subsequent fetches are served from the local catalog without network access.

type RegistryUsernameProvider added in v0.7.0

type RegistryUsernameProvider interface {
	RegistryUsername() string
}

RegistryUsernameProvider is an optional interface for auth handlers that declare a custom registry username convention. BridgeAuthToRegistry checks for this interface via type assertion on the default (non-built-in) path.

type RemoteCatalog

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

RemoteCatalog implements Catalog interface for OCI registries.

func NewRemoteCatalog

func NewRemoteCatalog(cfg RemoteCatalogConfig) (*RemoteCatalog, error)

NewRemoteCatalog creates a remote catalog client.

func (*RemoteCatalog) Attach added in v0.8.0

func (c *RemoteCatalog) Attach(ctx context.Context, ref Reference, artifactType string, data []byte, annotations map[string]string) (ocispec.Descriptor, error)

Attach pushes an artifact that references (is attached to) a subject artifact via the OCI referrers mechanism. The subject is identified by ref; the attachment is described by artifactType and its raw bytes.

func (*RemoteCatalog) CopyFrom

func (c *RemoteCatalog) CopyFrom(ctx context.Context, source *LocalCatalog, ref Reference, opts CopyOptions) (ArtifactInfo, error)

CopyFrom copies an artifact from a local catalog to this remote catalog.

func (*RemoteCatalog) CopyTo

func (c *RemoteCatalog) CopyTo(ctx context.Context, ref Reference, target *LocalCatalog, opts CopyOptions) (ArtifactInfo, error)

CopyTo copies an artifact from this remote catalog to a local catalog.

func (*RemoteCatalog) Delete

func (c *RemoteCatalog) Delete(ctx context.Context, ref Reference) error

Delete removes an artifact from the catalog.

The method first attempts a standard OCI delete by digest. If the registry rejects it because the manifest still has tags (e.g., GCP Artifact Registry returns 400 "dangling tag"), it retries by deleting via the tag reference.

func (*RemoteCatalog) Exists

func (c *RemoteCatalog) Exists(ctx context.Context, ref Reference) (bool, error)

Exists checks if an artifact exists in the catalog.

func (*RemoteCatalog) Fetch

func (c *RemoteCatalog) Fetch(ctx context.Context, ref Reference) ([]byte, ArtifactInfo, error)

Fetch retrieves an artifact from the remote catalog.

func (*RemoteCatalog) FetchWithBundle

func (c *RemoteCatalog) FetchWithBundle(ctx context.Context, ref Reference) ([]byte, []byte, ArtifactInfo, error)

FetchWithBundle retrieves an artifact's primary content and bundle layer. If the artifact has no bundle layer, bundleData is nil.

func (*RemoteCatalog) List

func (c *RemoteCatalog) List(ctx context.Context, kind ArtifactKind, name string) ([]ArtifactInfo, error)

List returns all artifacts matching the criteria.

func (*RemoteCatalog) ListTags added in v0.8.0

func (c *RemoteCatalog) ListTags(ctx context.Context, ref Reference) ([]TagInfo, error)

ListTags returns all tags (semver versions and aliases) for an artifact in the remote registry.

func (*RemoteCatalog) Name

func (c *RemoteCatalog) Name() string

Name returns the catalog identifier.

func (*RemoteCatalog) Referrers added in v0.8.0

func (c *RemoteCatalog) Referrers(ctx context.Context, ref Reference, artifactType string) ([]ReferrerInfo, error)

Referrers lists all artifacts that reference the given subject artifact. If artifactType is non-empty, only referrers matching that type are returned.

func (*RemoteCatalog) Registry

func (c *RemoteCatalog) Registry() string

Registry returns the registry address.

func (*RemoteCatalog) Repository

func (c *RemoteCatalog) Repository() string

Repository returns the base repository path.

func (*RemoteCatalog) RepositoryPath added in v0.8.0

func (c *RemoteCatalog) RepositoryPath(ref Reference) string

RepositoryPath returns the full OCI repository path for an artifact reference. This is useful for displaying the resolved path in CLI output.

func (*RemoteCatalog) Resolve

func (c *RemoteCatalog) Resolve(ctx context.Context, ref Reference) (ArtifactInfo, error)

Resolve finds the best matching version for a reference.

func (*RemoteCatalog) Store

func (c *RemoteCatalog) Store(ctx context.Context, ref Reference, content, bundleData []byte, annotations map[string]string, force bool) (ArtifactInfo, error)

Store saves an artifact to the remote catalog. For solutions with bundled files, bundleData contains the tar archive. If bundleData is nil, only the primary content layer is stored.

func (*RemoteCatalog) Tag

func (c *RemoteCatalog) Tag(ctx context.Context, ref Reference, alias string) (string, error)

Tag creates an alias tag for an existing remote artifact. Returns a non-empty string if the alias already existed pointing to a different digest.

type RemoteCatalogConfig

type RemoteCatalogConfig struct {
	// Name is the catalog identifier (e.g., "company-registry")
	Name string

	// RegistryURL is the registry address (e.g., "ghcr.io", "registry.example.com")
	Registry string

	// Repository is the base repository path (e.g., "myorg/scafctl")
	Repository string

	// CredentialStore provides authentication credentials
	CredentialStore *CredentialStore

	// AuthHandler provides dynamic token injection for this catalog.
	// When set, if the CredentialStore has no credentials for the registry,
	// the handler's token is bridged to OCI registry credentials.
	AuthHandler scafctlauth.Handler

	// AuthScope is the OAuth scope for auth handler token requests.
	AuthScope string

	// Insecure allows HTTP connections (for testing)
	Insecure bool

	// Logger for logging operations
	Logger logr.Logger
}

RemoteCatalogConfig holds configuration for creating a remote catalog.

type RemoteReference

type RemoteReference struct {
	// Registry is the registry host (e.g., "ghcr.io", "docker.io")
	Registry string

	// Repository is the repository path (e.g., "myorg/scafctl")
	Repository string

	// Kind is the artifact kind (solution, provider, or auth-handler)
	Kind ArtifactKind

	// Name is the artifact name
	Name string

	// Tag is the version tag or digest
	Tag string
}

RemoteReference represents a parsed remote registry reference.

func ParseRemoteReference

func ParseRemoteReference(input string) (*RemoteReference, error)

ParseRemoteReference parses a full remote reference URL. Supported formats:

  • "ghcr.io/myorg/scafctl/solutions/my-solution@1.0.0"
  • "oci://ghcr.io/myorg/scafctl/solutions/my-solution@1.0.0"
  • "docker.io/myorg/my-solution:1.0.0" (Docker Hub style)

Returns the registry, repository, name, and version/tag.

func (*RemoteReference) String

func (r *RemoteReference) String() string

String returns the full remote reference string.

func (*RemoteReference) ToReference

func (r *RemoteReference) ToReference() (Reference, error)

ToReference converts a RemoteReference to a Reference.

type RemoteSolutionResolver added in v0.8.0

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

RemoteSolutionResolver fetches solutions from remote OCI registries given a full Docker-style reference (e.g., "ghcr.io/myorg/starter-kit@1.0.0"). It implements the get.RemoteResolver interface.

func NewRemoteSolutionResolver added in v0.8.0

func NewRemoteSolutionResolver(cfg RemoteSolutionResolverConfig) *RemoteSolutionResolver

NewRemoteSolutionResolver creates a new RemoteSolutionResolver.

func (*RemoteSolutionResolver) FetchRemoteSolution added in v0.8.0

func (r *RemoteSolutionResolver) FetchRemoteSolution(ctx context.Context, rawRef string) ([]byte, []byte, error)

FetchRemoteSolution fetches a solution from a remote OCI reference. The ref is parsed via ParseRemoteReference. If no kind is specified in the path, the kind defaults to ArtifactKindSolution.

type RemoteSolutionResolverConfig added in v0.8.0

type RemoteSolutionResolverConfig struct {
	// CredentialStore provides authentication credentials for remote registries.
	CredentialStore *CredentialStore

	// AuthHandlerFunc returns an auth handler for a given registry host.
	// When set, the handler is passed to RemoteCatalogConfig.AuthHandler for
	// automatic token bridging. May return nil if no handler is available.
	AuthHandlerFunc func(registry string) scafctlauth.Handler

	// AuthScopeFunc returns an OAuth scope for a given registry host.
	// When set, the scope is passed to RemoteCatalogConfig.AuthScope so
	// handlers like GCP/Entra can request appropriately scoped tokens.
	AuthScopeFunc func(registry string) string

	// Insecure allows HTTP connections to registries (for testing).
	Insecure bool

	// Logger for logging operations.
	Logger logr.Logger
}

RemoteSolutionResolverConfig holds configuration for the remote solution resolver.

type SaveResult

type SaveResult struct {
	// Reference is the artifact that was saved.
	Reference Reference `json:"reference" yaml:"reference"`
	// OutputPath is the path to the created archive.
	OutputPath string `json:"outputPath" yaml:"outputPath"`
	// Size is the size of the archive in bytes.
	Size int64 `json:"size" yaml:"size"`
	// Digest is the manifest digest.
	Digest string `json:"digest" yaml:"digest"`
}

SaveResult contains information about the save operation.

type SolutionResolver

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

SolutionResolver wraps a Catalog to provide solution fetching by name[@version]. It implements the CatalogResolver interface from pkg/solution/get.

func NewSolutionResolver

func NewSolutionResolver(catalog Catalog, logger logr.Logger, opts ...SolutionResolverOption) *SolutionResolver

NewSolutionResolver creates a resolver that fetches solutions from the given catalog. Optional SolutionResolverOption values may be provided to configure artifact caching and cache bypass behavior.

func (*SolutionResolver) FetchSolution

func (r *SolutionResolver) FetchSolution(ctx context.Context, nameWithVersion string) ([]byte, error)

FetchSolution retrieves a solution from the catalog by name[@version]. The input format is "name" or "name@version" (e.g., "my-solution" or "my-solution@1.2.3"). Returns the solution content as bytes.

When an artifact cache is configured and noCache is false, the result is served from cache on a hit (within TTL), otherwise the catalog is fetched and the result is stored for future use.

func (*SolutionResolver) FetchSolutionWithBundle

func (r *SolutionResolver) FetchSolutionWithBundle(ctx context.Context, nameWithVersion string) ([]byte, []byte, error)

FetchSolutionWithBundle retrieves a solution and its bundle from the catalog by name[@version]. The input format is "name" or "name@version" (e.g., "my-solution" or "my-solution@1.2.3"). Returns the solution content bytes, bundle tar bytes (nil if no bundle), and any error.

When an artifact cache is configured and noCache is false, both content and bundle are cached together for TTL-based reuse.

type SolutionResolverOption added in v0.6.0

type SolutionResolverOption func(*SolutionResolver)

SolutionResolverOption configures a SolutionResolver.

func WithResolverArtifactCache added in v0.6.0

func WithResolverArtifactCache(c ArtifactCacher) SolutionResolverOption

WithResolverArtifactCache sets the artifact cache for the resolver. When set, fetched artifacts are stored in and served from this cache.

func WithResolverNoCache added in v0.6.0

func WithResolverNoCache(noCache bool) SolutionResolverOption

WithResolverNoCache disables artifact caching for this resolver. When true, the cache is neither read nor written, ensuring fresh catalog fetches.

func WithResolverRemoteCatalogs added in v0.8.0

func WithResolverRemoteCatalogs(remotes []Catalog) SolutionResolverOption

WithResolverRemoteCatalogs sets fallback remote catalogs for the resolver. When the local catalog does not contain the requested artifact, these remotes are tried in order. On a remote hit the artifact is automatically pulled into the local catalog so subsequent runs are instant.

type TagInfo added in v0.8.0

type TagInfo struct {
	Tag      string `json:"tag" yaml:"tag"`
	IsSemver bool   `json:"isSemver" yaml:"isSemver"`
	Version  string `json:"version,omitempty" yaml:"version,omitempty"`
}

TagInfo represents a single tag in a remote OCI repository.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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