Files
unkinben 123faf8bbf
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
Add vctl and vctx Vault token CLIs
Introduces the vault-tools monorepo: two Go CLIs that share a config file
(~/.config/vault) and token cache (~/.cache/vault) for working with multiple
Vault instances (contexts).

- add shared/ library: config parsing (vctl.yaml/config.yaml, per-context
  overrides, slash contexts), token cache (0600/0700, atomic writes, path-
  traversal guards), and a small hand-rolled Vault HTTP client (login/renew)
- add vctl: login/renew (single or --all), list, --method/--user overrides,
  no-echo password/token prompts, dynamic context completion
- add vctx: resolve a context, set VAULT_ADDR/VAULT_TOKEN/VAULT_NAMESPACE and
  exec the vault CLI, passing remaining args through untouched
- add unit tests across shared/, vctl and vctx command layers (config
  resolution, cache paths, vault client, --all iteration + error aggregation,
  vctx arg pass-through and env construction via fakeable exec/prompt seams)
- add Makefile (build/test/completions/rpm, patch|minor|major version bumps),
  nfpm RPM packaging bundling bash/zsh/fish completions for both binaries
- add Woodpecker pipelines: build/test/pre-commit on PRs, and a tag release
  that cross-compiles, builds+uploads the RPM to artifactapi, and cuts a Gitea
  release (serviceAccountName default, k8s resources on every step)
- add README, per-command docs (docs/vctl.md, docs/vctx.md), AGENTS.md and an
  example config

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-26 23:28:05 +10:00

2.7 KiB

AGENTS.md

Project Overview

vault-tools is a Go monorepo of small CLIs for managing Vault tokens across multiple vault instances ("contexts"):

  • vctl — logs in to / renews Vault tokens per context (login, renew, list), with --all, --method and --user flags. Caches each token under ~/.cache/vault/<context> as JSON (token + accessor + policies + TTL/expiry).
  • vctx — thin wrapper around the real vault CLI: vctx --context <ctx> <vault args...> resolves the context, sets VAULT_ADDR/VAULT_TOKEN/VAULT_NAMESPACE, and execs vault.

Both tools share the shared/ package (config parsing, token cache, Vault HTTP client) and read the SAME config file (~/.config/vault/vctl.yaml or config.yaml) and token cache so one ~/.config/vault/ configures everything.

Structure

shared/            # config.go, cache.go, vault.go (+ *_test.go)
vctl/main.go       # vctl CLI (module main package)
vctx/main.go       # vctx CLI (module main package)
docs/vctl.md       # per-command docs
docs/vctx.md
go.mod             # module git.unkin.net/unkin/vault-tools
Makefile           # build / test / lint / completions / rpm / version-bump
packaging/nfpm.yaml# nfpm spec (envsubst-templated) for the RPM (both binaries)
scripts/build-rpm.sh
.woodpecker/       # CI: build, test, pre-commit (PR) + release (tag)
dist/              # build output: binaries, completions, RPM (not committed)

Each tool is a separate main package under its own folder, so make build builds each with its own -o (a single go build ./... can't emit multiple mains to one file).

Build / test

make build          # -> dist/vctl, dist/vctx
make test           # go test -race ./...
make completions    # -> dist/completions/{vctl,vctx}.{bash,fish}, _{vctl,vctx}
make rpm            # build + nfpm RPM (bundles completions)
go build ./... && go test ./...

Conventions

  • Config/cache dirs honour $XDG_CONFIG_HOME / $XDG_CACHE_HOME.
  • Context names may contain slashes (staging/sydney) and nest in the cache; names are validated to prevent path traversal (see shared/cache.go).
  • Token files are 0600, their parent dirs 0700; writes are atomic (temp file + rename).
  • shared/vault.go is a small hand-rolled Vault HTTP client (no hashicorp/vault/api dependency) — only cobra, yaml.v3, x/term.

Releasing

Releases run in Woodpecker on v* tags. make patch|minor|major tags + pushes. The release pipeline cross-compiles both binaries, builds an RPM (with completions), PUTs it to the artifactapi rpm-internal yum repo, and cuts a Gitea release. Every pipeline step sets k8s resources and serviceAccountName: default; the release step uses the RELEASER_TOKEN Woodpecker secret.