|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code when working with code in this repository. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +`cli-utils` (module `github.com/smallstep/cli-utils`) is a small Go library of shared building blocks for Smallstep's `urfave/cli`-based command-line tools. Its main consumers are [`step`](https://github.com/smallstep/cli) and [`step-ca`](https://github.com/smallstep/certificates), which pin it at a tagged version. It is a public, Apache-2.0 library but is not a stable API: the README warns that other projects should not depend on it and that the API can change at any time. There is no binary here, only packages. |
| 8 | + |
| 9 | +## Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +make bootstrap # install golangci-lint, govulncheck, gotestsum |
| 13 | +make test # unit tests via gotestsum (-short, coverage); this is what `make ci` runs |
| 14 | +make race # unit tests with the race detector |
| 15 | +make lint # golangci-lint (config fetched from smallstep/workflows) + govulncheck |
| 16 | +make fmt # goimports -l -w on all .go files |
| 17 | +make # lint + test |
| 18 | +``` |
| 19 | + |
| 20 | +Plain `go` works too and needs no special environment (no private modules, no Docker, no `go generate`): |
| 21 | + |
| 22 | +```bash |
| 23 | +go build ./... |
| 24 | +go test -short ./... |
| 25 | +go test -run TestParse ./token/ # single test |
| 26 | +``` |
| 27 | + |
| 28 | +`make test` and `make lint` require the tools from `make bootstrap` on `$PATH`. `make lint` needs network access to download the shared golangci config. CI (`.github/workflows/ci.yml`) calls the shared `goCI` reusable workflow with `run-build: false`, so tests and lint are what gate a PR; CodeQL runs with `go build ./...`. |
| 29 | + |
| 30 | +## Architecture |
| 31 | + |
| 32 | +``` |
| 33 | +cli-utils/ |
| 34 | +├── command/ # Global command registry for urfave/cli apps |
| 35 | +│ ├── command.go # Register/Retrieve commands; ActionFunc captures the ctx; IsForce() |
| 36 | +│ └── version/ # `version` command, registered in init() |
| 37 | +├── errs/ # Error constructors with user-facing messages for flag/argument misuse |
| 38 | +├── fileutil/ # File writes with overwrite prompts (WriteFile, WriteSnippet, AppendNewLine, ...) |
| 39 | +├── step/ # $STEPPATH layout, contexts (profile + authority), defaults.json flag loading |
| 40 | +│ ├── config.go # Path(), Home(), BasePath(), Version(), file-location helpers |
| 41 | +│ └── context.go # Context/CtxState, contexts.json, SetEnvVar, getConfigVars |
| 42 | +├── token/ # JWT claim builders (token.Options) and parsing for step provisioning tokens |
| 43 | +│ └── provision/ # provision.Token: builds a signed JWT from token.Options |
| 44 | +├── ui/ # promptui-based interactive prompts, validators, colored output to stderr |
| 45 | +├── usage/ # Custom help templates and renderer (markdown-ish help text, HTML export) |
| 46 | +└── pkg/blackfriday/ # Vendored fork of russross/blackfriday v2 used by usage/ (own LICENSE.txt) |
| 47 | +``` |
| 48 | + |
| 49 | +### How the pieces fit |
| 50 | + |
| 51 | +- A CLI registers each `cli.Command` with `command.Register`. That calls `step.SetEnvVar`, which gives every flag an `EnvVar` of `STEP_<FLAG_NAME>` (uppercased, `-` to `_`) unless one is already set, and installs `getConfigVars` as the command's `Before` hook so unset flags are filled from the active context's `defaults.json`. Set a flag's `EnvVar` to `step.IgnoreEnvVar` to opt it out of both. |
| 52 | +- `step` resolves the config root from `STEPPATH` (default `$HOME/.step`) once, via `sync.Once`. With contexts enabled, per-authority config lives under `authorities/<name>/` and profiles under `profiles/<name>/`; `contexts.json` and `current-context.json` sit at the root. Call `step.Init()` before using these helpers. |
| 53 | +- `usage` overrides urfave/cli's `help` command and templates. Command `Description`/`UsageText` strings use a lightweight markdown dialect (`**bold**`, `'''` fenced blocks, `## SECTIONS`) that `usage.Render` turns into terminal output via `pkg/blackfriday`; `step help --html <dir>` exports the same content as HTML. |
| 54 | +- `fileutil.WriteFile` and friends consult `command.IsForce()`; without `--force` they prompt through `ui` before overwriting. |
| 55 | +- `ui` prints prompts and messages to stderr (never stdout) so command output stays pipeable; `ui_windows.go`/`ui_other.go` are build-tagged for console-mode handling. |
| 56 | + |
| 57 | +## Conventions |
| 58 | + |
| 59 | +**CLI framework**: `urfave/cli` v1 (`github.com/urfave/cli`), not v2. Errors returned to users go through `errs` constructors so messages are consistent across `step` commands. |
| 60 | + |
| 61 | +**Error wrapping**: `github.com/pkg/errors` throughout (`errors.Errorf`, `errors.Wrapf`); `errs.Wrap` normalizes causes for display. Do not introduce `fmt.Errorf("%w")` in a file that otherwise uses `pkg/errors`. |
| 62 | + |
| 63 | +**Logging**: none. Output goes to `ui.Print*` (stderr) or `fmt.Print*` (stdout) as appropriate. |
| 64 | + |
| 65 | +**Testing**: `testify` (`assert`/`require`) for new tests; a few older tests still use `github.com/smallstep/assert`. Tests that touch `$STEPPATH` use `t.TempDir()` plus `t.Setenv(step.HomeEnv, ...)` to stay hermetic. Fixtures live in `token/testdata/` (certificates and keys) and `pkg/blackfriday/testdata/` (markdown/HTML pairs). `command/`, `fileutil/`, and `usage/` have no tests. |
| 66 | + |
| 67 | +**Vendored code**: `pkg/blackfriday/` is a copy of an upstream library with its own license and README. Keep changes there minimal and clearly motivated; the rest of the repo is where Smallstep-specific behavior belongs. |
| 68 | + |
| 69 | +**Compatibility**: `step` and `step-ca` are the callers. Renaming or changing the signature of an exported symbol breaks them on their next dependency bump, so prefer additive changes and check both consumers before removing anything. |
| 70 | + |
| 71 | +## Environment Variables |
| 72 | + |
| 73 | +- `STEPPATH` — root of the step configuration directory (default `$HOME/.step`) |
| 74 | +- `HOME` — used to derive the default `STEPPATH`; falls back to `os/user` |
| 75 | +- `STEP_<FLAG>` — auto-derived per-flag overrides for any command registered via `command.Register` |
| 76 | +- `STEP_IGNORE_ENV_VAR` — sentinel value, not a variable to set: assign it to a flag's `EnvVar` to disable env and defaults.json lookup for that flag |
| 77 | + |
| 78 | +## Releases |
| 79 | + |
| 80 | +Versions are git tags (`v0.12.x`). After tagging, bump the dependency in `step` and `step-ca`; there is no release workflow in this repo. |
0 commit comments