fix

package
v0.2.1 Latest Latest
Warning

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

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

Documentation

Overview

Package fix proposes and applies deterministic one-line fixes for image references that carry a PHP release vulnerable to CVE-2026-109618 and CVE-2026-109619.

A fix is proposed only when it is verified: the replacement reference exists in the registry, holds images (not an empty index), covers every platform the original covers, and every one of those platforms proves a PHP release with the fix. The edited file is then re-scanned in memory: the reference must resolve to exactly the replacement, every other reference the edit changes (an ARG shared by several FROMs) must verify the same way, and nothing else in the file may change. Anything short of that is a Decline with the reason.

The rules are conservative:

  • docker.io/library/php with an exact X.Y.Z tag on a branch with a fix: the same tag with the fixed release (8.3.20-fpm-alpine3.21 becomes 8.3.36-fpm-alpine3.21), if the registry lists that tag. The OS release suffix is never changed.
  • A floating tag (8.3-fpm, 8-apache, latest, fpm-alpine) moves by itself when Docker Hub publishes the fixed release; nothing to edit, unless the reference is pinned by digest, in which case the digest is replaced with the tag's current one once that is verified.
  • An exact tag pinned by digest gets both the fixed tag and its digest.
  • A bare digest (php@sha256:...) does not say which variant it is: decline.
  • Branches before 8.2 have no upstream fix: moving to a supported branch changes the PHP minor version and is left to the developer.
  • Images built on PHP (wordpress, drupal, ...) and other repositories are only bumped when pinned by digest under a tag that now verifies fixed.

The edit lands where the changing characters were written: the FROM line, the ARG default that feeds it, the Compose default or .env value, the Helm values tag line. The rest of the line, and the rest of the file, are kept byte for byte.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Apply

func Apply(root string, changes []Change) error

Apply writes changes. Every change is checked first: its file must be a regular file inside root (no symbolic links on the way), and its line must still read exactly Old. If any check fails nothing is written. Each file is then replaced atomically (a temporary file in the same directory, synced and renamed over it), keeping its permissions and every other byte.

Types

type Change

type Change struct {
	// File is the repository-relative path of the edited file.
	File string `json:"file"`
	// Line is the 1-based line edited.
	Line int `json:"line"`
	// Old is the line as it is now and New the line after the fix, both
	// without the line terminator (which Apply keeps).
	Old string `json:"old"`
	New string `json:"new"`
	// Reason explains the fix and its verification.
	Reason string `json:"reason"`
	// Before and After are the image reference before and after the fix.
	Before string `json:"before"`
	After  string `json:"after"`
	// Ref is the reference the fix is for (its File may differ from File when
	// the edit is to an ARG, a .env file, ...).
	Ref refs.Ref `json:"ref"`
	// Verified lists the platforms checked in the replacement:
	// "linux/amd64: PHP 8.3.36".
	Verified []string `json:"verified"`
	// Also lists other references the same edit changes, each verified.
	Also []string `json:"also,omitempty"`
}

Change is one verified line edit.

func Plan

func Plan(ctx context.Context, root string, ref refs.Ref, res *registry.Resolution, resolver Resolver) (*Change, error)

Plan proposes a verified fix for a vulnerable reference. res is the reference's resolution (registry.Resolver.Resolve(ref.Image)). The error is a *Decline when there is no fix to propose, or another error when the repository could not be read.

type Decline

type Decline struct {
	Code   DeclineCode `json:"code"`
	Reason string      `json:"reason"`
}

Decline is returned by Plan when no fix is proposed.

func IsDecline

func IsDecline(err error) (*Decline, bool)

IsDecline reports whether err is a Decline, and returns it.

func (*Decline) Error

func (d *Decline) Error() string

type DeclineCode

type DeclineCode string

DeclineCode classifies why no fix is proposed.

const (
	DeclineNotVulnerable      DeclineCode = "not-vulnerable"
	DeclineUnresolved         DeclineCode = "unresolved"
	DeclineOffline            DeclineCode = "offline"
	DeclineEndOfLife          DeclineCode = "end-of-life-branch"
	DeclineMixedBranches      DeclineCode = "mixed-branches"
	DeclineFloatingTag        DeclineCode = "floating-tag"
	DeclineBareDigest         DeclineCode = "bare-digest"
	DeclineDerivedImage       DeclineCode = "derived-image"
	DeclineUnsupportedTag     DeclineCode = "unsupported-tag"
	DeclineSuffixNotPublished DeclineCode = "suffix-not-published"
	DeclineNotPublished       DeclineCode = "not-published-yet"
	DeclinePlatformsMissing   DeclineCode = "platforms-missing"
	DeclineNotFixed           DeclineCode = "replacement-not-fixed"
	DeclineNotEditable        DeclineCode = "not-editable"
	DeclineMultipleLines      DeclineCode = "multiple-lines"
	DeclineSharedEdit         DeclineCode = "shared-edit"
	DeclineStale              DeclineCode = "file-changed"
	DeclineVerification       DeclineCode = "verification-failed"
	// DeclineBaseOSChanged: the replacement is built on another OS release
	// (php:8.3.20-fpm on Debian bookworm, php:8.3.36-fpm on trixie). The
	// Reason names the explicit tag that keeps the release.
	DeclineBaseOSChanged DeclineCode = "base-os-changed"
	// DeclineBaseOSUnknown: the OS release of the original or the replacement
	// cannot be determined and the tag does not name it.
	DeclineBaseOSUnknown DeclineCode = "base-os-unknown"
)

type Resolver

type Resolver interface {
	Resolve(ctx context.Context, ref string) (*registry.Resolution, error)
	Tags(ctx context.Context, repository string) ([]string, error)
}

Resolver is what Plan needs from a registry; *registry.Resolver implements it.

Jump to

Keyboard shortcuts

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