Documentation
¶
Overview ¶
Package upgrade implements self-update from GitHub releases.
Index ¶
- Constants
- Variables
- func EdgeArchiveName(commit, goos, goarch string) string
- func EdgeAssetURL(name string) string
- func EdgeManifestName(commit string) string
- func EdgeManifestV2Name(commit string) string
- func EdgeTarget(commit string) string
- func EdgeVersion(commit string) string
- func IsEdgeTarget(s string) bool
- func IsFullCommit(s string) bool
- func ParseEdgeTarget(s string) (string, error)
- func ResolveCommit(ctx context.Context, rev string) (string, error)
- func SameCommit(a, b string) bool
- func Upgrade(current string, progress func(msg string)) (string, error)
- func UpgradeWithOptions(current string, opts Options, progress func(msg string)) (string, error)
- func VersionCommit(v string) (string, bool)
- type Asset
- type CheckResult
- type EdgeBuild
- type EdgeManifest
- type EdgeStatus
- type Options
- type Release
- type Staged
Constants ¶
const ( // EdgeTag is the tag of the single prerelease every edge build is attached // to. The tag is created once, by the first publish, and never moved: the // assets carry their commits in their names, so what the tag points at is // immaterial — and a moved tag would rewrite history for anyone who // fetched it. EdgeTag = "edge" // EdgeTargetPrefix starts an upgrade target that names an edge build: // "edge:<commit>". EdgeTargetPrefix = "edge:" // EdgeManifestSchema is the newest manifest version scripts/build-edge.sh // writes and this build reads. Schema 2 added the sequence (Task 20380) and // is published as EdgeManifestV2Name; a schema-1 manifest is still read, as // a build that carries no sequence — which a device running a sequenced // build refuses as older. EdgeManifestSchema = 2 // EdgeRetainedCommits is how many commits' builds edge.yml keeps. Older // ones are pruned, so a device cannot be sent a build from months ago — // and an operator who wants that needs a release. EdgeRetainedCommits = 30 )
Variables ¶
var ErrCommitNotFound = errors.New("upgrade: no such commit on GitHub")
ErrCommitNotFound reports that GitHub has no commit by that name in the pinned repository — for the hub's own build, that the deploy built a local commit nobody pushed.
var ErrEdgeManifest = errors.New("upgrade: the edge manifest does not match")
ErrEdgeManifest reports a manifest that does not describe the build that was asked for.
var ErrEdgeNotPublished = errors.New("upgrade: no edge build is published for that commit")
ErrEdgeNotPublished reports that no edge build exists for a commit: CI has not published it yet, it failed, or the build was pruned.
var ErrEdgeTarget = version.ErrEdgeTarget
ErrEdgeTarget reports a target that is not edge:<commit>.
Functions ¶
func EdgeArchiveName ¶ added in v0.0.5
EdgeArchiveName is the asset name of commit's archive for one platform.
The release name with the commit in it. scripts/build-edge.sh renames the release script's archives to exactly this, and edge_assets_test.go fails if the two drift.
func EdgeAssetURL ¶ added in v0.0.5
EdgeAssetURL is the download URL of one edge asset, for display.
func EdgeManifestName ¶ added in v0.0.5
EdgeManifestName is the asset name of commit's schema-1 manifest.
Every edge build still publishes one (Task 20380), with no sequence in it, because it is the only manifest a device whose cloop predates sequences can read: its reader accepts exactly schema 1 under exactly this name. Such a device installs the build from it — its first sequenced build, the bootstrap the installer allows — and from then on reads EdgeManifestV2Name. Retire it once no device on the edge channel runs a build without a sequence (hub doctor's executors.edge_lag names any that do).
func EdgeManifestV2Name ¶ added in v0.0.5
EdgeManifestV2Name is the asset name of commit's schema-2 manifest, which names the build's place on main (Task 20380). This build reads it first.
func EdgeTarget ¶ added in v0.0.5
EdgeTarget formats the upgrade target naming commit's edge build.
func EdgeVersion ¶ added in v0.0.5
EdgeVersion is the version an edge build of commit reports: dev+g and the first seven digits, which is what pkg/version gives an in-checkout build and what the hub's deploy stamps today.
func IsEdgeTarget ¶ added in v0.0.5
IsEdgeTarget reports whether s names an edge build; see version.IsEdgeTarget.
func IsFullCommit ¶ added in v0.0.5
IsFullCommit reports whether s is a full 40-digit commit id.
func ParseEdgeTarget ¶ added in v0.0.5
ParseEdgeTarget returns the commit an "edge:<commit>" target names.
func ResolveCommit ¶ added in v0.0.5
ResolveCommit expands a commit prefix to the full id through the GitHub API, or returns ErrCommitNotFound.
func SameCommit ¶ added in v0.0.5
SameCommit reports whether two versions or commits name the same commit; see version.SameCommit.
func Upgrade ¶
Upgrade downloads and installs the latest release, replacing the running binary. It returns the new version tag on success.
It verifies provenance; UpgradeWithOptions is the form that can be told not to.
func UpgradeWithOptions ¶ added in v0.0.2
UpgradeWithOptions is Upgrade with explicit control over verification.
func VersionCommit ¶ added in v0.0.5
VersionCommit returns the commit prefix a dev build's version names; see version.CommitOf.
Types ¶
type Asset ¶
type Asset struct {
Name string `json:"name"`
BrowserDownloadURL string `json:"browser_download_url"`
Size int64 `json:"size"`
}
Asset is a single file attached to a GitHub release.
type CheckResult ¶
CheckResult is the result of a version check.
func Check ¶
func Check(current string) (*CheckResult, error)
Check compares current against the latest GitHub release tag and returns a CheckResult describing whether an update is available.
type EdgeBuild ¶ added in v0.0.5
type EdgeBuild struct {
// Version is the build that was asked about, e.g. "dev+g8b418e2".
Version string
// Short is the commit prefix Version names; Commit the full id, once
// GitHub has resolved it.
Short, Commit string
Status EdgeStatus
// Manifest is the published build's manifest when Status is
// EdgePublished. Read, not verified: see FetchEdgeManifest.
Manifest EdgeManifest
// RunURL is the workflow run the reason refers to, when there is one.
RunURL string
// Err is the failure behind EdgeUnknown.
Err error
}
EdgeBuild is what is known about the edge build of one build version.
func ResolveEdgeBuild ¶ added in v0.0.5
ResolveEdgeBuild finds out whether an edge build of version exists, and if not, why. commit is the full id when the caller already knows it ("" to resolve it from version). It never returns an error: an unanswerable question is EdgeUnknown, with Err set.
type EdgeManifest ¶ added in v0.0.5
type EdgeManifest struct {
// Schema is EdgeManifestSchema.
Schema int `json:"schema"`
// Commit is the full commit id that was built.
Commit string `json:"commit"`
// Version is what the binaries report: dev+g<short commit>, the stamp the
// hub's own deploy gives the same commit.
Version string `json:"version"`
// Protocol is the newest executor protocol the binaries speak, read from
// the built binary itself (`cloop version --json`). The hub offers a
// device this build only if it does not lower the device's protocol.
Protocol int `json:"protocol"`
// Sequence is the commit's first-parent position on main (schema 2), the
// same number stamped into the binaries; zero in a schema-1 manifest,
// whose builds carry none. A device refuses a build whose sequence is
// lower than its own, and the hub never offers one.
Sequence int `json:"sequence,omitempty"`
// Archives maps each archive's asset name to its SHA-256.
Archives map[string]string `json:"archives"`
// BuiltAt and Run say when and by which workflow run, for a human.
BuiltAt string `json:"built_at,omitempty"`
Run string `json:"run,omitempty"`
}
EdgeManifest describes one commit's edge build. edge.yml writes it, signs it, and publishes it beside the archives.
func FetchEdgeManifest ¶ added in v0.0.5
func FetchEdgeManifest(ctx context.Context, commit string) (EdgeManifest, error)
FetchEdgeManifest downloads commit's manifest WITHOUT verifying its signature, for the hub's advice: whether the build exists and which protocol it claims. The hub decides only what to offer with it; the device that installs the build verifies everything itself and refuses a lower protocol on its own. commit must be the full id.
func (EdgeManifest) Validate ¶ added in v0.0.5
func (m EdgeManifest) Validate(commit string) error
Validate checks that m describes commit's edge build. commit must be the full 40-digit id.
type EdgeStatus ¶ added in v0.0.5
type EdgeStatus string
EdgeStatus classifies what is known about one commit's edge build.
const ( // EdgePublished: the manifest is there. EdgePublished EdgeStatus = "published" // EdgeNoCommit: the build names no commit — a release, or bare "dev". EdgeNoCommit EdgeStatus = "no_commit" // EdgeDirty: the build was made from a tree with uncommitted changes. EdgeDirty EdgeStatus = "dirty" // EdgeUnpushed: GitHub has no such commit. EdgeUnpushed EdgeStatus = "unpushed" // EdgeNoCI: no CI run on main exists for the commit. EdgeNoCI EdgeStatus = "no_ci" // EdgeCIRunning: CI is queued or running on it. EdgeCIRunning EdgeStatus = "ci_running" // EdgeCIFailed: CI finished on it without succeeding. EdgeCIFailed EdgeStatus = "ci_failed" // EdgePublishing: CI passed and the edge workflow has not finished. EdgePublishing EdgeStatus = "publishing" // EdgePublishFailed: the edge workflow failed for it. EdgePublishFailed EdgeStatus = "publish_failed" // EdgePruned: it was published and has been pruned since. EdgePruned EdgeStatus = "pruned" // EdgeUnknown: GitHub could not be asked. EdgeUnknown EdgeStatus = "unknown" )
type Options ¶ added in v0.0.2
type Options struct {
// SkipVerify installs without proving the archive's provenance.
//
// It exists for air-gapped mirrors that cannot reach Sigstore, and for
// nothing else. It does not disable the checksum: that still runs, and
// still proves only that the download arrived intact — checksums.txt is
// served from the same release as the archive, so an attacker who can
// replace one replaces the other.
SkipVerify bool
// Verifier overrides the provenance verifier. Tests set it. An edge build
// is verified with Verifier.ForChannel(provenance.ChannelEdge), so the
// release identity configured here never vouches for one.
Verifier *provenance.Verifier
// EdgeBaseURL overrides where edge assets are downloaded from, for tests
// and for a site that mirrors the edge release. Every asset is still
// verified against the edge identity, so a mirror can withhold builds but
// not substitute them. Set only in-process: nothing that crosses the wire
// reaches Options (pkg/executor/remote/upgradeproto.go).
EdgeBaseURL string
}
Options controls how an upgrade verifies what it is about to install.
The zero value verifies, deliberately: a security check whose default depends on a caller remembering to enable it is one that will eventually be forgotten at some call site nobody is looking at.
type Release ¶
type Release struct {
TagName string `json:"tag_name"`
Name string `json:"name"`
Assets []Asset `json:"assets"`
}
Release represents a GitHub release response (subset of fields used).
func FetchLatestRelease ¶
FetchLatestRelease queries the GitHub releases API for the latest release.
func FetchLatestReleaseContext ¶ added in v0.0.5
FetchLatestReleaseContext is FetchLatestRelease bounded by ctx, for a caller answering a request — the hub resolving "latest" before it asks a device to upgrade — that must not wait out the client's own 30-second timeout.
func FetchRelease ¶ added in v0.0.3
FetchRelease queries the GitHub releases API for one release by tag.
Separate from FetchLatestRelease because a fleet upgrade is usually *to a named version* rather than to whatever is newest: an operator rolling a hundred devices forward wants them to land on the same build, and "latest" evaluated once per device is not that — a release published midway through the rollout would split the fleet across two versions.
type Staged ¶ added in v0.0.3
type Staged struct {
// Tag is the release this came from, resolved — so a caller that asked
// for "latest" learns what latest meant.
Tag string
// BinaryPath is the extracted cloop executable.
BinaryPath string
// AssetName is the release archive the binary came out of.
AssetName string
// ProvenanceVerified records that the archive's signature was checked
// against cloop's pinned identity for its channel. False only when the
// caller passed Options.SkipVerify to StageRelease.
ProvenanceVerified bool
// Channel is the channel the build came from, and so the identity it was
// verified against.
Channel provenance.Channel
// Version is what the staged binary must report when it is run, when the
// channel says so: an edge build's signed manifest names it, and the
// installer refuses a binary that disagrees (Task 20376). Empty for a
// release, which is bound by its tag's signature alone.
Version string
// Protocol is the executor protocol an edge build's manifest claims; 0
// for a release. The installer reads the real one from the binary.
Protocol int
// Commit is the full commit an edge build was made from.
Commit string
// Sequence is the place on main an edge build's signed manifest names
// (Task 20380), zero for a schema-1 manifest and for a release. The
// installer requires the binary to report it, and orders the install by
// the binary's own stamp.
Sequence int
}
Staged describes a release that has been fetched, verified and written to disk, but not installed.
func StageEdge ¶ added in v0.0.5
StageEdge downloads the edge build target names ("edge:<commit>"), proves it was signed by edge.yml on main and built from that commit, and extracts the binary into destDir. Nothing is installed.
A short commit is resolved to the full id through the GitHub API first. The returned Staged carries the version the binary must report (pass it to the installer as ExpectVersion) and the protocol the manifest claims.
There is no unverified mode: Options.SkipVerify is refused here. An air-gapped site has no use for builds of main, and the signature is the channel's whole trust root.
func StageRelease ¶ added in v0.0.3
StageRelease downloads the release for tag, proves it came from cloop's release workflow, and extracts the binary into destDir.
It returns before anything is installed. The caller is responsible for destDir's lifetime; a staged binary left behind is an executable nobody is watching, so callers that stage into a temporary directory should remove it.