CLI command
skarbiec tool
Take a developer tool's token out of the plain-text file the tool keeps it in, and into the vault, so the tool signs in with a token read from the vault and no file holds a token that can publish or deploy. It is one operation for every tool; each tool is an adapter that knows where its file is, how an entry is named and which variables it reads before the file.
Invocation#
skarbiec tool list
skarbiec tool status [<tool>]
skarbiec tool import <tool> <id> [--select <entry>] --bindings <file> [--tags <tag,...>]
# the tool then runs through exec
skarbiec exec --env-from <file> -- <program>Purpose#
Take a developer tool's token out of the plain-text file the tool keeps it in, and into the vault, so the tool signs in with a token read from the vault and no file holds a token that can publish or deploy. It is one operation for every tool; each tool is an adapter that knows where its file is, how an entry is named and which variables it reads before the file.
Required inputs and options#
- list takes nothing. status takes an optional tool, else answers every tool. import takes the tool, the new item's id, --select naming the entry where the tool keeps one token per entry, --bindings — the exec --env-from file to bind the token in, created when absent — and optional --tags. The adapters: npm (.npmrc, or the file NPM_CONFIG_USERCONFIG names; --select is the registry key as .npmrc writes it, such as //registry.npmjs.org/; it binds NPM_TOKEN_<the registry's letters and digits> and writes ${that variable} in the token's place), twine (~/.pypirc; --select is the repository section; it stores a login and binds TWINE_USERNAME and TWINE_PASSWORD), gh (hosts.yml in GH_CONFIG_DIR, $XDG_CONFIG_HOME/gh or ~/.config/gh; --select is the host; it binds GH_TOKEN, or GH_ENTERPRISE_TOKEN for any host but github.com), gem (~/.gem/credentials, else credentials under $XDG_DATA_HOME/gem or ~/.local/share/gem; --select is rubygems_api_key or a gem server's address; it binds GEM_HOST_API_KEY), huggingface (token and stored_tokens under HF_TOKEN_PATH, HF_STORED_TOKENS_PATH, HF_HOME, $XDG_CACHE_HOME/huggingface or ~/.cache/huggingface; without --select the active token, with it a stored one; it binds HF_TOKEN), fly (config.yml in FLY_CONFIG_DIR or ~/.fly; it binds FLY_ACCESS_TOKEN) and vercel (the first auth.json of the CLI's data directory or ~/.vercel; it binds VERCEL_TOKEN). POST /v1/operator/tool/list, /status and /import take the same — tool, id, select, bindings as an absolute path and tags — and act on the machine the backend runs on.
Output and state effects#
- list prints each adapter with what it is and what --select names. status prints, per tool, tool, file, the variables it reads and entries — each entry with how it is kept, plain text with the import that moves it as move_with, or how else (an environment reference, no password, no token); without a tool it prints every tool, a tool whose file cannot be read answering its error. No token is printed. import stores the entry's token as a new item and reads it back, binds the tool's variables to it in the bindings file — unchanged when those lines are already there — remembers that file (bindings list), and only then takes the token out of the tool's file, keeping every other line or key: npm's line names the variable instead, twine's password line, gh's oauth_token lines, gem's key line and fly's access_token line go, the Hugging Face token file and every stored token holding the same token go, and auth.json is written back without its token. It journals tool-imported with the tool, item, entry, variables and files, and prints ok, tool, item, entry, variables, file, bindings, run_with and next — and for vercel the rotate line that replaces the token.
Refusals#
- Anything else exits 2 with the usage, as do an unknown tool, naming the tools there are, import without a tool, an id or --bindings, a missing --select where the tool keeps one token per entry, and a --select where it keeps one. import is refused for an entry the file does not hold, one already read from a variable, one keeping no token or password, a twine section naming no username, gh hosts keeping several accounts' tokens, a Hugging Face file with no active token and no --select, an auth.json that is not a JSON object, a bindings file binding a variable to something else, an id that exists and a token the item does not read back — with the tool's file left as it was. When the bindings file or the tool's file cannot be written, the tool's file keeps the token and the item holds a copy, both named with the step left.
Examples#
skarbiec tool list skarbiec tool status skarbiec tool import npm npm-publish --select //registry.npmjs.org/ --bindings .skarbiec-env --tags js skarbiec tool import twine pypi-upload --select pypi --bindings .skarbiec-env skarbiec tool import fly fly-deploy --bindings .skarbiec-env skarbiec exec --env-from .skarbiec-env -- npm publish