Documentation
¶
Overview ¶
Package registry provides a platform-agnostic abstraction over container registries (Docker Hub, GitLab, GHCR, Quay, JFrog, Harbor, Gitea). Every registry operation (list tags, delete tags) goes through the Registry interface so StageFreight's retention engine works identically regardless of where images are hosted.
Index ¶
- func CanonicalProvider(provider string) (string, error)
- func CheckManifestDigest(ctx context.Context, host, path, tag string, ...) (string, error)
- func DeriveRawBase(linkBase string) string
- func DiscoverAllArtifacts(ctx context.Context, images []build.PublishedImage, ...) map[string]ArtifactLinks
- func HasSection(content, name string) bool
- func InsertAboveMatch(content, pattern, text string) (string, bool)
- func InsertAboveMatchInSection(content, sectionName, pattern, text string) (string, bool)
- func InsertAboveSection(content, name, text string) (string, bool)
- func InsertBelowMatch(content, pattern, text string) (string, bool)
- func InsertBelowMatchInSection(content, sectionName, pattern, text string) (string, bool)
- func InsertBelowSection(content, name, text string) (string, bool)
- func IsForbidden(err error) bool
- func NormalizeHost(h string) string
- func NormalizeProvider(p string) string
- func PlaceContent(content, sectionName, position, matchPattern, text string, inline, plain bool) string
- func ReplaceBetween(content, startMarker, endMarker, replacement string) (updated string, found bool)
- func ReplaceMatch(content, pattern, text string) (string, bool)
- func ReplaceMatchInSection(content, sectionName, pattern, text string) (string, bool)
- func ReplaceSection(content, name, replacement string) (updated string, found bool)
- func SectionContent(content, name string) (string, bool)
- func SectionEnd(name string) string
- func SectionStart(name string) string
- func ValidateCredentials(prefix string) error
- func ValidateImagePath(path string) error
- func ValidatePattern(pattern string) error
- func ValidateProvider(provider string) error
- func ValidateRegistryConfig(url, path string, tags []string, credentials, provider string, ...) []error
- func ValidateRegistryURL(u string) error
- func ValidateRetention(r config.RetentionPolicy) error
- func ValidateTag(tag string) error
- func ValidateTagTemplate(tmpl string) error
- func WrapSection(name, content string) string
- func WrapSectionInline(name, content string) string
- type ArtifactLinks
- type DockerHub
- func (d *DockerHub) DeleteTag(ctx context.Context, repo string, tag string) error
- func (d *DockerHub) ListTags(ctx context.Context, repo string) ([]TagInfo, error)
- func (d *DockerHub) Provider() string
- func (d *DockerHub) UpdateDescription(ctx context.Context, repo, short, full string) error
- func (d *DockerHub) Warnings() []string
- type GHCR
- type GitLabRegistry
- func (g *GitLabRegistry) DeleteTag(ctx context.Context, repo string, tag string) error
- func (g *GitLabRegistry) ListTags(ctx context.Context, repo string) ([]TagInfo, error)
- func (g *GitLabRegistry) Provider() string
- func (g *GitLabRegistry) UpdateDescription(_ context.Context, _, _, _ string) error
- type Gitea
- type HTTPError
- type Harbor
- type JFrog
- type Local
- type Quay
- type ReadmeContent
- type Registry
- type ResolvedRegistryTarget
- type RetentionResult
- type SkippedError
- type TagInfo
- type VerificationResult
- type Warner
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CanonicalProvider ¶
CanonicalProvider normalizes a provider string to its canonical form and validates it. Returns the canonical name or an error for unknown values.
func CheckManifestDigest ¶
func CheckManifestDigest(ctx context.Context, host, path, tag string, credResolver func(string) (string, string), credRef string) (string, error)
CheckManifestDigest performs a HEAD (fallback GET) on the OCI manifest endpoint. Returns the Docker-Content-Digest header value if available. Exported for cross-client digest verification (shadow write detection).
func DeriveRawBase ¶
DeriveRawBase auto-derives a raw file URL base from a link_base URL. Supports GitHub, GitLab, and Gitea URL patterns.
func DiscoverAllArtifacts ¶
func DiscoverAllArtifacts(ctx context.Context, images []build.PublishedImage, credResolver func(string) (string, string)) map[string]ArtifactLinks
DiscoverAllArtifacts runs DiscoverArtifacts concurrently for multiple images. Deduplicates by host/path@digest to avoid redundant lookups.
func HasSection ¶
HasSection reports whether content contains markers for the named section.
func InsertAboveMatch ¶
InsertAboveMatch inserts text before the first line matching the regex pattern. Returns the updated content and whether a match was found.
func InsertAboveMatchInSection ¶
InsertAboveMatchInSection finds a regex match within a named section and inserts text above the matched line. The section markers are preserved.
func InsertAboveSection ¶
InsertAboveSection inserts text before the opening <!-- sf:<name> --> marker. Returns the updated content and whether the section was found.
func InsertBelowMatch ¶
InsertBelowMatch inserts text after the first line matching the regex pattern. Returns the updated content and whether a match was found.
func InsertBelowMatchInSection ¶
InsertBelowMatchInSection finds a regex match within a named section and inserts text below the matched line. The section markers are preserved.
func InsertBelowSection ¶
InsertBelowSection inserts text after the closing <!-- /sf:<name> --> marker. Returns the updated content and whether the section was found.
func IsForbidden ¶
IsForbidden returns true if the error chain contains an HTTP 403 response.
func NormalizeHost ¶
NormalizeHost strips scheme prefixes and trailing slashes from a registry host. Prevents config variations like "https://ghcr.io" from producing broken URLs.
func NormalizeProvider ¶
NormalizeProvider maps provider aliases to their canonical platform names. Canonical names are the platform brand: docker, github, gitlab, quay, jfrog, harbor, gitea. Legacy aliases (dockerhub, ghcr) are accepted and mapped to canonical forms.
func PlaceContent ¶
func PlaceContent(content, sectionName, position, matchPattern, text string, inline, plain bool) string
PlaceContent applies a placement operation to inject content into a document. Handles all combinations: section, match, section+match, top, bottom. The position parameter should already be normalized (above/below/replace/top/bottom). If inline is true, first-insertion wraps inline; if plain is true, no markers.
func ReplaceBetween ¶
func ReplaceBetween(content, startMarker, endMarker, replacement string) (updated string, found bool)
ReplaceBetween finds arbitrary start/end markers and replaces the content between them. Markers themselves are preserved. Works like ReplaceSection but with user-specified markers instead of the standard sf:NAME pattern. Whitespace detection: if markers are inline (no newline between), no padding.
func ReplaceMatch ¶
ReplaceMatch replaces lines matching the regex pattern with the provided text. All contiguous matching lines are replaced as a block. Returns the updated content and whether a match was found.
func ReplaceMatchInSection ¶
ReplaceMatchInSection finds a regex match within a named section and replaces matched lines. The section markers are preserved.
func ReplaceSection ¶
ReplaceSection finds the markers for the named section and replaces the content between them. Markers themselves are preserved. Returns the updated content and whether the section was found.
Whitespace-aware: if both markers are on the same line in the source (inline section), replacement is inserted without newline padding. If markers are on separate lines (block section), replacement gets newline padding for readability. The source document declares the intent by how the markers are placed.
If the section is not found, content is returned unchanged with found=false so the caller can decide where to insert a new section.
func SectionContent ¶
SectionContent extracts the content between section markers. Returns the content and whether the section was found.
func SectionEnd ¶
SectionEnd returns the closing marker for a named managed section.
func SectionStart ¶
SectionStart returns the opening marker for a named managed section.
func ValidateCredentials ¶
ValidateCredentials checks that a credential prefix is a valid env var name.
func ValidateImagePath ¶
ValidateImagePath checks that a repository/image path conforms to OCI spec.
func ValidatePattern ¶
ValidatePattern checks that a regex pattern compiles.
func ValidateProvider ¶
ValidateProvider normalizes and checks that the provider is a known value.
func ValidateRegistryConfig ¶
func ValidateRegistryConfig(url, path string, tags []string, credentials, provider string, branches, gitTags []string, retention config.RetentionPolicy) []error
ValidateRegistryConfig runs all validation checks against a registry config entry. Returns all errors found (not just the first).
func ValidateRegistryURL ¶
ValidateRegistryURL checks that a registry URL is well-formed. Rejects strings with spaces, control characters, or invalid structure.
func ValidateRetention ¶
func ValidateRetention(r config.RetentionPolicy) error
ValidateRetention checks that all retention policy values are non-negative.
func ValidateTag ¶
ValidateTag checks that a resolved tag conforms to OCI spec.
func ValidateTagTemplate ¶
ValidateTagTemplate checks that an unresolved tag template is structurally valid. Allows {var} and {var:param} syntax. Rejects unclosed braces, spaces, control chars.
func WrapSection ¶
WrapSection wraps content in named section markers (block mode with newlines).
func WrapSectionInline ¶
WrapSectionInline wraps content in named section markers (inline, no newlines).
Types ¶
type ArtifactLinks ¶
type ArtifactLinks struct {
SBOM string // digest ref for SBOM artifact (host/path@sha256:...)
Provenance string // digest ref for provenance artifact
Signature string // digest ref for signature artifact
}
ArtifactLinks holds discovered OCI referrer artifact links for an image.
func DiscoverArtifacts ¶
func DiscoverArtifacts(ctx context.Context, img build.PublishedImage, credResolver func(string) (string, string)) (ArtifactLinks, error)
DiscoverArtifacts queries the OCI referrers API for a verified image digest. Returns links to SBOM, provenance, and signature artifacts if present. Best-effort: returns empty ArtifactLinks (no error) if referrers API unsupported.
type DockerHub ¶
type DockerHub struct {
// contains filtered or unexported fields
}
DockerHub implements the Registry interface for Docker Hub. Uses hub.docker.com v2 API for listing, deleting tags, and updating descriptions. Authenticates via /v2/auth/token (supports both PATs and passwords).
func NewDockerHub ¶
func (*DockerHub) UpdateDescription ¶
type GHCR ¶
type GHCR struct {
// contains filtered or unexported fields
}
GHCR implements the Registry interface for GitHub Container Registry (ghcr.io). Uses the GitHub REST API for package version management. Requires a PAT with read:packages and delete:packages scopes.
type GitLabRegistry ¶
type GitLabRegistry struct {
// contains filtered or unexported fields
}
GitLabRegistry implements the Registry interface for GitLab Container Registry. Uses the GitLab REST API (projects/:id/registry/repositories) for tag management. Requires either a CI_JOB_TOKEN (in CI) or a personal/project access token.
func NewGitLab ¶
func NewGitLab(registryURL, user, pass string) *GitLabRegistry
func (*GitLabRegistry) Provider ¶
func (g *GitLabRegistry) Provider() string
func (*GitLabRegistry) UpdateDescription ¶
func (g *GitLabRegistry) UpdateDescription(_ context.Context, _, _, _ string) error
type Gitea ¶
type Gitea struct {
// contains filtered or unexported fields
}
Gitea implements the Registry interface for Gitea/Forgejo container package registries. Uses the Gitea package API (/api/v1/packages/:owner). Requires a token with package:read and package:delete scopes.
type Harbor ¶
type Harbor struct {
// contains filtered or unexported fields
}
Harbor implements the Registry interface for Harbor v2 container registry. Uses the Harbor REST API v2.0 (/api/v2.0/projects/:project/repositories/:repo/artifacts). Requires a user with push+delete permissions on the target project.
type JFrog ¶
type JFrog struct {
// contains filtered or unexported fields
}
JFrog implements the Registry interface for JFrog Artifactory / JFrog Container Registry. Uses the Artifactory REST API for Docker registry management. Requires an admin token or user with delete permissions on the target repository.
type Local ¶
type Local struct{}
Local implements the Registry interface for the local Docker daemon. Uses `docker` CLI commands to list and remove images — no remote API calls. This enables retention for local dev builds loaded with --load.
type Quay ¶
type Quay struct {
// contains filtered or unexported fields
}
Quay implements the Registry interface for Quay.io (and self-hosted Quay/Red Hat Quay). Uses the Quay REST API (/api/v1/repository). Requires an OAuth token or robot account token with repo:admin scope.
type ReadmeContent ¶
ReadmeContent holds the processed README ready for pushing to registries.
func PrepareReadmeFromFile ¶
func PrepareReadmeFromFile(file, description, linkBase, rootDir string) (*ReadmeContent, error)
PrepareReadmeFromFile loads a README file and returns processed content ready for registry sync. Takes individual fields for maximum flexibility — callers resolve config to args.
type Registry ¶
type Registry interface {
// Provider returns the registry vendor name.
Provider() string
// ListTags returns all tags for a repository, sorted by creation time descending.
ListTags(ctx context.Context, repo string) ([]TagInfo, error)
// DeleteTag removes a single tag from a repository.
DeleteTag(ctx context.Context, repo string, tag string) error
// UpdateDescription pushes short and full descriptions to the registry.
// Returns nil for providers that don't support description APIs.
UpdateDescription(ctx context.Context, repo, short, full string) error
}
Registry is the interface every container registry provider implements.
func NewRegistry ¶
NewRegistry creates a registry client for the given provider. Credentials are resolved from environment variables using the prefix:
prefix: "DOCKER" → DOCKER_USER / DOCKER_PASS prefix: "GHCR_ORG" → GHCR_ORG_USER / GHCR_ORG_PASS
The registryURL is the base URL (e.g., "docker.io", "ghcr.io").
type ResolvedRegistryTarget ¶
type ResolvedRegistryTarget struct {
Provider string // canonical provider: docker, github, gitlab, quay, jfrog, harbor, gitea, generic
Host string // normalized registry host (e.g., "docker.io", "registry.gitlab.com")
Path string // resolved repo/image path (e.g., "prplanit/stagefreight")
Tags []string // fully resolved publish tags
}
ResolvedRegistryTarget is a fully resolved registry target with enough information to both push images and generate deterministic UI URLs. If StageFreight can publish to this target, it can generate correct URLs.
func (ResolvedRegistryTarget) DisplayName ¶
func (r ResolvedRegistryTarget) DisplayName() string
DisplayName returns the human-friendly registry label.
func (ResolvedRegistryTarget) ImageRef ¶
func (r ResolvedRegistryTarget) ImageRef() string
ImageRef returns the canonical image reference (host/path).
func (ResolvedRegistryTarget) RepoURL ¶
func (r ResolvedRegistryTarget) RepoURL() string
RepoURL returns the web UI URL for this image's repository page. Every supported provider returns a deterministic URL. Generic provider returns https://{host}/{path} (the user's configured URL). Panics on unknown providers — if StageFreight can publish, it must resolve URLs.
func (ResolvedRegistryTarget) TagURL ¶
func (r ResolvedRegistryTarget) TagURL(tag string) string
TagURL returns the web UI URL for a specific tag on this image. Every supported provider returns a deterministic URL. Generic provider returns https://{host}/{path} (best available reference). Panics on unknown providers — if StageFreight can publish, it must resolve URLs.
type RetentionResult ¶
type RetentionResult struct {
Provider string
Repo string
Matched int // tags matching the pattern set
Kept int // tags kept by policy
Deleted []string // tags successfully deleted
Skipped []string // tags skipped (digest shared with protected tag)
Errors []error // errors from individual deletes
}
RetentionResult captures what the retention engine did.
func ApplyRetention ¶
func ApplyRetention(ctx context.Context, reg Registry, repo string, tagPatterns []string, policy config.RetentionPolicy) (*RetentionResult, error)
ApplyRetention lists all tags on the registry, filters them by the given tag patterns (using config.MatchPatterns with full !/OR/AND semantics), sorts by creation time descending, and applies restic-style retention policies to decide which tags to keep.
Tags whose digest is shared with a protected tag are skipped during deletion to prevent breaking rolling tags like latest-dev.
Policies are additive — a tag survives if ANY policy wants to keep it:
- keep_last N: keep the N most recent
- keep_daily N: keep one per day for the last N days
- keep_weekly N: keep one per week for the last N weeks
- keep_monthly N: keep one per month for the last N months
- keep_yearly N: keep one per year for the last N years
tagPatterns uses the same syntax as branches/git_tags in the config:
["^dev-"] → only tags starting with "dev-" ["^dev-", "!^dev-keep"]→ dev- tags, excluding dev-keep* [] → ALL tags are candidates (dangerous, use with care)
type SkippedError ¶
type SkippedError struct {
Tag string
}
SkippedError is a sentinel indicating a tag was skipped because its digest is shared with a protected tag.
func (*SkippedError) Error ¶
func (e *SkippedError) Error() string
func (*SkippedError) IsSkipped ¶
func (e *SkippedError) IsSkipped() bool
type VerificationResult ¶
type VerificationResult struct {
Image build.PublishedImage
Verified bool
Digest string // remote digest if available
Err error
}
VerificationResult tracks the outcome of verifying a single published image.
func VerifyImages ¶
func VerifyImages(ctx context.Context, images []build.PublishedImage, credResolver func(string) (string, string)) ([]VerificationResult, error)
VerifyImages checks each published image against its remote registry. Uses OCI Distribution API HEAD (fallback GET) manifest request. Concurrent (max 8 workers), retries with exponential backoff. Digest mismatch is a verification failure.