diff --git a/README.md b/README.md index 767dce2..1d96f75 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,8 @@ netssh -p 2222 admin@app-server-03 uptime - **Flexible IP resolution** — configurable chain of strategies: management subnet, primary IP, or named interface - **Interactive TUI** — fuzzy search with live NetBox queries and 300 ms debouncing (start with `netssh`, no arguments) - **Persistent cache** — successful lookups are cached to `~/.cache/netssh/hosts.json` for instant shell completion -- **Shell completion** — tab-complete hostnames from the cache in zsh, bash, and fish +- **Setup wizard** — interactive first-run onboarding; re-run anytime with `netssh configure` +- **Shell completion** — install without sudo via `netssh completion install` - **Default SSH user** — set a fallback username once in config instead of typing it every time ## Installation @@ -46,12 +47,27 @@ go build -o netssh ./cmd/netssh ## Configuration -Create `~/.config/netssh.yaml`: +### Interactive wizard + +On first run (when no config exists), `netssh` automatically starts an interactive setup wizard. +Re-run it at any time to change settings without editing the file manually: + +```sh +netssh configure +``` + +The wizard walks through NetBox connection, SSH defaults, resolver strategies, and cache TTL, +then saves to `~/.config/netssh.yaml`. + +### Manual config + +`~/.config/netssh.yaml`: ```yaml netbox: url: https://netbox.example.com - token: your-api-token-here + token: nbt_your-api-token-here # v2 token (nbt_ prefix) recommended + token_version: 2 # auto-detected from token; 1 = legacy, 2 = nbt_ resolver: # Strategies are tried in order; the first to return an IP wins. @@ -73,7 +89,19 @@ ssh: default_user: admin # used when no user is specified on the command line ``` -Any value can be overridden with environment variables (`NETSSH_NETBOX_URL`, `NETSSH_NETBOX_TOKEN`, etc.) or will be read from the config file. +Any value can be overridden with environment variables (`NETSSH_NETBOX_URL`, `NETSSH_NETBOX_TOKEN`, etc.). + +### API tokens + +NetBox supports two token formats: + +| Format | Example | Notes | +|--------|---------|-------| +| v2 (recommended) | `nbt_abc123…` | Create in NetBox → Admin → API Tokens | +| v1 (legacy) | `abc123def456…` | Older format; still works, but v2 is preferred | + +`netssh` auto-detects the version from the token prefix and stores it as `token_version` in the config. +A hint is shown during `netssh configure` if a legacy v1 token is entered. ## Usage @@ -146,28 +174,26 @@ Strategies are tried in the configured order; the first to succeed wins. ## Shell Completion -### zsh +Install completion for the current user (no sudo required): ```sh -netssh completion zsh > "${fpath[1]}/_netssh" +netssh completion install # auto-detects $SHELL +netssh completion install --shell bash +netssh completion install --shell zsh +netssh completion install --shell fish ``` -Or add to `.zshrc`: +| Shell | Install path | +|-------|-------------| +| bash | `~/.local/share/bash-completion/completions/netssh` | +| zsh | `~/.zfunc/_netssh` | +| fish | `~/.config/fish/completions/netssh.fish` | + +For zsh, make sure `~/.zfunc` is in your `fpath` (add to `~/.zshrc`): ```zsh -source <(netssh completion zsh) -``` - -### bash - -```sh -netssh completion bash > /etc/bash_completion.d/netssh -``` - -### fish - -```sh -netssh completion fish > ~/.config/fish/completions/netssh.fish +fpath=(~/.zfunc $fpath) +autoload -Uz compinit && compinit ``` Completions are served from the local cache — no network request on every ``. @@ -179,12 +205,13 @@ go test ./... # run all tests go build ./... # build all packages ``` -The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, and SSH argument parser. +The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, SSH argument parser, config loading, and the setup wizard. ## How it works -1. `netssh` checks whether the first argument is a known subcommand (`search`, `cache`, `completion`). If not, it enters SSH wrapper mode. -2. It parses the SSH arguments to extract the destination hostname, handling all flags that consume an extra argument (`-p`, `-i`, `-J`, …). -3. It checks the local cache. If the entry exists and is within the TTL, it connects immediately. -4. Otherwise it queries NetBox (`/api/dcim/devices/` and `/api/virtualization/virtual-machines/` in parallel), runs the result through the resolver chain, and caches the IP. -5. It calls `syscall.Exec` to replace itself with `ssh`, substituting the hostname with the resolved IP. +1. `netssh` checks whether the first argument is a known subcommand (`configure`, `search`, `cache`, `completion`). If not, it enters SSH wrapper mode. +2. On first run or when `netbox.url` is empty, the interactive setup wizard starts automatically. +3. It parses the SSH arguments to extract the destination hostname, handling all flags that consume an extra argument (`-p`, `-i`, `-J`, …). +4. It checks the local cache. If the entry exists and is within the TTL, it connects immediately. +5. Otherwise it queries NetBox (`/api/dcim/devices/` and `/api/virtualization/virtual-machines/` in parallel), runs the result through the resolver chain, and caches the IP. +6. It calls `syscall.Exec` to replace itself with `ssh`, substituting the hostname with the resolved IP.