selfupdate

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package selfupdate replaces this binary with a published release.

It is the same transaction `install.sh` and `install.ps1` perform, and that is deliberate rather than incidental: a second, subtly different way to install signpost would be a second place for the verification rules to drift, and the verification is the whole reason this is a package rather than three lines in the command. What the installers do, and what this does, in the same order:

  • Resolve the latest tag from the redirect on /releases/latest rather than from the API. The API is rate-limited per IP and unauthenticated CI shares an IP with everyone else on the runner; the redirect is not, and it needs no token.
  • Download the platform's archive from the release, and download checksums.txt.
  • Refuse to proceed if the release publishes no checksums.txt, or if the archive is not listed in it, or if the digest does not match. Three separate refusals, none of them a warning: an unverified binary is the one outcome worse than not updating.
  • Write beside the target and rename over it, so a failure leaves the old binary intact and a running process is never written into.

Nothing here is a git operation and nothing reads the repository: an update is about the tool, not about the tree it analyses. The package therefore has no dependency on discover, graph, or okf, and can be exercised end to end against an httptest server.

Index

Constants

View Source
const DefaultTimeout = 2 * time.Minute

DefaultTimeout bounds the whole exchange: two redirects, two downloads.

One bound for all of it rather than per request, because the failure this guards against is a stalled transfer and a per-request timeout resets on every byte. Ten megabytes over a slow link is the legitimate worst case and takes well under this.

View Source
const Repo = "3rg0n/signpost"

Repo is the repository releases are published from.

Hard-coded rather than configurable. An update fetches an executable and runs it as the user, so the source is a trust boundary: a flag or an environment variable pointing it elsewhere would turn one mistyped hostname, or one poisoned CI environment, into arbitrary code execution wearing this tool's name. Tests reach the seam through Client.BaseURL, which is unexported behaviour of a struct field rather than an option a user can set.

Variables

This section is empty.

Functions

func ReleasesURL

func ReleasesURL() string

ReleasesURL is where a human goes to read what changed.

Types

type Client

type Client struct {
	// HTTPClient is the transport. Nil means one with DefaultTimeout and redirects
	// followed, matching what a browser or curl would do for these URLs.
	HTTPClient *http.Client
	// BaseURL is where releases live. Empty means github.com, which is the only value
	// a released binary ever uses; a test points it at an httptest server.
	BaseURL string
}

Client fetches releases. The zero value works.

func (*Client) Apply

func (c *Client) Apply(o Options) (Result, error)

Apply installs a release over the target binary.

func (*Client) Download

func (c *Client) Download(r Release) (archive []byte, digest string, err error)

Download fetches a release's archive and returns it, verified.

Verified before it is returned rather than after, so no caller can be written that unpacks first and checks second. The three refusals are separate errors because they mean different things to whoever reads them: a release without checksums is a broken release, an asset missing from checksums is a partial publish, and a mismatch is either a corrupted transfer or an archive that is not the one that was published.

func (*Client) Latest

func (c *Client) Latest() (Release, error)

Latest resolves the most recent published release for this platform.

type Options

type Options struct {
	// Version is the tag to install. Empty means the latest release.
	Version string
	// Path is the binary to replace. Empty means the running executable.
	Path string
	// Current is the version this binary reports, used to skip a no-op write.
	Current string
	// DryRun resolves and verifies but writes nothing, so somebody can see what an
	// update would do before letting it happen to a tool their CI depends on.
	DryRun bool
	// Force writes even when the versions already match — the repair case, for a
	// binary that is the right version and the wrong bytes.
	Force bool
}

Options configure Apply.

type Release

type Release struct {
	// Version is the tag, as published: "v0.2.0".
	Version string
	// Asset is the archive's filename, which is also its key in checksums.txt.
	Asset string
	// URL is where Asset was, or would be, downloaded from.
	URL string
}

Release is a published release and the asset for the running platform.

type Result

type Result struct {
	// From and To are the version replaced and the version installed. Equal when
	// nothing was written.
	From, To string
	// Path is the binary that was replaced, or would have been.
	Path string
	// Replaced is false when the binary was already at the requested version, or when
	// DryRun asked for no write.
	Replaced bool
	// SHA256 is the verified digest of the archive, hex-encoded. Reported so the
	// command can print what it checked rather than only that it checked.
	SHA256 string
}

Result is what an update did.

Jump to

Keyboard shortcuts

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