Documentation
¶
Overview ¶
Package selfupdate lets an installed flynn replace itself with a newer one, without a shell script, a package manager, or any tool the user does not already have.
The security of an update path is not in how it downloads: it is in what it refuses to install. Everything this package fetches is treated as hostile until the signed provenance in internal/release says otherwise, and the provenance is what the download is then pinned to. A compromised mirror, a hostile proxy, a certificate authority in the wrong hands, or a GitHub outage substituting the wrong bytes all end the same way: a digest that does not match, and nothing written.
The release listing is the one input that is not signed, and it is used only to enumerate candidates, never as evidence. An attacker who controls it can hide new versions or offer old ones, so this package remembers the highest version it has ever verified and the newest it has ever been offered, and refuses to move backwards past either without being asked in as many words.
The install is the other half, and it is where update mechanisms usually break: the new binary is staged in the same directory as the one it replaces so the swap is a rename within one filesystem, the running binary's path is resolved through its symlinks so the write lands where it was aimed, an install owned by a package manager is refused rather than trampled, and the new binary is made to prove it runs before it is kept. Nothing that has not verified is ever executed.
Index ¶
Constants ¶
const ( CodeListing = "selfupdate.listing" CodeNoRelease = "selfupdate.no_release" CodeDowngrade = "selfupdate.downgrade" CodeStale = "selfupdate.stale_listing" CodeArchive = "selfupdate.archive" CodeInstall = "selfupdate.install" CodeManaged = "selfupdate.managed_install" CodePermission = "selfupdate.permission" CodeState = "selfupdate.state" CodeSmokeTest = "selfupdate.smoke_test" CodeDevBuild = "selfupdate.dev_build" )
Failure codes.
Variables ¶
This section is empty.
Functions ¶
func SweepSuperseded ¶
SweepSuperseded removes the outgoing binaries an earlier upgrade left behind on the platforms that cannot delete a running executable. It is called at startup, is best effort, and reports how many it collected. A leftover file is untidy, not unsafe: nothing executes it, and the next upgrade does not read it.
Types ¶
type Plan ¶
type Plan struct {
Current Version
Target Version
Provenance release.Provenance
Asset string
Digest string
URL string
// Path is the binary that will be replaced: the running executable with its
// symlinks resolved, which is not always the path the user typed.
Path string
// Downgrade is set when the target is older than the floor, which only a Request
// that said so out loud can produce.
Downgrade bool
// Warning carries something the operator needs to read even though the plan is
// valid, such as a listing that went backwards.
Warning string
// contains filtered or unexported fields
}
Plan is a verified, ready-to-apply upgrade. Holding one means the provenance already checked out: the signature, the identity, and the transparency-log entry. What is left is the download, which is pinned to Digest, and the install.
type Release ¶
type Release struct {
Version Version
Prerelease bool
PublishedAt time.Time
// Current marks the release this binary is running.
Current bool
}
Release is one release the listing offered. It is unverified: the tag is a candidate to go and check, not a fact.
type Request ¶
type Request struct {
// To pins an exact version. Empty means the newest release.
To string
// AllowPrerelease lets a prerelease be chosen as the newest. An explicit To always
// wins over this: asking for a version by name is asking for it.
AllowPrerelease bool
// AllowDowngrade permits installing a version older than the running one (or older
// than the highest ever verified here). It is off by default because a downgrade is
// an attack far more often than it is an intention.
AllowDowngrade bool
}
Request is what the operator asked for.
type Updater ¶
type Updater struct {
// contains filtered or unexported fields
}
Updater upgrades the running binary.
func (*Updater) Apply ¶
Apply installs a plan. It is separate from Check so that the command can show the operator exactly what verified, and what it is about to do, before it does it.
func (*Updater) Check ¶
Check verifies what the newest (or requested) release is and what installing it would mean, without installing anything and without writing to the binary's directory. It is what `flynn version check` and `flynn upgrade --check` run.
func (*Updater) List ¶
List reports the releases that exist, newest first. It verifies nothing, because there is nothing here to verify: the listing exists to answer "what should I go and check", and every answer it gives is checked before a byte of it is installed.
func (*Updater) RecordSeen ¶
RecordSeen remembers the newest release the listing has offered, so a listing that later goes backwards can be noticed. It is called after a successful listing, and a failure to write it is not a failure of the command.
type Version ¶
type Version struct {
// contains filtered or unexported fields
}
Version is a parsed release version. Only the shape flynn actually tags is accepted: "v" followed by major.minor.patch, optionally a prerelease. A version this package cannot parse is never compared, because a comparison that quietly treats an unparseable version as zero is a downgrade attack with extra steps.
func ParseVersion ¶
ParseVersion reads a version tag. It is strict on purpose.
func (Version) Compare ¶
Compare orders two versions by semantic-versioning precedence: -1 if v sorts before w, 0 if they are the same version, +1 if v sorts after w. A prerelease sorts before the release it leads to, so v0.2.0-rc.1 is older than v0.2.0, which is what makes "do not install something older than what I am running" mean the right thing.
func (Version) IsPrerelease ¶
IsPrerelease reports whether this version carries a prerelease suffix.