sign

package
v0.0.21 Latest Latest
Warning

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

Go to latest
Published: Sep 26, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package sign checks that an asset carries the signatures its entry says it does.

Recording a signature is not the same as there being one. The entry says how the asset can be verified; this runs the verification, with aqua's own verifiers, so that what aqua-registry-g2 promises is what aqua will be able to do at install time. A release that is signed for the generator and not for the installer would be the worst of both.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnverified = errors.New("the asset can't be verified the way its entry says it can")

ErrUnverified says a signature the entry carries couldn't be shown to hold, either because it doesn't or because the check couldn't be made.

Functions

func Render

func Render(asset *generate.Asset, version string)

Render fills in the templates an entry's signing configuration still holds.

The definition writes them, and the file being generated describes one version of one environment, so nothing in it should have to be worked out again later. It is done last because the pattern a signer was guessed by, and the name it was replaced with, are both written with the version in them.

func TemplateVersion

func TemplateVersion(s, version string) string

TemplateVersion puts the version back where a value holds it.

A workflow signs under the ref it ran for, so its name holds the version, and a definition pinning it as it stands would only ever match the one release. A service account signs under a name that doesn't move and is pinned as it is.

It is the definition that wants this. What a run generates describes one version and holds no templates at all.

Types

type Identity

type Identity struct {
	// SAN is the subject alternative name of the signing certificate: a workflow
	// URI for something built by GitHub Actions, an email address for a service
	// account.
	SAN string
	// Issuer is the OIDC issuer that vouched for the SAN. Without it the SAN is
	// only a string anyone could have put in a certificate of their own.
	Issuer string
	// Repository and Ref are the repository the signing run belonged to and the ref
	// it ran for, as Fulcio recorded them. They are empty for a signature made
	// somewhere other than GitHub Actions.
	//
	// They matter because a workflow is shared. suzuki-shunsuke/go-release-workflow
	// signs the releases of dozens of repositories, so a certificate naming it is a
	// certificate any of them could have obtained: asking for the workflow alone
	// accepts a signature made for somebody else's release.
	Repository string
	Ref        string
}

Identity is who signed an artifact, as cosign is asked to check it.

It is read off the signature rather than guessed at. aqua gr assumes the signer is a workflow in the package's own repository, which is right often enough to be misleading: sigstore/cosign signs with a service account, and a definition carrying that assumption fails for everyone who installs it.

func (*Identity) Opts

func (i *Identity) Opts() []string

Opts renders the identity as the cosign flags that check for it.

type Verifier

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

Verifier runs the signature verifications an entry asks for.

func New

func New(ctx context.Context, logger *slog.Logger, httpClient *http.Client) (*Verifier, error)

New creates a Verifier.

The verification tools are installed the first time a check needs one, into aqua's own root directory — the same copies aqua would use, and the same place AQUA_ROOT_DIR points at. aqua's verifiers don't install anything themselves: they work out where the tool is and run it, and putting it there is the install path's job, which this stands in for.

func (*Verifier) Check

func (v *Verifier) Check(ctx context.Context, logger *slog.Logger, pkgName, version string, asset *generate.Asset, path string) error

Check verifies every signature the asset's entry carries against the file at path, and reports whether they all held.

A signature that can't be verified stops the version rather than being dropped from the entry. The two readings of a failure -- the release stopped being signed, and the check couldn't be made right now -- are not distinguishable here, and only one of them is safe to act on: recording a signed package as unsigned is a loss that nothing later notices, while not publishing a version is undone by the next run.

It happened the other way first. cosign was rate limited while the kubernetes packages were generated, five retries inside two seconds all met the same limit, and the entries came out saying those releases carry no signature at all.

The cost is a version that stalls: an upstream that really did stop signing, or a signer that can't be read off the certificate, produces nothing until somebody changes the definition. That is the direction to fail in, and it is why the signer is read off the signature first, which settles the case this used to exist for -- a guessed identity that was never right.

The environment the asset is for is what the signature names are rendered with, not the machine this runs on: the entry for darwin/arm64 is verified with darwin/arm64's signature wherever the run happens.

Jump to

Keyboard shortcuts

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