Documentation
¶
Overview ¶
Package update implements the v0.1.0 signed update system (owner directive §5).
Trust chain (in enforcement order — verification is FIRST, download is LAST):
- SIGNATURE: the update manifest carries an Ed25519 signature over its canonical core bytes; the public key is EMBEDDED in the binary. A manifest from any URL is worthless without a valid signature — "never trust an unsigned update simply because it comes from a familiar download URL".
- VERSION: the manifest version must be strictly newer than the running binary (semver, pre-release aware). Downgrades and same-version re-writes are refused without --force.
- PLATFORM: the manifest must name an artifact for the running GOOS/GOARCH pair (no best-effort guesses).
- CHECKSUM: the downloaded artifact must match the manifest's SHA-256 exactly, and its size must match.
- REPLACE: the payload is written to a temp file NEXT TO the target (same filesystem → rename is atomic), fsynced, mode- preserved, then renamed over the running binary; the previous binary is kept as <target>.bak for recovery. A failure at any step restores the .bak and removes temps.
The HTTP fetcher caps the body size, enforces timeouts, redacts any credential-looking URL in errors (the httpx pattern), and refuses non-HTTP(S) schemes.
Index ¶
- Constants
- func CompareVersions(a, b string) (int, error)
- func IsDirSyncWarning(err error) bool
- func IsUpToDate(err error) bool
- func LoadManifest(ctx context.Context, location string, fetcher *Fetcher) ([]byte, error)
- func ParseVersion(v string) (major, minor, patch int, pre string, err error)
- func RuntimeGOARCH() string
- func RuntimeGOOS() string
- func SetTestPublicKey(pub ed25519.PublicKey)
- func Sign(m Manifest, priv ed25519.PrivateKey) ([]byte, error)
- func TrustAnchor() ed25519.PublicKey
- type ApplyResult
- type Artifact
- type Error
- type Fetcher
- type Manifest
Constants ¶
const EmbeddedUpdatePublicKeyB64 = "hB+FoV/HjZ4AQlsaCosmdMkzX3LsyWkDwZeGNFAHlsc="
keys.go — the update trust anchor.
EmbeddedUpdatePublicKey is the base64 Ed25519 PUBLIC key that signed release manifests must verify against. It is baked into the binary on purpose: an update manifest is only as trustworthy as this key, never as the URL it was fetched from.
Key ceremony (docs/UPDATE.md §2): the project owner generates the keypair with `gseer-release keygen`, keeps the PRIVATE key offline with the release process, and replaces the constant below with the matching public half before cutting a release. The private key must NEVER live in this repository. Rotation = new keypair + new embedded anchor + a signed revocation note in the release channel.
const MaxArtifactBytes = 512 << 20
MaxArtifactBytes caps an update payload (a GSEER binary is tens of MB; 512 MiB is generous and refuses memory-bomb URLs).
Variables ¶
This section is empty.
Functions ¶
func CompareVersions ¶
CompareVersions returns -1/0/+1: a<b → -1. A pre-release (-rc1) sorts BEFORE its release. Unparseable versions are NEVER treated as newer (fail-closed comparison).
func IsDirSyncWarning ¶
IsDirSyncWarning reports whether err is the "replaced, but the directory entry could not be flushed to disk" durability warning. When it is true the binary WAS replaced — callers must not treat the update as failed or rolled back; they should surface the warning.
func IsUpToDate ¶
IsUpToDate reports whether err is the "not older" condition (which is a successful check, not a failure).
func LoadManifest ¶
LoadManifest reads manifest bytes from a path or fetches a URL.
func ParseVersion ¶
ParseVersion parses "vMAJOR.MINOR.PATCH[-PRERELEASE]" into comparable parts. Errors name the offending version.
func RuntimeGOARCH ¶
func RuntimeGOARCH() string
func RuntimeGOOS ¶
func RuntimeGOOS() string
RuntimeGOOS/RuntimeGOARCH expose the platform pair for display.
func SetTestPublicKey ¶
SetTestPublicKey swaps the trust anchor (TESTS ONLY — the CLI wires it through an internal seam so the embedded key stays the only production trust root).
func Sign ¶
func Sign(m Manifest, priv ed25519.PrivateKey) ([]byte, error)
Sign produces the signed manifest bytes from the core and a private key (the release tool's operation; exported for tests and cmd/gseer-release).
func TrustAnchor ¶
TrustAnchor returns the active public key (test override wins).
Types ¶
type ApplyResult ¶
type ApplyResult struct {
PreviousVersion string
NewVersion string
Replaced string
Backup string // "" when the replace had no prior file
Bytes int64
}
ApplyResult reports a completed replacement.
func Apply ¶
func Apply(ctx context.Context, manifestBytes []byte, pub []byte, currentVersion, targetPath string, force bool, fetcher *Fetcher) (*ApplyResult, error)
Apply runs the full chain: verify → version check → platform select → fetch → checksum → atomic replace (+ backup, + rollback on failure). currentVersion is the running binary's version string.
If the replace itself succeeded but the directory durability sync failed, Apply returns the result AND a warning error (see IsDirSyncWarning): the binary was swapped and nothing was rolled back, but the change may not survive a crash or power loss.
type Artifact ¶
type Artifact struct {
OS string `json:"os"`
Arch string `json:"arch"`
URL string `json:"url"`
SHA256 string `json:"sha256"` // hex
Size int64 `json:"size"`
}
Artifact is one platform payload inside a manifest.
func (Artifact) VerifyChecksum ¶
VerifyChecksum reports whether the artifact's recorded SHA-256 and size match the downloaded payload.
type Error ¶
Error is the update system's structured error (what → why → next). Err carries the wrapped underlying cause: Why renders it for humans while Err keeps it machine-inspectable — errors.Is / errors.As walk the live chain (e.g. MoveFileExW error → *os.LinkError → *Error) and the cause is never flattened to a string alone.
type Fetcher ¶
Fetcher downloads a URL with a hard cap and timeout. It refuses non-HTTP(S) schemes and redacts userinfo-bearing URLs in errors.
type Manifest ¶
type Manifest struct {
Version string `json:"version"`
ReleasedAt time.Time `json:"released_at"`
Artifacts []Artifact `json:"artifacts"`
NotesURL string `json:"notes_url,omitempty"`
Signature string `json:"signature,omitempty"` // base64 Ed25519 over the canonical core
}
Manifest is the signed update manifest. The SIGNATURE covers the canonical JSON of ManifestCore (the struct below minus Signature), marshaled by encoding/json (field order is declaration order → deterministic). The signed file is the Manifest with signature set; verification re-marshals the core and checks the Ed25519 signature over those exact bytes.
func Check ¶
Check runs the verification chain WITHOUT downloading: signature, version relation, and platform availability.
func ParseManifest ¶
ParseManifest decodes and structurally validates manifest bytes.
func (Manifest) CanonicalCore ¶
CanonicalCore renders the exact bytes the signature covers.
func (Manifest) SelectArtifact ¶
SelectArtifact returns the artifact for the running platform. No guessing: a missing os/arch pair is a hard error.