# netssh > **Vibe-coded project** — this codebase was written entirely by an AI assistant (Claude) without human code review. Use in production at your own risk. A transparent SSH wrapper that resolves hostnames via [NetBox](https://netbox.dev/) before connecting. Instead of looking up an IP manually, you just type the hostname as it appears in NetBox: ```sh netssh my-router-01 netssh -p 2222 admin@app-server-03 uptime ``` `netssh` looks up the host in NetBox, resolves the right IP using a configurable strategy chain, and replaces the process with the native `ssh` binary — so all your existing SSH configs, keys, and agent forwarding work without any changes. ## Features - **Transparent proxy** — replaces itself with `ssh` via `syscall.Exec`, preserving all SSH flags and options - **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) - **Recently-used list** — TUI opens with your 10 most-recently-connected hosts, no typing needed - **Tag/kind filter** — press `Ctrl+F` in the TUI to filter by `tag:prod` or `kind:vm` - **User/port override** — press `e` in the TUI to override the SSH user or port before connecting - **Persistent cache** — successful lookups are cached to `~/.cache/netssh/hosts.json` for instant shell completion - **Full pagination** — `cache refresh` fetches all hosts from NetBox (not just the first 50) - **Selective refresh** — `cache refresh --tag prod --kind vm` limits what gets synced - **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 ### One-liner (Linux & macOS) ```sh curl -fsSL https://git.zb-server.de/Sebi/ssh-netbox-wrapper/raw/branch/main/install.sh | bash ``` The script detects your OS and architecture, downloads the matching binary from the [latest release](https://git.zb-server.de/Sebi/ssh-netbox-wrapper/releases/latest), verifies the SHA-256 checksum, and installs to `/usr/local/bin/netssh` (using `sudo` only if necessary). To install to a custom directory: ```sh INSTALL_DIR=~/.local/bin curl -fsSL https://git.zb-server.de/Sebi/ssh-netbox-wrapper/raw/branch/main/install.sh | bash ``` ### Build from source ```sh git clone ssh://git@git.zb-server.de:30022/Sebi/ssh-netbox-wrapper.git cd ssh-netbox-wrapper go build -o netssh ./cmd/netssh ``` ## Configuration ### 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: 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. strategies: - management_subnet - primary_ip # Used by the management_subnet strategy. management_subnets: - 10.0.0.0/8 - 172.16.0.0/12 # Used by the interface_name strategy. interface_name: mgmt0 cache: ttl: 3600 # seconds; 0 = always query NetBox on connect (cache still used for completion) # path: ~/.cache/netssh/hosts.json # default 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.). ### 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 ### SSH wrapper mode Pass any SSH flags and a NetBox hostname: ```sh netssh my-router-01 netssh -p 2222 admin@app-server-03 uptime netssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no db-primary ``` The process is replaced by `ssh` with the resolved IP — your `~/.ssh/config`, agent, and keys all work as normal. ### Default username Set `ssh.default_user` in the config to avoid typing a username every time: ```sh netssh my-router # → ssh -l admin 10.0.0.1 ``` The default is only applied when no user is specified on the command line. An explicit user always takes precedence: ```sh netssh root@my-router # user@ prefix wins → ssh root@10.0.0.1 netssh -l ops my-router # -l flag wins → ssh -l ops 10.0.0.1 ``` ### Interactive TUI Run without arguments to open the interactive search: ```sh netssh ``` The TUI opens with your 10 most-recently-connected hosts. Start typing to search all cached hosts or query NetBox live. | Key | Action | |-----|--------| | type | filter hosts (300 ms debounce → NetBox query) | | `Tab` | autocomplete top result into the search field | | `↑` / `↓` | navigate results | | `Enter` | connect to selected host | | `e` | open inline editor to override user/port before connecting | | `Ctrl+F` | open/close tag and kind filter (`tag:prod kind:vm`) | | `Esc` / `Ctrl+C` | quit (or close filter/edit if open) | **Tag and kind filter** — press `Ctrl+F` to open a second input line: ``` Filter: tag:prod kind:vm ``` Multiple `tag:` values are AND-combined. The filter is applied locally against the cache; when doing a live NetBox search the first tag is also forwarded as a query parameter. **User/port override** — press `e` on any highlighted host: ``` Connect as: admin@my-router:22 ``` Edit the pre-filled value and press `Enter` to connect. `Esc` cancels. Port 22 is treated as default and omitted from the ssh command. ### Cache management ```sh netssh cache list # show all cached entries netssh cache refresh # re-fetch ALL hosts from NetBox (paginated) netssh cache refresh --tag prod # only hosts with the "prod" tag netssh cache refresh --kind vm # only virtual machines netssh cache refresh --tag prod --kind vm # combine filters netssh cache clear # wipe the cache ``` ### Search (for scripting) ```sh netssh search app- # prints matching hostnames, one per line ``` ## IP Resolution Strategies Strategies are tried in the configured order; the first to succeed wins. | Name | Description | |------|-------------| | `primary_ip` | Returns the `primary_ip4` (or `primary_ip6`) set in NetBox. No extra API call. | | `management_subnet` | Fetches all IPs for the host and returns the first one matching a configured CIDR. | | `interface_name` | Fetches IPs attached to a specific named interface (e.g. `mgmt0`). | ## Shell Completion Install completion for the current user (no sudo required): ```sh netssh completion install # auto-detects $SHELL netssh completion install --shell bash netssh completion install --shell zsh netssh completion install --shell fish ``` | 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 fpath=(~/.zfunc $fpath) autoload -Uz compinit && compinit ``` Completions are served from the local cache — no network request on every ``. ## Development ```sh go test ./... # run all tests go build ./... # build all packages ``` The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, SSH argument parser, config loading, and the setup wizard. ## Disclaimer This is a **vibe-coded** project: the entire codebase — architecture, implementation, tests, and docs — was generated by an AI assistant (Claude by Anthropic). No human has reviewed or audited the code. It works for the author's personal use case, but correctness and security are not guaranteed. Read the source before running it in sensitive environments. ## How it works 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.