554 lines
23 KiB
Markdown
554 lines
23 KiB
Markdown
# 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 `Ctrl+E` in the TUI to override the SSH user or port before connecting
|
|
- **Server notes** — multiline local notes or optional NetBox comments, available in the TUI and CLI
|
|
- **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
|
|
- **Default SSH port** — set a fallback port in config; injected as `-p` when not specified on the command line
|
|
- **Host shortcuts** — type `web01` instead of `web01.example.com`; configurable domain strip and hyphen folding
|
|
- **Shell aliases** — `netssh alias` generates shell aliases for all cached hosts
|
|
- **Automatic 24h cache refresh** — the cache is refreshed in the background every 24 hours
|
|
|
|
## 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
|
|
curl -fsSL https://git.zb-server.de/Sebi/ssh-netbox-wrapper/raw/branch/main/install.sh | INSTALL_DIR="$HOME/.local/bin" bash
|
|
```
|
|
|
|
### Updating an existing installation
|
|
|
|
Run the same one-liner again to update to the latest release. The installer uses
|
|
an existing `netssh` found in `PATH`, or `/usr/local/bin/netssh` for a new installation.
|
|
`INSTALL_DIR` explicitly overrides the destination. The replacement is atomic,
|
|
so an installed binary can be updated while it is running.
|
|
|
|
The installer checks all required programs before downloading or modifying files:
|
|
`curl`, `uname`, `sed`, `awk`, `mktemp`, `rm`, `dirname`, `readlink`, `mkdir`, `cat`,
|
|
`install`, `mv`, `cp`, `chmod`, `cmp`, and either `sha256sum` (Linux) or `shasum`
|
|
(macOS). Bash runs the installer; `sudo` is checked beforehand only if the target
|
|
directory requires elevated permissions. Missing programs are listed together;
|
|
install them with your package manager and retry. **Python is not required. SHA-256 verification is mandatory:** missing,
|
|
duplicate or mismatched checksums abort the update before replacing anything.
|
|
|
|
It also consolidates netssh integration in existing Bash, Zsh and Fish profiles
|
|
and creates the current shell's rc file when needed. Old standalone netssh hooks,
|
|
inline host aliases and `eval "$(netssh alias)"` entries are replaced by a single
|
|
managed block per rc file. Legacy entries in login profiles are removed as well.
|
|
Other shell settings, NetBox configuration, cache and local notes are preserved.
|
|
Every changed existing profile gets a `.netssh-backup.XXXXXX` backup; symlinks
|
|
and permissions are preserved. `XDG_CONFIG_HOME`, `XDG_CACHE_HOME` and `ZDOTDIR`
|
|
are respected. Alias files and installed shell completions are regenerated.
|
|
Open a **new terminal** after updating to load the new aliases and hooks.
|
|
|
|
### Release downloads and change history
|
|
|
|
Each new release includes `install.sh`, binaries for Linux and macOS (amd64 and
|
|
arm64), and `checksums.txt` covering all of these files. The release notes include
|
|
an installation command pointing directly to that release's `install.sh` asset
|
|
and a list of changes since the previous version tag.
|
|
|
|
See [CHANGELOG.md](CHANGELOG.md) for the change history. The installer attached to
|
|
a release installs or updates to the latest published binary release.
|
|
|
|
### 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, cache TTL, and an optional command alias,
|
|
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
|
|
default_port: 2222 # optional; injected as -p if not specified on the command line
|
|
|
|
shortcuts:
|
|
domains: # strip these suffixes to create short aliases
|
|
- .example.com
|
|
strip_hyphens: false # if true, fsn1-web01 → fsn1web01 (cache-only resolution)
|
|
```
|
|
|
|
Any value can be overridden with environment variables (`NETSSH_NETBOX_URL`, `NETSSH_NETBOX_TOKEN`, etc.).
|
|
|
|
### Short command alias
|
|
|
|
In `netssh configure`, set **Command alias** to `j` to use `j` anywhere you would
|
|
use `netssh`:
|
|
|
|
```sh
|
|
j # interactive server search
|
|
j server01 # connect to a server
|
|
j notes show server01
|
|
```
|
|
|
|
The setting is saved as:
|
|
|
|
```yaml
|
|
shell:
|
|
alias: j
|
|
```
|
|
|
|
The wizard regenerates shell aliases and installs the current shell's hook when
|
|
an alias is set. Open a new terminal (or follow the displayed reload command).
|
|
Changing the setting replaces the old generated alias; leaving it empty disables
|
|
it for new shells. The command alias takes priority over a host alias with the
|
|
same name and works even when no servers are cached. Environment override:
|
|
`NETSSH_SHELL_ALIAS=j`.
|
|
|
|
The command alias also supports shell completion: `j ser<Tab>` suggests cached
|
|
server names, just like `netssh ser<Tab>`. The wizard, shell hook, installer, and
|
|
`netssh completion install` maintain the alias completion files automatically.
|
|
Changing or disabling the alias removes its old generated completion files.
|
|
Bash requires bash-completion to load user completion files; for Zsh, include
|
|
`~/.zfunc` in `fpath` before running `compinit` as described below. Fish loads
|
|
completion files automatically. Open a new terminal after changing the alias.
|
|
|
|
### 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
|
|
```
|
|
|
|
### Default SSH port
|
|
|
|
Set `ssh.default_port` in the config to use a non-standard port without specifying it every time:
|
|
|
|
```sh
|
|
netssh my-router # → ssh -p 2222 -l admin 10.0.0.1
|
|
```
|
|
|
|
The default is only applied when `-p` is not already present in the SSH arguments. An explicit `-p` always takes precedence:
|
|
|
|
```sh
|
|
netssh -p 22 my-router # -p flag wins → ssh -p 22 10.0.0.1
|
|
```
|
|
|
|
### Host shortcuts
|
|
|
|
Configure short aliases so you can type `web01` instead of `web01.example.com`:
|
|
|
|
```yaml
|
|
shortcuts:
|
|
domains:
|
|
- .example.com
|
|
- .example.de
|
|
strip_hyphens: false # optional
|
|
```
|
|
|
|
Resolution order:
|
|
|
|
1. **Exact match** — the input is looked up as-is in the cache.
|
|
2. **Domain expansion** — if the input contains no dot, each configured domain is appended and tried (`web01` → `web01.example.com`). If no cache hit, NetBox is queried with the expanded name.
|
|
3. **Hyphen folding** (`strip_hyphens: true`) — hyphens are inserted back before looking up in the cache (`fsn1web01` → `fsn1-web01.example.com`). This only works when the host is already cached; run `netssh cache refresh` first.
|
|
|
|
Domains may be configured with or without a leading dot. If several cached hosts normalize to the same shortcut, the connection is rejected; use the full hostname. Live host lookups check every result page and reject duplicate exact names.
|
|
|
|
| Input | Config | Resolved as |
|
|
|-------|--------|-------------|
|
|
| `web01` | `domains: [.example.com]` | `web01.example.com` |
|
|
| `fsn1web01` | `domains: [.example.com]`, `strip_hyphens: true` | `fsn1-web01.example.com` (cache only) |
|
|
|
|
### Shell aliases
|
|
|
|
Generate shell aliases for all cached hosts based on the shortcut settings:
|
|
|
|
```sh
|
|
netssh alias # bash/zsh syntax
|
|
netssh alias --shell fish # fish syntax
|
|
```
|
|
|
|
Example output:
|
|
|
|
```bash
|
|
# netssh aliases (3 hosts) — source with: eval "$(netssh alias)"
|
|
alias db01='netssh db01.example.com'
|
|
alias fsn1web01='netssh fsn1-web01.example.com'
|
|
alias web01='netssh web01.example.com'
|
|
```
|
|
|
|
Add to your shell startup file:
|
|
|
|
```sh
|
|
# bash / zsh — in ~/.bashrc or ~/.zshrc
|
|
eval "$(netssh alias)"
|
|
|
|
# fish — in ~/.config/fish/config.fish
|
|
netssh alias --shell fish | source
|
|
|
|
# scripts
|
|
source <(netssh alias)
|
|
```
|
|
|
|
Without a `shortcuts` config, the alias name is derived from the full hostname with dots replaced by underscores (e.g. `web01_example_com`). If two hosts would produce the same alias name, the first entry wins and a warning is printed to stderr.
|
|
|
|
### 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 |
|
|
| `Ctrl+E` | open inline editor to override user/port before connecting |
|
|
| `Ctrl+N` | edit local notes for the selected server |
|
|
| `Ctrl+B` | edit NetBox comments for the selected server |
|
|
| `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 `Ctrl+E` on any highlighted host:
|
|
|
|
```
|
|
Connect as: admin@my-router:22
|
|
```
|
|
|
|
Edit the pre-filled value and press `Enter` to connect. `Esc` cancels. The configured default port is pre-filled. An explicit port 22 overrides a different configured default.
|
|
|
|
### Server notes
|
|
|
|
Select a server in the TUI and press `Ctrl+N` for local notes, or `Ctrl+B` for
|
|
NetBox comments. Both open a multiline editor: `Ctrl+S` saves, `Esc` cancels.
|
|
Existing text is loaded before editing. A failed save keeps your draft in the editor.
|
|
Local notes and NetBox comments are independent; there is no automatic synchronization.
|
|
|
|
The CLI also supports reading, replacing, and appending notes:
|
|
|
|
```sh
|
|
netssh notes set web01 "Maintenance on Friday"
|
|
netssh notes append web01 "Reboot completed"
|
|
netssh notes show web01
|
|
printf 'First line\nSecond line\n' | netssh notes set web01
|
|
netssh notes append web01 --netbox --kind vm "Maintenance completed"
|
|
netssh notes show web01 --netbox --kind vm
|
|
```
|
|
|
|
`set` replaces the selected note; `append` preserves existing text and adds a new line.
|
|
Omitting the text reads it from standard input. An empty string clears the note.
|
|
For an uncached local host, specify `--kind device` or `--kind vm`; local operations
|
|
work offline. Use the full server name as displayed in the TUI.
|
|
|
|
Local notes live under `~/.config/netssh/notes/` (`$XDG_CONFIG_HOME` is respected),
|
|
with file permissions `0600` and atomic file replacement. They are keyed by NetBox
|
|
URL, host kind, and hostname, so cache refreshes and `cache clear` preserve them.
|
|
Changing the hostname or NetBox URL creates a separate note identity.
|
|
|
|
`--netbox` explicitly selects the device/VM's shared `comments` field and requires
|
|
a token with write permissions. Existing comments are loaded before modification;
|
|
ambiguous names are rejected (specify `--kind` where appropriate).
|
|
The client uses the API's ETag/If-Match conflict protection when the server provides
|
|
it; older NetBox versions without ETags use the server's last-write-wins behavior.
|
|
See the [NetBox REST API documentation](https://netbox.readthedocs.io/en/stable/integrations/rest-api/).
|
|
|
|
### 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
|
|
```
|
|
|
|
The cache is refreshed automatically in the background every 24 hours. The trigger fires on the next SSH connect or TUI start after the interval has elapsed — there is no delay to the connection itself. The timestamp of the last refresh is stored in `~/.cache/netssh/last_refresh`.
|
|
|
|
To also trigger the check at shell startup (before you run any SSH command), install the shell hook:
|
|
|
|
```sh
|
|
netssh hook install # auto-detects $SHELL
|
|
netssh hook install --shell bash
|
|
netssh hook install --shell zsh
|
|
netssh hook install --shell fish
|
|
```
|
|
|
|
This appends a single line (`netssh shell-init`) to your shell profile. To remove it:
|
|
|
|
```sh
|
|
netssh hook uninstall
|
|
```
|
|
|
|
The hook is a no-op when the cache is fresh — it adds no measurable delay to your shell startup.
|
|
|
|
### 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.
|
|
|
|
Cache refresh uses the same strategies as a direct connection. To allow the primary IP as a fallback, include `primary_ip` in the strategy list. Hosts that cannot be resolved, or have ambiguous names in the refresh results, are removed from the cache and reported as warnings.
|
|
|
|
| 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 `<Tab>`.
|
|
|
|
## Shell Hook
|
|
|
|
`netssh hook install` sets up two things in your shell profile:
|
|
|
|
1. **`netssh shell-init`** — runs on every new shell session. It regenerates the alias file from the current cache so your aliases are always up to date, and starts a background cache refresh if the last full refresh was more than 24 hours ago.
|
|
2. **A `source` line** (bash/zsh only) — loads the generated alias file so shortcuts like `web01` work immediately in every new shell. Fish uses `conf.d/` auto-sourcing instead, so no explicit source line is needed.
|
|
|
|
The alias file is also generated immediately during `hook install`, so aliases are available as soon as you reload your profile — no `cache refresh` needed first (though the cache must not be empty).
|
|
|
|
### Install
|
|
|
|
```sh
|
|
netssh hook install # auto-detects $SHELL
|
|
netssh hook install --shell bash
|
|
netssh hook install --shell zsh
|
|
netssh hook install --shell fish
|
|
```
|
|
|
|
Example output:
|
|
|
|
```
|
|
Hook installed → /home/user/.bashrc
|
|
Reload with: source /home/user/.bashrc
|
|
42 aliases written to /home/user/.cache/netssh/aliases.sh
|
|
```
|
|
|
|
What gets written to the profile:
|
|
|
|
**bash / zsh** (`~/.bashrc` or `~/.zshrc`):
|
|
```bash
|
|
netssh shell-init # netssh cache auto-refresh
|
|
source ~/.cache/netssh/aliases.sh 2>/dev/null # netssh aliases
|
|
```
|
|
|
|
**fish** (`~/.config/fish/config.fish`):
|
|
```fish
|
|
netssh shell-init # netssh cache auto-refresh
|
|
```
|
|
|
|
Fish alias file (`~/.config/fish/conf.d/netssh.fish`) is written automatically and sourced by fish on every shell start without any profile changes.
|
|
|
|
| Shell | Profile file | Alias file |
|
|
|-------|-------------|------------|
|
|
| bash | `~/.bashrc` | `~/.cache/netssh/aliases.sh` |
|
|
| zsh | `~/.zshrc` | `~/.cache/netssh/aliases.sh` |
|
|
| fish | `~/.config/fish/config.fish` | `~/.config/fish/conf.d/netssh.fish` |
|
|
|
|
The install is idempotent — running it again changes nothing if the lines are already present.
|
|
|
|
Reload your profile after installation to activate immediately:
|
|
|
|
```sh
|
|
source ~/.bashrc # bash
|
|
source ~/.zshrc # zsh
|
|
source ~/.config/fish/config.fish # fish
|
|
```
|
|
|
|
### Alias file updates
|
|
|
|
The alias file is regenerated automatically — no manual action needed:
|
|
|
|
| Event | Aliases updated |
|
|
|-------|----------------|
|
|
| New shell session (`shell-init`) | Yes — from the current local cache |
|
|
| `netssh cache refresh` | Yes — after the full refresh completes |
|
|
| Background 24h auto-refresh | Yes — after the background refresh completes |
|
|
|
|
Aliases for newly added hosts appear in the next shell session after a `cache refresh` has run.
|
|
|
|
### Uninstall
|
|
|
|
```sh
|
|
netssh hook uninstall # auto-detects $SHELL
|
|
netssh hook uninstall --shell zsh
|
|
```
|
|
|
|
Removes both the `netssh shell-init` line and the `source aliases.sh` line from the profile. The alias files (`aliases.sh`, `netssh.fish`) are left on disk — delete them manually if desired.
|
|
|
|
### Relation to the connect-time auto-refresh
|
|
|
|
The shell hook and the connect-time trigger (which fires on each `netssh` invocation) are independent but complementary:
|
|
|
|
| Trigger | When it fires |
|
|
|---------|--------------|
|
|
| SSH connect / TUI start | On the next `netssh` call after 24 h have elapsed |
|
|
| Shell hook (`shell-init`) | On the first new shell session after 24 h have elapsed |
|
|
|
|
Both are non-blocking — the refresh runs as a background process and never delays your prompt or SSH connection. They share `~/.cache/netssh/last_refresh`, so only one background refresh runs per 24-hour window regardless of how many shells or connections are opened.
|
|
|
|
## Development
|
|
|
|
Renovate monitors the release workflow's actions, the Go version in `go.mod`, and
|
|
all direct and indirect Go module dependencies. Go dependency updates also run
|
|
`go mod tidy` to keep `go.mod` and `go.sum` consistent.
|
|
|
|
```sh
|
|
go test ./... # includes offline installer/update tests
|
|
go build ./... # build all packages
|
|
```
|
|
|
|
The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, SSH argument parser, config loading, setup wizard, shortcut normalization, and shell hook install/uninstall.
|
|
|
|
## 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 resolves the destination: first an exact cache lookup, then shortcut expansion (domain append, hyphen folding) against the cache, and finally a fresh NetBox query with the expanded name. If the cache entry is within the TTL, no network request is made.
|
|
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.
|