match

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jul 4, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package match holds the Rewriter seam (Locate + Render -> edit-set) and its dispatch table: the smart rewriter plus the action-pin rewriter for SHA-pinned uses: lines. Pure.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ActionPin

type ActionPin struct{}

ActionPin rewrites a GitHub Actions secure pin, where one resolved candidate drives two spans on the same line:

uses: owner/repo@<40-hex-sha>   # v1.2.3

the commit SHA (from Candidate.Commit) and the trailing version comment (from Candidate.Version, restyled). The version comment is the current-version anchor - a SHA cannot anchor a semver constraint - so when it is present it fixes the version and its style. A pin with no comment is still a valid target: it has no current version to anchor a relative constraint, so run resolves it per the directive (latest unless a range constrains it) and Render appends a fresh comment, documenting the version the SHA now points at. Render relies on the provider storing the peeled target commit, not an annotated-tag object SHA.

func NewActionPin

func NewActionPin() ActionPin

NewActionPin returns the action-pin rewriter (stateless value, like Smart).

func (ActionPin) Locate

func (ActionPin) Locate(line string) (Location, error)

Locate parses the action reference, requiring a full 40-hex SHA after @. A version-shaped token in the trailing comment, when present, anchors the current version and its style. A pin with no comment at all is located with no current version, so run resolves it fresh and Render appends the comment. It errors for each way the line fails to be a SHA pin (no reference, not SHA-pinned, short SHA), and when a comment is present but carries no version - clover will not guess whether a human note like "# pinned" was meant to be a version.

type ActionTrack

type ActionTrack struct{}

ActionTrack rewrites a GitHub Actions secure pin whose trailing comment names a floating branch rather than a version:

uses: owner/repo@<40-hex-sha>   # main

Like ActionPin it drives two spans from one candidate - the commit SHA (from Candidate.Commit) and the comment (from Candidate.Version) - but it takes the comment literally instead of requiring a version-shaped token, so a branch name anchors the line and Semver stays nil.

func NewActionTrack

func NewActionTrack() ActionTrack

NewActionTrack returns the action-track rewriter (stateless value, like Smart).

func (ActionTrack) Locate

func (ActionTrack) Locate(line string) (Location, error)

Locate finds the @<sha> commit and the # comment, reusing the SHA parsing the action-pin rewriter uses and taking the comment verbatim so a branch name like "main" is captured rather than rejected.

type Context

type Context struct {
	Path     string
	Line     string
	Provider string
	Value    string
}

Context is what the dispatch table routes on: the file, the target line, the marker's provider, and the follower value kind.

type DockerPin

type DockerPin struct{}

DockerPin rewrites a digest-pinned image reference, where one resolved candidate drives two spans on the same line:

FROM repo:1.27@sha256:<64-hex>

the tag (restyled from Candidate.Version) and the digest (from Candidate.Digest). The tag is the current-version anchor, so a pin without one is an error; it acts only on already-pinned lines, never adding a digest.

func NewDockerPin

func NewDockerPin() DockerPin

NewDockerPin returns the docker-pin rewriter (stateless value, like Smart).

func (DockerPin) Locate

func (DockerPin) Locate(line string) (Location, error)

Locate finds the version tag and the @sha256 digest, erroring specifically for each way a line can fail to be a digest pin (not pinned, short or non-sha256 digest, no tag, non-version tag) so lint can explain it.

type DockerTag

type DockerTag struct{}

DockerTag rewrites a tag-only image reference, where the version is the tag of an image ref:

FROM localhost:5000/team/api:2.0.1
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/team/api:2.0.1

Unlike the smart rewriter it does not scan the whole line - a registry :port, an ECR account id, or a region like us-east-1 are all version-shaped and would make the line ambiguous. Instead it anchors on the image reference, taking the tag as the last colon-segment after the last slash, so only the tag is read. The located tag re-styles exactly like a smart token, so Locate returns a smartLocated.

func NewDockerTag

func NewDockerTag() DockerTag

NewDockerTag returns the docker tag-only rewriter (stateless value, like Smart).

func (DockerTag) Locate

func (DockerTag) Locate(line string) (Location, error)

Locate finds the version token in the image tag, ignoring the registry host, port, and path so they are never mistaken for the version.

type DockerTrack

type DockerTrack struct{}

DockerTrack rewrites a digest-pinned image reference whose tag is a floating ref (latest, nonroot, edge) rather than a version:

FROM repo:latest@sha256:<64-hex>

Like DockerPin it drives two spans from one candidate - the tag (from Candidate.Version) and the digest (from Candidate.Digest) - but it takes the tag literally instead of requiring a version-shaped token, so a floating tag anchors the line and Semver stays nil. It acts only on already digest-pinned lines, never adding a digest.

func NewDockerTrack

func NewDockerTrack() DockerTrack

NewDockerTrack returns the docker-track rewriter (stateless value, like Smart).

func (DockerTrack) Locate

func (DockerTrack) Locate(line string) (Location, error)

Locate finds the literal tag and the @sha256 digest, reusing the digest parsing the docker-pin rewriter uses and taking the tag verbatim so a non-version tag like "latest" is captured rather than rejected.

type FindReplace

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

FindReplace is the explicit find/replace rewriter. find locates the region to rewrite: a glob with <placeholders> (each a capturing group of its shape), or a /regex/ (strict, no placeholders; group 1 is the value). replace is optional: without it each captured value is substituted in place, preserving the rest; with it the whole matched region is re-rendered from the template. A token renders its resolved value when clover computes one, else the text find captured, so a match-only <hex> is preserved.

func NewFindReplace

func NewFindReplace(find, replace string) (FindReplace, error)

NewFindReplace compiles a find/replace pair through the shared pattern grammar: a /regex/ find is strict (nil tokens), any other find is a glob with placeholders.

func (FindReplace) Locate

func (fr FindReplace) Locate(line string) (Location, error)

Locate matches find against the line: the whole match is the span to rewrite, and the value anchoring selection is the first version-shaped capture (glob) or capture group 1 (regex), falling back to the whole match.

type Guarded

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

Guarded is a rewriter wrapper that first requires a find/replace-style guard to match the line, then delegates the actual location and rendering to another rewriter. It is useful when a sidecar's jq locator selects the line, but a find pattern should still fail loud if the line has drifted to another source.

func NewGuarded

func NewGuarded(find string, inner Rewriter) (Guarded, error)

NewGuarded returns a rewriter guarded by find. The guard is match-only; render behavior comes entirely from inner.

func (Guarded) Locate

func (g Guarded) Locate(line string) (Location, error)

Locate verifies the guard matches before delegating to the inner rewriter.

type Hash

type Hash struct{}

Hash rewrites a follower's commit or sha256 line by swapping the existing hex token for the resolved one. It locates by shape (a 40- or 64-char hex run), so it needs no anchor; the resolved value the pipeline passes is spliced in as-is.

func NewHash

func NewHash() Hash

NewHash returns the hash rewriter (stateless value, like Smart).

func (Hash) Locate

func (Hash) Locate(line string) (Location, error)

Locate finds the single commit- or sha256-length hex run on the line, erroring when there is none or more than one (the ambiguity it fails loud on).

type Inference

type Inference struct {
	Provider   string
	Registry   string
	Repository string
}

Inference is what auto-detection resolved for a `provider=auto` marker from its target line: the real provider plus any provider parameters readable from the line. Empty parameter fields mean the line did not carry that detail.

func Infer

func Infer(path, line string) (Inference, bool)

Infer resolves the provider for an `auto` marker from its file path and target line, reusing the dispatch routes: the first route whose path and line match (ignoring its provider guard, which is the answer) names the provider. It also reads the provider's parameters from the line - the repository from a GitHub Actions pin, the registry and repository from a container image reference - so a bare `provider=auto` needs no further keys. It returns ok=false when nothing matches, leaving the marker for the caller to reject.

type Location

type Location interface {
	// Current is the version text currently on the line, recorded as the old value.
	Current() string
	// Semver is the parsed core of the current version, nil when unparseable. It
	// anchors selection.
	Semver() *version.Version
	// NeedsDigest reports whether rendering will rewrite a content digest, so the
	// pipeline knows to resolve one for the candidate.
	NeedsDigest() bool
	// Render rewrites the line for the resolved candidate, returning the new line
	// and whether it changed. It errors rather than reporting a silent no-op when
	// the candidate lacks a field it needs or the located span no longer fits.
	Render(line string, candidate model.Candidate) (string, bool, error)
}

Location is what a Rewriter found on a target line: the common anchors the pipeline reads (Current, Semver, NeedsDigest) plus the ability to render itself for a resolved candidate. Each rewriter returns its own implementation, so the renderer-specific state (spans, captures) stays private to the rewriter that produced it rather than piling into a shared struct.

type Renderer

type Renderer interface {
	Rendered(candidate model.Candidate) string
}

Renderer is the optional capability of a Location that can report the exact version text it will write for a candidate, which may differ from the candidate's raw version once restyled (a stripped variant, a re-precisioned or re-prefixed core). The pipeline resolves a digest for this text rather than the raw candidate, so a pinned image's digest always describes the tag written.

type Rewriter

type Rewriter interface {
	// Locate extracts the version currently on the line, erroring when the
	// rewriter cannot act on it (no target, ambiguous, or malformed).
	Locate(line string) (Location, error)
}

Rewriter locates the version a target line carries. Implementations range from the shape-based Smart rewriter to format-specific ones. Locate is offline and pure, so lint runs it to validate a marker without resolving anything; the Location it returns renders the line once a candidate is resolved.

func For

func For(ctx Context) Rewriter

For selects the rewriter for a target line, walking the routes first-match-wins and falling back to the smart rewriter.

type SecurePin

type SecurePin interface {
	Pinned() string
}

SecurePin is the optional capability of a Location whose target pins a secure value beside the version - an action commit SHA or an image content digest. Pinned reports the value currently on the line, so a run can cross-check it against the value the resolved tag reports and catch a committed pin that no longer matches upstream.

type Smart

type Smart struct{}

Smart is the default rewriter. It locates a version by shape - no provider anchor is needed for the v0.1.0 providers, which are weakly anchored - and renders a new version that preserves the original's style: its v-prefix, component precision, and variant suffix, trimming a prerelease only when the original had none.

func NewSmart

func NewSmart() Smart

NewSmart returns the default smart rewriter. It takes no arguments today but is the seam for future options, and keeps construction uniform with the rest of the codebase. The value is returned directly: Smart is stateless, so a pointer would only add an allocation and indirection.

func (Smart) Locate

func (Smart) Locate(line string) (Location, error)

Locate finds the single version token on line. It errors when the line has no version-shaped token, or more than one (the ambiguity the design fails loud on rather than guessing). Locate does no I/O, so lint runs it to validate a marker without resolving anything.

type Span

type Span struct {
	Start int
	End   int
}

Span is a byte range [Start, End) within a line.

type Token

type Token struct {
	Span       Span
	Prefix     string // "v", or "" when bare
	Core       string // numeric core, 1-3 dotted components, e.g. "1.27"
	Prerelease string // prerelease identifiers without the leading -, or ""
	Suffix     string // recognised variant suffix without the leading -, or ""
	Build      string // build metadata without the leading +, or ""
}

Token is a version reference located in a line: its byte span plus the parts it decomposes into. Keeping the numeric Core separate from the Prefix, Prerelease, variant Suffix, and Build means the rewriter can normalise on the core and re-apply each decoration exactly once when rendering a new version.

func Find

func Find(line string) []Token

Find returns every version-shaped token in line, in order. It is the whole- line scan the smart rewriter uses where a provider offers no anchor; matching is deliberately strict (see scanToken) to keep false positives rare.

Jump to

Keyboard shortcuts

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