burrow is a Bunny.net CLI written in Go.
brew install sandwich/tap/burrowyay -S burrow-bin
# or with paru:
paru -S burrow-binscoop bucket add sandwich https://github.com/sandwich/scoop-bucket
scoop install burrowDownload the archive for your OS/arch from Releases, extract, and place burrow on your $PATH. Each release ships:
- SHA-256 checksums (
checksums.txt) - cosign signatures (
*.sig+*.crt) — verify withcosign verify-blob - SPDX SBOMs (
*.sbom.json) per archive
Verify a download:
cosign verify-blob \
--certificate burrow_<version>_<os>_<arch>.<ext>.crt \
--signature burrow_<version>_<os>_<arch>.<ext>.sig \
--certificate-identity-regexp 'https://github\.com/sandwich/burrow/' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
burrow_<version>_<os>_<arch>.<ext>- Go 1.21 or newer
gitmake(optional — only needed for the Makefile targets)- Linux only, optional credential helpers:
libsecret(secret-tool) orpass
git clone https://github.com/sandwich/burrow.git
cd burrowPlain go build:
go build ./cmd/burrow
./burrow --helpOr via the Makefile (writes a stamped binary to ./bin/):
make build
./bin/burrow --helpThe Makefile injects version metadata via -ldflags. Override at build time:
make build VERSION=v0.1.0make test # go test ./...
make coverage # writes coverage.out and prints a function summaryInstall the burrow binary to your $GOBIN (or $GOPATH/bin, default ~/go/bin):
make installIf burrow --help returns "command not found", ~/go/bin isn't on your PATH. Either run it by full path:
~/go/bin/burrow --help…or add the Go bin directory to your shell rc once:
# bash
echo 'export PATH="$(go env GOPATH)/bin:$PATH"' >> ~/.bashrc && exec bash
# zsh
echo 'export PATH="$(go env GOPATH)/bin:$PATH"' >> ~/.zshrc && exec zsh
# fish
fish_add_path (go env GOPATH)/binThe contracts/scrape pipeline can use a companion analyzer at cmd/burrow-analyzer:
go build -o burrow-analyzer ./cmd/burrow-analyzer
export BURROW_LLM_ANALYZER=$PWD/burrow-analyzerAuthenticate once (stores your API key securely when possible):
burrow auth login
burrow auth statusNon-interactive options:
export BUNNY_API_KEY="..."
burrow auth login
printf "%s" "$BUNNY_API_KEY" | burrow auth login --stdinCredential store selection:
- macOS: Keychain (
security) - Linux:
secret-tool, thenpass, else file fallback - Windows: Registry (value encrypted via DPAPI using
powershell)
Override with BURROW_CREDENTIAL_STORE=keychain|secret-tool|pass|registry|file.
Generic API caller (works for any Bunny.net endpoint when you know METHOD + PATH):
burrow api GET /pullzone
burrow api GET /pullzone/123 --pretty
burrow api POST /pullzone --json '{"Name":"example"}'Base URL resolution:
--base-url https://...BURROW_BASE_URL=https://...burrow config set --base-url https://...
Discover endpoints from the local contract:
burrow endpoints list
burrow endpoints resolve GET /pullzone/123
burrow endpoints call GET /pullzone/{id} --param id=123endpoints call uses base_url from the contract when available (e.g. Stream API uses https://video.bunnycdn.com).
Setup diagnostics:
burrow doctor
burrow doctor --check-authContracts are local JSON describing endpoints (see contracts/contract.json for the format).
Initialize and validate:
burrow contracts init
burrow contracts validateSync from Bunny.net API reference docs (recommended):
burrow contracts sync
burrow contracts validateImport from an OpenAPI JSON document (if Bunny publishes one):
burrow contracts import-openapi --file ./openapi.json
# or:
burrow contracts import-openapi --url https://example.com/openapi.jsonQueue a docs scrape and run it:
burrow scrape enqueue --url "https://docs.example.com/api-reference"
burrow scrape runBulk-enqueue from a sitemap:
burrow scrape sitemap --url "https://docs.example.com/sitemap.xml"
burrow scrape runOptional LLM-assisted analyzer:
- Set
BURROW_LLM_ANALYZERto an executable that reads analyzer input JSON on stdin and prints an updated contract JSON on stdout. - Reference implementation (heuristic, no LLM):
go build ./cmd/burrow-analyzerthenexport BURROW_LLM_ANALYZER=./burrow-analyzer.
Analyzer protocol:
- stdin: JSON
{ "url": "...", "html": "<raw>", "contract": { ... } } - stdout: updated contract JSON (and nothing else)