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 ¶
- func BinaryName(name string) string
- func CacheDir() (string, error)
- func CachedBinary(name string) string
- func Ensure(ctx context.Context, t Tool) (string, error)
- func Platform() string
- func ProvisionManaged(ctx context.Context, spec ManagedSpec) (string, error)
- type Asset
- type GitHubSpec
- type ManagedSpec
- type Process
- type RunSpec
- type Tool
- type URLSpec
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BinaryName ¶
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 ¶
CacheDir is the root for downloaded binaries. Override via $BASHY_BIN_CACHE; otherwise <UserCacheDir>/bashy/bin.
func CachedBinary ¶
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 ¶
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 ProvisionManaged ¶
func ProvisionManaged(ctx context.Context, spec ManagedSpec) (string, error)
ProvisionManaged resolves spec to a cached executable path. Resolution order — the single shared pipeline:
- cache hit at DestDir/<name> → return (no network)
- fetch <name>-<goos>-<goarch>.gz from ReleaseRepo → gunzip → DestDir/<name>
- Build from source (if provided) → DestDir/<name>
- 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 ¶
Process is a launched managed binary.
func Launch ¶
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 ¶
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).
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.
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}"