registry

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: BSD-3-Clause Imports: 22 Imported by: 0

Documentation

Overview

Package registry resolves image references against their registries and decides, from image configuration alone, which PHP release each platform of an image carries.

Only manifests and image configs are read; layers are never downloaded. A PHP version is claimed only when an image config carries the build environment of the official php image (github.com/docker-library/php), which images built FROM php inherit:

PHP_VERSION=X.Y.Z
PHP_URL=https://www.php.net/distributions/php-X.Y.Z.tar.xz   (or .gz, .bz2;
        older images: https://secure.php.net/get/php-X.Y.Z.tar.xz/from/this/mirror)
PHP_SHA256=<64 hex digits>   (very old images: PHP_MD5=<32 hex digits>)

Anything else makes no claim: an image that installs PHP some other way may well contain PHP, but its config does not prove which release.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BaseOSFromName

func BaseOSFromName(n string) string

BaseOSFromName normalizes an org.opencontainers.image.base.name value to family:release ("debian:bookworm-slim" becomes "debian:bookworm", "alpine:3.21" stays). It returns "" for anything that is not a plain repository:tag of an operating system image.

func CleanText

func CleanText(s string, max int) string

CleanText makes registry- or file-provided text safe to put in a one-line message: control characters (including newlines) become spaces, runs of spaces collapse, and the result is cut to max bytes (on a rune boundary) with "..." appended when cut.

func NormalizePlatform

func NormalizePlatform(p string) string

NormalizePlatform makes platform strings comparable: "linux/arm64/v8" and "linux/arm64" are the same platform.

func PHPFromEnv

func PHPFromEnv(env []string) (string, []string)

PHPFromEnv decides the PHP version from an image config's environment. It returns "" unless the environment is the official php image's build environment (see the package documentation).

func PlatformMatches

func PlatformMatches(want, have string) bool

PlatformMatches reports whether an image platform satisfies a requested one. Both are os/arch[/variant]; linux/arm64 and linux/arm64/v8 are the same; a request without a variant matches every variant of its os/arch ("linux/arm" matches linux/arm/v6 and linux/arm/v7), so all of them are judged.

func Transient

func Transient(kind string) bool

Transient reports whether an error kind (ErrorKind.String(), as in repocheck.Result.ErrorKind) may succeed on a later attempt: network, timeout and rate-limited failures. not-found, denied, invalid, unsupported and offline are definitive for this scan.

Types

type Assessment

type Assessment struct {
	Verdict Verdict `json:"verdict"`
	Reason  string  `json:"reason"`
	// Platforms lists the platforms that prove a PHP version.
	Platforms []PlatformVerdict `json:"platforms,omitempty"`
	// VulnerablePlatforms lists the vulnerable ones ("linux/amd64 (PHP 8.3.35)").
	VulnerablePlatforms []string `json:"vulnerable_platforms,omitempty"`
	// WithoutPHP lists platforms whose config proves no PHP version.
	WithoutPHP []string `json:"without_php,omitempty"`
}

Assessment is the verdict for a Resolution, with the per-platform reasons.

func Assess

func Assess(res *Resolution) Assessment

Assess judges a Resolution by knowledge.Upstream, platform by platform.

func AssessPlatform

func AssessPlatform(res *Resolution, platform string) Assessment

AssessPlatform judges res for one platform only, as a FROM --platform= does; an empty platform judges every platform.

type Error

type Error struct {
	Kind ErrorKind
	Ref  string
	Err  error
}

Error is a resolution failure.

func (*Error) Error

func (e *Error) Error() string

Error is a single line. The underlying error's text, which can come from the registry's response body, is stripped of control characters and cut to about 200 characters.

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorKind

type ErrorKind int

ErrorKind classifies resolution failures.

const (
	KindNetwork     ErrorKind = iota // the registry could not be reached or failed
	KindNotFound                     // the tag, digest or repository does not exist
	KindDenied                       // authentication required or refused (Docker Hub also answers this for repositories that do not exist)
	KindRateLimited                  // HTTP 429 after retries
	KindInvalid                      // not a valid reference
	KindUnsupported                  // a manifest the scanner does not read (schema 1, artifacts)
	KindOffline                      // offline mode cannot resolve the reference
	KindTimeout                      // a timeout or deadline expired (or the call was cancelled)
)

func (ErrorKind) String

func (k ErrorKind) String() string

type Options

type Options struct {
	// Offline makes no network requests. Only a docker.io/library/php
	// reference with an exact X.Y.Z tag and no digest resolves (the official
	// tags are the PHP version); everything else returns an Error of kind
	// KindOffline.
	Offline bool
	// Keychain supplies registry credentials (default authn.DefaultKeychain,
	// which reads the Docker config and credential helpers).
	Keychain authn.Keychain
	// Transport is the base HTTP transport (default: go-containerregistry's
	// remote.DefaultTransport with a 30 s response header timeout).
	Transport http.RoundTripper
	// Timeout bounds each Resolve and Tags call (default 2 minutes).
	Timeout time.Duration
	// Retries is how many times a request is retried after HTTP 429, 500, 502,
	// 503, 504 or a transient network error (default 4; negative for none).
	Retries int
	// MinBackoff and MaxBackoff bound the exponential backoff between retries
	// (defaults 1 s and 30 s). A Retry-After header longer than MaxRetryAfter
	// (default 60 s) is not waited for: the request fails as rate limited.
	MinBackoff, MaxBackoff, MaxRetryAfter time.Duration
	// Concurrency is the most registry requests in flight (default 4).
	Concurrency int
	// Mirrors sends requests for a registry to another host
	// ({"index.docker.io": "mirror.example.com"}). The reference keeps its
	// name; only the host contacted changes. Tests point Docker Hub at an
	// in-memory registry this way.
	Mirrors map[string]string
	// UserAgent is sent with every request (default "php2shell-scan").
	UserAgent string
	// Platforms, when set, restricts every Resolution to these platforms
	// ("linux/amd64", "linux/arm64"; see PlatformMatches): images for other
	// platforms are left out and listed in Resolution.OmittedPlatforms.
	Platforms []string
	// RequestTimeout bounds the wait for each response's headers (default
	// 30 s) and, at twice that, for its body, whatever Transport is given. A
	// registry host that times out is not contacted again by this Resolver:
	// later requests to it fail at once (as KindTimeout).
	RequestTimeout time.Duration
}

Options configure a Resolver.

type Platform

type Platform struct {
	// Platform is os/arch[/variant]; "" when unknown (offline resolution).
	Platform string    `json:"platform"`
	Digest   string    `json:"digest,omitempty"`
	Created  time.Time `json:"created,omitempty"`
	// PHPVersion is set only when the image config proves it (see the package
	// documentation); Evidence says how.
	PHPVersion string   `json:"php_version,omitempty"`
	Evidence   []string `json:"evidence,omitempty"`
	// BaseOS is the base operating system release the image is built on,
	// normalized ("alpine:3.21", "debian:bookworm"), from the
	// org.opencontainers.image.base.name annotation (BaseSource
	// "annotation") or, failing that, from the first history entry the
	// docker-library build leaves (BaseSource "history"); "" when unknown.
	BaseOS     string `json:"base_os,omitempty"`
	BaseSource string `json:"base_source,omitempty"`
	// ImageVersion is the org.opencontainers.image.version annotation; for
	// the official php image it is the explicit tag ("8.3.20-fpm-alpine3.21").
	ImageVersion string `json:"image_version,omitempty"`
}

Platform is one image of a Resolution.

type PlatformVerdict

type PlatformVerdict struct {
	Platform   string                   `json:"platform"`
	PHPVersion string                   `json:"php_version"`
	Status     knowledge.UpstreamStatus `json:"status"`
	Reason     string                   `json:"reason"`
}

PlatformVerdict is the judgement for one platform with a proven PHP version.

type Reference

type Reference struct {
	// Original is the reference as given.
	Original string
	// Registry is the registry host as go-containerregistry normalizes it
	// ("index.docker.io" for Docker Hub).
	Registry string
	// Path is the repository path within the registry ("library/php").
	Path string
	// Tag is the tag as written, "" when there is none (for a reference
	// without a digest that means "latest").
	Tag string
	// Digest is the digest as written, "" when there is none.
	Digest string
}

Reference is a parsed image reference. Unlike name.ParseReference, it keeps both the tag and the digest of "repo:tag@sha256:...".

func ParseReference

func ParseReference(s string) (Reference, error)

ParseReference parses an image reference string.

func (Reference) EffectiveTag

func (r Reference) EffectiveTag() string

EffectiveTag is the tag a pull by tag uses: Tag, or "latest".

func (Reference) IsOfficialPHP

func (r Reference) IsOfficialPHP() bool

IsOfficialPHP reports whether the reference names Docker Hub's official php image (php, library/php, docker.io/library/php, index.docker.io/library/php).

func (Reference) Repository

func (r Reference) Repository() string

Repository is the repository name with Docker Hub shown as docker.io: "docker.io/library/php", "ghcr.io/org/app".

func (Reference) String

func (r Reference) String() string

String is the canonical form: repository, tag (if written) and digest (if written).

type Resolution

type Resolution struct {
	// Ref is the reference as given; Reference is its parsed form.
	Ref       string    `json:"ref"`
	Reference Reference `json:"-"`
	// Digest is the digest of the manifest or index the reference points at.
	Digest    string `json:"digest,omitempty"`
	MediaType string `json:"media_type,omitempty"`
	// Index is true when the reference points at an image index (manifest
	// list).
	Index bool `json:"index,omitempty"`
	// Empty is true when the reference exists but holds no images: an index
	// whose only manifests are attestations, or none at all. Docker Hub
	// publishes new tags this way before their builds finish.
	Empty bool `json:"empty,omitempty"`
	// Platforms lists every image the reference holds, in index order.
	Platforms []Platform `json:"platforms,omitempty"`
	// Offline is true when the result comes from offline rules.
	Offline bool `json:"offline,omitempty"`
	// OmittedPlatforms lists the platforms left out by a platform filter
	// (Options.Platforms, FilterPlatforms).
	OmittedPlatforms []string `json:"omitted_platforms,omitempty"`
}

Resolution is what a reference points at.

func FilterPlatforms

func FilterPlatforms(res *Resolution, platforms []string) *Resolution

FilterPlatforms returns a copy of res holding only the images whose platform matches one of platforms (all of them when platforms is empty). The others are listed in OmittedPlatforms. An offline resolution (platform unknown) is returned unchanged.

func Resolve

func Resolve(ctx context.Context, ref string, opts Options) (*Resolution, error)

Resolve resolves a reference with a new Resolver. Use a shared Resolver to benefit from caching across references.

type Resolver

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

Resolver resolves references, caching every result for its lifetime (one scan): the same reference, and the same manifest digest, are fetched once. It is safe for concurrent use.

func NewResolver

func NewResolver(opts Options) *Resolver

NewResolver returns a Resolver.

func (*Resolver) Resolve

func (r *Resolver) Resolve(ctx context.Context, s string) (*Resolution, error)

Resolve resolves a reference: by digest when it has one (a digest wins over a tag, as in docker pull), otherwise by tag.

func (*Resolver) Stats

func (r *Resolver) Stats() Stats

Stats reports the requests made so far.

func (*Resolver) Tags

func (r *Resolver) Tags(ctx context.Context, repository string) ([]string, error)

Tags lists a repository's tags (all pages), cached per Resolver.

type Stats

type Stats struct {
	// ManifestGets are GET requests for manifests: the requests Docker Hub
	// counts against pull rate limits.
	ManifestGets int `json:"manifest_gets"`
	// ManifestHeads are HEAD requests for manifests (not counted by Docker
	// Hub).
	ManifestHeads int `json:"manifest_heads"`
	// BlobGets are GET requests for blobs. The resolver only ever fetches
	// image configs, never layers.
	BlobGets int `json:"blob_gets"`
	// TagLists are tags/list requests (one per page).
	TagLists int `json:"tag_lists"`
	// Other counts everything else (token and ping requests).
	Other int `json:"other"`
	// Redirects counts requests that follow a redirect (blob CDNs).
	Redirects int `json:"redirects"`
	// Retries counts requests repeated after a 429, a 5xx or a network error.
	Retries int `json:"retries"`
	// RateLimitRemaining is the last "ratelimit-remaining" header Docker Hub
	// sent ("95;w=21600"), if any.
	RateLimitRemaining string `json:"rate_limit_remaining,omitempty"`
}

Stats counts the HTTP requests a Resolver made.

type Verdict

type Verdict string

Verdict is what a Resolution proves about CVE-2026-109618/109619.

const (
	// Vulnerable: at least one platform carries a PHP release without the fix.
	Vulnerable Verdict = "vulnerable"
	// Fixed: every platform that proves a PHP version carries the fix.
	Fixed Verdict = "fixed"
	// Unknown: PHP versions are proven but at least one cannot be judged (a
	// development or pre-release build), and none is vulnerable.
	Unknown Verdict = "unknown"
	// NoPHP: no platform's config proves a PHP version. Not a finding.
	NoPHP Verdict = "no-php-evidence"
	// NoImages: the reference exists but holds no images (an empty index).
	NoImages Verdict = "no-images"
	// Unresolved: the reference could not be resolved.
	Unresolved Verdict = "unresolved"
)

Directories

Path Synopsis
Package registrytest runs an in-memory OCI registry for tests and builds images that look like the official php image and images derived from it.
Package registrytest runs an in-memory OCI registry for tests and builds images that look like the official php image and images derived from it.

Jump to

Keyboard shortcuts

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