binmgr

package
v0.0.0-...-c495aaa Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package binmgr is the shared managed-external-binary mechanism for the dhnt ecosystem: resolve a (name, version, platform) tool spec → download from its own release → sha256-verify → cache → return the executable path. Both bashy (the user-facing "OS of binaries" host) and outpost (the lean mesh supervisor) call it IN-PROCESS — coreutils is the shared layer both already import — to run wrapped tools (loom/Gitea, Zot, SeaweedFS, Kopia, …) without compiling those heavy binaries into either. Each tool ships per-platform binaries + sha256 from its own CI; binmgr is the one trust/verify/version path for all of them.

It complements external/podman's Resolve (which locates an already-present binary): binmgr is the download half. See docs/external-binary-builtins.md.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BinaryName

func BinaryName(name string) string

BinaryName is the on-disk basename Ensure caches a tool under (adds .exe on Windows). Exported so callers can build/inspect cache paths.

func CacheDir

func CacheDir() (string, error)

CacheDir is the root for downloaded binaries. Override via $BASHY_BIN_CACHE; otherwise <UserCacheDir>/bashy/bin.

func CachedBinary

func CachedBinary(name string) string

CachedBinary returns an already-cached tool binary from a prior Ensure (newest version wins), or "" when none is cached. A hot-path caller uses it to skip version resolution + network entirely: Ensure lays tools out at <CacheDir>/<name>/<version>/<binaryName>. Both raw-binary and Tree entrypoints whose entrypoint basename equals the tool name are found.

func Ensure

func Ensure(ctx context.Context, t Tool) (string, error)

Ensure resolves the tool's asset for the current platform, downloading + sha256-verifying + caching it if not already present, and returns the path to the executable. Idempotent: a cache hit returns immediately with no network.

func Platform

func Platform() string

Platform returns the current "goos/goarch" key.

func ProvisionManaged

func ProvisionManaged(ctx context.Context, spec ManagedSpec) (string, error)

ProvisionManaged resolves spec to a cached executable path. Resolution order — the single shared pipeline:

  1. cache hit at DestDir/<name> → return (no network)
  2. fetch <name>-<goos>-<goarch>.gz from ReleaseRepo → gunzip → DestDir/<name>
  3. Build from source (if provided) → DestDir/<name>
  4. error

Deps are provisioned first (into the same dir). Standalone throughout — nothing here needs a paired host; a caller layers mesh delegation ON TOP if it wants.

Types

type Asset

type Asset struct {
	// URL is the download URL (a raw binary, or a .tar.gz/.tgz/.zip archive).
	URL string `json:"url"`
	// SHA256 is the expected hex digest of the downloaded file (preferred).
	SHA256 string `json:"sha256"`
	// SHA512 is the expected hex sha512 digest — the strongest supported check,
	// used when SHA256 is empty. The integrity check some vendors publish (e.g.
	// Apache dist ships only .sha512).
	SHA512 string `json:"sha512,omitempty"`
	// MD5 is the expected hex md5 digest — a weak fallback for tools that publish
	// only .md5 sidecars (e.g. SeaweedFS). Used when SHA256/SHA512 are empty.
	// At least one of SHA256/SHA512/MD5 MUST be set: an asset with none is
	// REFUSED (fail-closed), never installed unverified.
	MD5 string `json:"md5,omitempty"`
	// Binary is the path to the executable WITHIN an archive (e.g.
	// "gitea/gitea"); empty means the download is itself the raw binary.
	Binary string `json:"binary,omitempty"`
	// Tree requests whole-archive ("recursive") extraction instead of pulling a
	// single Binary member: the entire .tar.gz/.zip tree is unpacked into the
	// tool's cache dir, preserving modes and symlinks. Use it for tools that need
	// their full layout to run (a Go toolchain's bin/+pkg/+src/, an SDK, …).
	Tree bool `json:"tree,omitempty"`
	// Entrypoint is the executable's slash-separated path within the extracted
	// tree (e.g. "go/bin/go"); required when Tree is set, ignored otherwise.
	Entrypoint string `json:"entrypoint,omitempty"`
}

Asset is one platform's download for a tool.

type GitHubSpec

type GitHubSpec struct {
	// Name is the logical tool name — the cache key and the cached binary name.
	Name string
	// Repo is "owner/repo" (e.g. "go-gitea/gitea").
	Repo string
	// Version is a release tag (e.g. "v1.26.1"); "" or "latest" = latest release.
	Version string
	// Member is the executable's path within a .tar.gz/.zip asset; "" means the
	// matched asset is the raw binary (Gitea, Zot).
	Member string
	// Tree requests whole-archive extraction (Asset.Tree) instead of pulling a
	// single Member: the matched .tar.gz/.zip is unpacked in full, for tools that
	// need their sibling layout to run (e.g. ollama + its ggml runner libs).
	// Requires Entrypoint; Member is ignored.
	Tree bool
	// Entrypoint is the executable's slash path within the extracted tree (e.g.
	// "ollama"); required when Tree is set.
	Entrypoint string
	// AssetMatch overrides the default platform matcher for tools whose asset
	// names don't carry the standard os/arch tokens.
	AssetMatch func(assetName, goos, goarch string) bool
}

GitHubSpec locates a tool's binary on GitHub releases: given a repo + version, ResolveGitHub picks the asset for the current platform and resolves its sha256 (a per-asset .sha256 sidecar, or a checksums file in the release). Reusable for every tool that ships GitHub releases (Gitea, Zot, SeaweedFS, Kopia, …).

Note on trust: a checksum resolved from the release is a transit-integrity check, not a defense against a tampered release — the sidecar lives next to the artifact and moves with it. For real supply-chain integrity, pin the digest in pins.go, where the trust root is this repo's reviewed history rather than the downloaded release. See Ensure and pins.go.

type ManagedSpec

type ManagedSpec struct {
	// Name is the cache key and the resulting executable's basename.
	Name string
	// DestDir is where the executable is installed (a stable path a fast cache
	// check can find without network). "" = binmgr's CacheDir().
	DestDir string
	// ReleaseRepo is "owner/repo" whose latest release carries a prebuilt blob
	// named <name>-<goos>-<goarch>.gz (built from permissive source in CI). "" =
	// no prebuilt step.
	ReleaseRepo string
	// Deps are provisioned first, into the same DestDir (e.g. podman → vfkit,
	// gvproxy on macOS). Best-effort.
	Deps []ManagedSpec
	// Build builds the component from source into dest when no prebuilt blob is
	// available (the licensing-policy fallback: permissive source + toolchain).
	// nil = fetch-only.
	Build func(ctx context.Context, dest string) error
	// Log receives progress lines. Optional.
	Log func(string)
}

ManagedSpec describes a managed component (an engine or tool) and how to make it available. ProvisionManaged resolves it with ONE process shared by every consumer — bashy, outpost, and Tessaro apps — so podman/ollama/<new X> are provisioned identically everywhere, and always **standalone**: a paired host is never assumed.

type Process

type Process struct {
	Path string
	Cmd  *exec.Cmd
}

Process is a launched managed binary.

func Launch

func Launch(ctx context.Context, path string, spec RunSpec) (*Process, error)

Launch runs an already-resolved binary path (the half of Start after Ensure). Useful when the caller resolved the path itself, or in tests.

func Start

func Start(ctx context.Context, spec RunSpec) (*Process, error)

Start ensures the binary is present (download/verify/cache), launches it, and — if HealthURL is set — blocks until it answers or HealthWait elapses (killing it on timeout). Returns immediately once ready (or once launched, if no probe).

func (*Process) Pid

func (p *Process) Pid() int

Pid returns the running process id, or 0 if not started.

func (*Process) Stop

func (p *Process) Stop(timeout time.Duration) error

Stop asks the process to terminate (SIGTERM on unix, Kill on Windows), then hard-kills it if it hasn't exited within timeout. Idempotent.

func (*Process) Wait

func (p *Process) Wait() error

Wait blocks until the process exits.

type RunSpec

type RunSpec struct {
	Tool       Tool          // the binary to Ensure + run
	Args       []string      // command-line args
	Env        []string      // extra env, appended to the parent environment
	Dir        string        // working directory ("" inherits)
	Stdout     io.Writer     // default os.Stdout
	Stderr     io.Writer     // default os.Stderr
	HealthURL  string        // optional: GET until it answers (< 500) to consider ready
	HealthWait time.Duration // max wait for readiness (default 30s)
}

RunSpec describes how to launch a managed binary. The caller supplies the args (e.g. binding the tool to a loopback port) and an optional readiness probe; the supervisor handles ensure → launch → wait-ready → stop. Shared by `bashy loom` (foreground) and the outpost wrap-harness builtin (background daemon).

type Tool

type Tool struct {
	Name    string           `json:"name"`
	Version string           `json:"version"`
	Assets  map[string]Asset `json:"assets"`
}

Tool is a managed external binary: a logical name, a version (the cache key), and per-platform assets keyed by "goos/goarch" (e.g. "linux/amd64").

func ResolveGitHub

func ResolveGitHub(ctx context.Context, spec GitHubSpec) (Tool, error)

ResolveGitHub turns a GitHubSpec into a Tool for the current platform, ready to pass to Ensure/Start.

func ResolveURL

func ResolveURL(ctx context.Context, spec URLSpec) (Tool, error)

ResolveURL turns a URLSpec into a Tool for the current platform, ready for Ensure/Start. It fetches and parses the checksum so the cache stays verified.

type URLSpec

type URLSpec struct {
	// Name is the logical tool name — the cache key and cached binary name.
	Name string
	// Version is required (no "latest" auto-resolution — there's no API to query).
	Version string
	// URLTemplate is the download URL with {version}/{goos}/{goarch}/{ext} tokens.
	URLTemplate string
	// ChecksumURLTemplate (optional) is the sha256 sidecar URL template; when
	// empty, ResolveURL tries "<download-url>.sha256". The body may be a bare
	// digest or a "<digest>  <file>" line — the first 64-hex run is taken.
	ChecksumURLTemplate string
	// Member is the executable's path within a .tar.gz/.zip; "" = raw binary.
	Member string
	// ArchAlias maps runtime.GOARCH into the vendor's token (e.g. amd64→x86_64).
	ArchAlias func(goarch string) string
	// OSAlias maps runtime.GOOS into the vendor's token.
	OSAlias func(goos string) string
}

URLSpec locates a tool's binary at a templated download URL — for vendors that publish releases OUTSIDE GitHub (e.g. act_runner on dl.gitea.com). It is the non-GitHub sibling of GitHubSpec: same trust path (download → sha256-verify → cache via Ensure), just a different way to resolve the per-platform asset URL.

URLTemplate (and the optional ChecksumURLTemplate) expand these tokens:

{version}  the resolved version (leading "v" preserved as given)
{goos}     runtime.GOOS, after OSAlias if set
{goarch}   runtime.GOARCH, after ArchAlias if set
{ext}      ".exe" on windows, "" elsewhere

Example (act_runner):

URLTemplate: "https://dl.gitea.com/act_runner/{version}/act_runner-{version}-{goos}-{goarch}{ext}"

Jump to

Keyboard shortcuts

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