Skip to content

Latest commit

Β 

History

244 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

binstaller β€” one YAML profile, every binary, every machine

One YAML profile. Every binary. Same result on every machine.

binstaller is a native CLI that installs binary tool distributions from a single declarative profile β€” with a dry-run plan you read first, SHA-256 verification you can trust, and a lock file that pins the result.


Release Pages Latest release

Scala 3 Mill GraalVM Linux macOS Sigstore


🌐 Website Β Β·Β  πŸ“š Wiki Β Β·Β  πŸ“¦ Releases Β Β·Β  πŸ” Security model


binstaller apply β€” concurrent downloads with progress bars and an install summary


⚑ Install

curl --proto '=https' --tlsv1.2 -sSfL \
  https://github.com/worxbend/binstaller/releases/latest/download/install.sh | sh

The script downloads the release tarball, verifies its SHA-256 checksum, additionally verifies the keyless Sigstore signature when cosign is installed, and installs binstaller to ~/.local/bin.

Knob Effect
BINSTALLER_INSTALL_DIR πŸ“ Install somewhere other than ~/.local/bin.
BINSTALLER_VERSION πŸ“Œ Pin a specific version, e.g. v0.2.0.
BINSTALLER_UPDATE_PATH=1 🧭 Append the install dir to ~/.bashrc and ~/.zshrc.

Note

By default nothing in your shell configuration is modified β€” the script just prints the export PATH=... line to run.

πŸ“¦ Release artifacts β€” every .tar.gz and the example config ship with a .sha256 file
  • binstaller-<version>-linux-amd64.tar.gz
  • binstaller-<version>-linux-arm64.tar.gz
  • binstaller-<version>-macos-amd64.tar.gz
  • binstaller-<version>-macos-arm64.tar.gz
  • config.example.<version>.yaml
  • install.sh

πŸš€ Quick Start

1️⃣ Copy a profile

cp config.example.yaml config.yaml

2️⃣ Read the plan β€” nothing is written

binstaller plan
binstaller plan output showing resolved versions, URLs, checksums and archive mappings

3️⃣ Apply it

binstaller apply

4️⃣ Watch for drift

binstaller versions
binstaller versions output with pinned versions next to newer GitHub releases

Narrow the blast radius β€” both flags are repeatable, --only is applied first and --skip second:

binstaller plan  --only yazi
binstaller apply --skip neovim

Pin everything to a lock file:

binstaller lock --lock-file binstaller.lock.json
binstaller apply --locked --lock-file binstaller.lock.json

✨ Why binstaller

πŸ” Plan before apply
Every version, URL, archive mapping and symlink resolved and printed. Zero filesystem writes.
πŸ” Checksums, loudly
SHA-256 verified when configured β€” and a missing checksum is called out in the plan.
🧊 Lock files
lock writes resolved versions and digests; apply --locked refuses to drift.
πŸ›‘οΈ SSRF-guarded
HTTPS only. Loopback, private and cloud-metadata hosts rejected β€” on every redirect hop.
↩️ Resumable state
State is saved after each tool and keyed to the manifest fingerprint, so re-runs skip what worked.
⚑ Native, no JVM
GraalVM native images for Linux and macOS, amd64 and arm64.
πŸ“¦ Archives handled
Direct binaries, zip, tar.gz, tar.xz β€” member paths validated so nothing escapes staging.
πŸ”— Sudo is opt-in
System-wide symlinks need allowSudoSymlinks and are flagged sudo risk in the plan.
🧱 Strict mode
policy.mode: strict rejects latest-URLs, missing checksums, sudo symlinks and tar.xz fallbacks.

Important

The scope is deliberately narrow. binstaller is not a package manager, a dotfiles runner, an installer-script host, a shell-command runner, or a multi-OS provisioner. Manifest installer: blocks are rejected at load time, on purpose.


πŸŽ›οΈ CLI Surface

Command Purpose Writes files
πŸ” plan Render the resolved install plan. ❌
πŸš€ apply Download, verify, stage, install, symlink, save state. βœ…
πŸ†™ versions Print package versions and available GitHub release updates. ❌
🧊 lock Resolve and write a JSON lock file. 🧊 lock file only
βš™οΈ Shared options and exit codes

Shared options

Flag Meaning
--config FILE Path to the YAML profile. Defaults to config.yaml in the current directory.
--state FILE Override the profile state file for apply.
--reset-state Ignore saved execution state and start fresh.
--verbose Show additional command diagnostics.
--only TOOL Include only a named tool (plan, apply, versions, lock). Repeatable.
--skip TOOL Omit a named tool (plan, apply, versions, lock). Repeatable.

plan and apply also accept

Flag Meaning
--locked Require a compatible JSON lock file before running.
--lock-file FILE Path to the JSON lock file used by --locked.

apply also accepts

Flag Meaning
--parallelism N Number of tools downloaded and staged concurrently. Default 4. Must be at least 1.

lock also accepts

Flag Meaning
--lock-file FILE Lock file to write. Default binstaller.lock.json.

Exit codes

Code Meaning
0 βœ… Completed successfully, including help and plan.
1 ❌ Manifest loading/resolution failed, selection invalid, apply failed, or state persistence failed.
2 ⚠️ Command-line usage error.

πŸ“„ The Manifest

One file describes the whole toolchain β€” reviewable in a pull request, validated before a byte is downloaded.

apiVersion: binstaller.io/v1alpha1
kind: BinaryDistributionProfile

spec:
  policy:
    mode: strict                      # 🧱 reject latest-URLs, missing checksums, sudo symlinks
    appsDir: "${HOME}/.apps"
    allowSudoSymlinks: false

  versions:
    lazygit: 0.61.0                   # πŸ“Œ pinned
    kubectl:
      resolver:                       # 🌐 resolved at plan time
        type: http-text
        url: https://dl.k8s.io/release/stable.txt

  plan:
    - name: lazygit
      kind: binary-tool
      spec:
        versionRef: lazygit
        installDir: "${appsDir}/lazygit"
        download:
          url: "https://github.com/jesseduffield/lazygit/releases/download/v${version}/lazygit_${version}_Linux_x86_64.tar.gz"
          filename: lazygit.tar.gz
          checksum:                   # πŸ” verified before anything is unpacked
            algorithm: sha256
            value: 45d49e06…78633d
          archive:
            type: tar.gz
            extract:
              files:
                - from: lazygit
                  to: bin/lazygit
        executables:
          - path: bin/lazygit

πŸ“– Full field reference: docs/manifest-reference.md Β· πŸ“‹ Complete working profile: config.example.yaml


↩️ State And Resume

apply writes state after each per-tool result. State is tied to the profile name and the manifest fingerprint, so a later apply can skip tools already completed for the same profile.

  • πŸ“ The state path comes from --state or spec.policy.stateFile.
  • πŸ”’ State paths are current-directory filenames only β€” absolute, nested and empty paths are rejected.
  • 🧊 plan never touches state.
  • πŸ”„ Use --reset-state to intentionally ignore compatible saved state and retry from the beginning.

πŸ› οΈ Build From Source

Requirements: JDK 21+ Β· GraalVM 21 only for local native images.

./mill __.compile                          # πŸ—οΈ  compile everything
./mill __.test                             # πŸ§ͺ  run every test module
./mill mill.scalalib.scalafmt/checkFormatAll   # 🎨  formatting gate

./mill app.run plan --config config.example.yaml   # ▢️  run from source

Build a native image locally:

GRAALVM_HOME=/path/to/graalvm ./mill app.nativeImage
🧩 Module graph
app  ──▢ cli ──▢ core ──▢ config
Module Responsibility
config YAML reading, typed decoding, validation, unsupported-field rejection.
core Resolution, downloads, checksums, extraction, staging, symlinks, state, events.
cli Picocli parsing, exit codes, colored progress, script-friendly output.
app Process entry and exit-code propagation only.

πŸ“š Documentation

Doc What's inside
🌐 Website Feature tour, screenshots and quick start.
πŸ“š Wiki Getting started, recipes, troubleshooting, FAQ.
πŸ—οΈ Architecture Module graph, data flow, event contract.
🧩 Developer API Typed plan and lock API, lifecycle, injection.
πŸ“„ Manifest reference Profile shape, policy, versions, downloads, archives, symlinks.
πŸ” Security model Trust boundaries, checksums, archive safety, sudo policy, known risks.
πŸ§ͺ Testing guide Project-native checks and test patterns.
🚒 Release guide Native artifacts, release workflow, smoke checks.

Found it useful? ⭐ Star the repo β€” it genuinely helps.

πŸ› Report a bug Β Β·Β  πŸ’‘ Request a feature Β Β·Β  🌐 Website

Built with Scala 3, Mill and GraalVM.

About

πŸš€ One YAML profile β†’ the same binaries on every machine. Native CLI with dry-run plans, SHA-256 verification, lock files and resumable applies.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages