docs: add v0.4.0 workflow guide and release notes
This commit is contained in:
parent
db25f9011b
commit
0151076ca9
38
README.md
38
README.md
|
|
@ -22,11 +22,11 @@ port forwarding management.
|
|||
- Password and key-passphrase auth through a PTY prompt handler, without putting
|
||||
secrets in command-line arguments.
|
||||
- Key, SSH-agent, password, and key+passphrase auth modes.
|
||||
- **Routes / ProxyJump** — manage bastion hosts and jump chains with human-readable display.
|
||||
- **Routes / ProxyJump** — ordered bastion chains with stable references to sshkeeper profiles; profile renames do not break routes.
|
||||
- **Port forwarding** — named local/remote/SOCKS forwards with type selector, validation, and OpenSSH preview.
|
||||
- **Tunnel management** — start/stop/list background tunnels, PID tracking, runtime state.
|
||||
- **Tunnel vs Forward** — clear separation: forward = saved rule, tunnel = running SSH process.
|
||||
- Groups, tags, command templates, search by metadata/routes/forward ports, and OpenSSH config generation.
|
||||
- First-class groups, multi-select tags, command templates, search by metadata/routes/forward ports, and OpenSSH config generation.
|
||||
- Import from `~/.ssh/config` and simple tab-separated export.
|
||||
|
||||
## Install
|
||||
|
|
@ -66,11 +66,11 @@ Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
|
|||
- Primary public repository: [github.com/mirivlad/sshkeeper](https://github.com/mirivlad/sshkeeper)
|
||||
- Self-hosted mirror: `git@git.mirv.top:mirivlad/sshkeeper`
|
||||
|
||||
### Install from release (after v0.2.0 publication)
|
||||
### Install from release
|
||||
|
||||
```bash
|
||||
tar -xzf sshkeeper_v0.2.0_linux_amd64.tar.gz
|
||||
sudo install -m 0755 sshkeeper_v0.2.0_linux_amd64/sshkeeper /usr/local/bin/sshkeeper
|
||||
tar -xzf sshkeeper_v0.4.0_linux_amd64.tar.gz
|
||||
sudo install -m 0755 sshkeeper_v0.4.0_linux_amd64/sshkeeper /usr/local/bin/sshkeeper
|
||||
sshkeeper
|
||||
```
|
||||
|
||||
|
|
@ -140,7 +140,8 @@ it to DEL (in xterm, `backarrowKey: false`).
|
|||
| Ctrl+E | Edit server |
|
||||
| Ctrl+F | Search |
|
||||
| Ctrl+W | Manage port forwards for selected server |
|
||||
| Ctrl+X | Action menu (connect, tunnels, forwards, route, test, edit, delete, import/export, vault actions) |
|
||||
| Ctrl+X | Server actions (connect, tunnels, forwards, route, test, edit, delete) |
|
||||
| m | Manage groups, tags, command templates, running tunnels, import/export, and vault |
|
||||
| Ins | Select / deselect a server |
|
||||
| ? | Quick help (hotkeys) |
|
||||
| Ctrl+H | Full documentation |
|
||||
|
|
@ -157,12 +158,25 @@ In add/edit forms:
|
|||
|-----|--------|
|
||||
| Tab / Down | Next field |
|
||||
| Shift+Tab / Up | Previous field |
|
||||
| `/` on Auth Method or Group | Pick from list |
|
||||
| `/` on Auth, Identity File, Route, Group, Startup Command, or Tags | Open the relevant picker/editor |
|
||||
| Enter | Move to action / activate |
|
||||
| Esc | Back |
|
||||
|
||||
## Routes, Tunnels, and Port Forwards
|
||||
|
||||
Routes are stored as ordered hops. If a hop matches an existing sshkeeper profile,
|
||||
sshkeeper stores a stable reference to that profile ID, not the mutable alias. The
|
||||
connection planner resolves the profile's real host/user/port/key and writes a
|
||||
temporary OpenSSH config for the session, so a sshkeeper bastion does **not** need
|
||||
a matching `Host` entry in `~/.ssh/config`.
|
||||
|
||||
Use `profile:<alias>` to require a profile reference and `raw:<target>` to require
|
||||
a literal OpenSSH jump target. An unprefixed exact known alias is treated as a
|
||||
profile; any other value remains a raw target.
|
||||
|
||||
In the TUI, `/` on Route opens the ordered route editor: `Enter` adds a profile,
|
||||
`x`/Delete removes a hop, and `[`/`]` moves it.
|
||||
|
||||
### Jump host (single bastion)
|
||||
|
||||
```bash
|
||||
|
|
@ -248,11 +262,11 @@ key-passphrase authentication so the PTY prompt handler can provide the secret.
|
|||
| Action | Command | TUI | Description |
|
||||
|--------|---------|-----|-------------|
|
||||
| Connect | `sshkeeper connect <alias>` | `Enter` | Standard SSH session, no port forwards |
|
||||
| Connect with tunnels | `sshkeeper tunnel <alias>` | Action menu → Connect with tunnels | SSH session with all enabled forwards active |
|
||||
| Start tunnels only | `sshkeeper tunnel <alias> --forward-only` | Action menu → Start tunnels only | Foreground tunnel, no shell |
|
||||
| Start tunnels in background | `sshkeeper tunnel <alias> --background` | Action menu → Start tunnels in background | Detached tunnel process with PID tracking |
|
||||
| Manage port forwards | `sshkeeper forward` | Action menu → Manage port forwards | Add/edit/delete forward rules |
|
||||
| Manage tunnels | `sshkeeper tunnel list/stop/stop-all` | Action menu → Manage tunnels | View running tunnels and stop them |
|
||||
| Connect with tunnels | `sshkeeper tunnel <alias>` | Server Actions → Connect with tunnels | SSH session with all enabled forwards active |
|
||||
| Start tunnels only | `sshkeeper tunnel <alias> --forward-only` | Server Actions → Start tunnels only | Foreground tunnel, no shell |
|
||||
| Start tunnels in background | `sshkeeper tunnel <alias> --background` | Server Actions → Start tunnels in background | Detached tunnel process with PID tracking |
|
||||
| Port forwards | `sshkeeper forward` | Server Actions → Port forwards (or `Ctrl+W`) | Add/edit/enable/delete forward rules |
|
||||
| Running tunnels | `sshkeeper tunnel list/stop/stop-all` | `m` → Running tunnels | View tracked/running tunnels and stop them |
|
||||
|
||||
## Vault
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,8 @@ Auth: agent Group: - Status: ?
|
|||
| `Enter` | Подключиться к серверу |
|
||||
| `Ctrl+A` | Добавить сервер |
|
||||
| `Ctrl+E` | Редактировать сервер |
|
||||
| `Ctrl+X` | Меню действий |
|
||||
| `Ctrl+X` | Действия выбранного сервера |
|
||||
| `m` | Глобальное меню Manage |
|
||||
| `Ctrl+F` | Поиск |
|
||||
| `Ins` | Выбрать/снять выбор |
|
||||
| `?` | Краткая справка по клавишам |
|
||||
|
|
@ -201,7 +202,8 @@ sshkeeper — Quick Help
|
|||
Ctrl+A Add server
|
||||
Ctrl+E Edit server
|
||||
Ctrl+F Search
|
||||
Ctrl+X Action menu
|
||||
Ctrl+X Server actions
|
||||
m Manage
|
||||
Ins Select / deselect
|
||||
|
||||
Port forwards
|
||||
|
|
@ -252,7 +254,8 @@ sshkeeper — Full Help
|
|||
Ctrl+A Add server
|
||||
Ctrl+E Edit server
|
||||
Ctrl+F Search
|
||||
Ctrl+X Action menu
|
||||
Ctrl+X Server actions
|
||||
m Manage
|
||||
Ins Select / deselect
|
||||
|
||||
...
|
||||
|
|
@ -287,7 +290,7 @@ Add Server
|
|||
User: root
|
||||
Auth Method: key
|
||||
Identity File: ~/.ssh/id_ed25519
|
||||
Route hops: bastion
|
||||
Route: profile:bastion
|
||||
Group: KP
|
||||
Notes: Main mail server
|
||||
Startup Command: tmux attach -t ops
|
||||
|
|
@ -311,8 +314,12 @@ Add Server
|
|||
|---------|----------|
|
||||
| `Tab` или `↓` | Следующее поле |
|
||||
| `Shift+Tab` или `↑` | Предыдущее поле |
|
||||
| `/` на Auth Method | Выбрать из списка (password/key/key_passphrase/agent) |
|
||||
| `/` на Group | Выбрать из существующих групп |
|
||||
| `/` на Auth Method | Выбрать password/key/key_passphrase/agent |
|
||||
| `/` на Identity File | Выбрать приватный ключ из `~/.ssh` |
|
||||
| `/` на Route | Открыть редактор цепочки бастионов |
|
||||
| `/` на Group | Выбрать существующую группу |
|
||||
| `/` на Startup Command | Скопировать команду из глобального шаблона |
|
||||
| `/` на Tags | Multi-select существующих тегов; новые можно ввести вручную |
|
||||
| `Enter` на Test | Проверить подключение |
|
||||
| `Enter` на Save | Сохранить |
|
||||
| `Esc` | Назад; при изменённых данных сначала запросить подтверждение сброса |
|
||||
|
|
@ -378,9 +385,16 @@ ROUTE: ⇒ bastion → dmz-gw → … → root@secure.internal:22
|
|||
### Настройка маршрута
|
||||
|
||||
**Через TUI:**
|
||||
1. Добавьте/редактируйте сервер или выберите `Ctrl+X` → "Manage route"
|
||||
2. В поле "Route hops" введите бастионы через запятую: `bastion,dmz-gw`
|
||||
3. Или введите адрес напрямую: `user@bastion.example.com:2222`
|
||||
1. Добавьте/редактируйте сервер или выберите `Ctrl+X` → **Route**.
|
||||
2. Нажмите `/` на поле Route — откроется список существующих профилей.
|
||||
3. `Enter` добавляет выбранный профиль в ordered chain, `x`/Delete удаляет hop, `[`/`]` меняет порядок.
|
||||
4. Для произвольной OpenSSH-цели оставьте escape hatch в поле: `raw:user@bastion.example.com:2222`.
|
||||
|
||||
Ссылка на профиль хранится по стабильному ID. Переименование alias бастиона не
|
||||
ломает зависимые маршруты, а удалить используемый бастион sshkeeper не даст,
|
||||
пока он присутствует в route других серверов. Во время подключения profile-hop
|
||||
разрешается из БД sshkeeper; отдельная запись с тем же alias в `~/.ssh/config`
|
||||
не требуется.
|
||||
|
||||
**Через CLI:**
|
||||
|
||||
|
|
@ -413,7 +427,7 @@ sshkeeper route clear web
|
|||
### Управление forwards через TUI
|
||||
|
||||
1. Выберите сервер на главном экране
|
||||
2. Нажмите `Ctrl+X` → "Manage port forwards"
|
||||
2. Нажмите `Ctrl+X` → **Port forwards**
|
||||
3. Откроется список forwards:
|
||||
|
||||
```
|
||||
|
|
@ -426,7 +440,7 @@ Selected
|
|||
Port 127.0.0.1:15432 on this machine will be forwarded through web to 127.0.0.1:5432.
|
||||
ssh -L 127.0.0.1:15432:127.0.0.1:5432
|
||||
|
||||
Ctrl+A: add | Ctrl+E/Enter: edit | Ctrl+D: delete | Esc: back
|
||||
Ctrl+A: add | Ctrl+E/Enter: edit | Space: enable/disable | Ctrl+D: delete | Esc: back
|
||||
```
|
||||
|
||||
Строки и пояснение выбранного forward сокращаются по экранным ячейкам, а не
|
||||
|
|
@ -438,6 +452,7 @@ Selected
|
|||
|---------|----------|
|
||||
| `Ctrl+A` | Добавить forward |
|
||||
| `Enter` или `Ctrl+E` | Редактировать выбранный |
|
||||
| `Space` | Включить/выключить правило |
|
||||
| `Ctrl+D` | Удалить (с подтверждением) |
|
||||
| `Esc` | Назад |
|
||||
|
||||
|
|
@ -514,7 +529,7 @@ forward и сейчас поддерживает только `key` или `agen
|
|||
### Управление туннелями
|
||||
|
||||
**Через TUI:**
|
||||
1. Нажмите `Ctrl+X` → "Manage tunnels"
|
||||
1. Нажмите `m` → **Running tunnels**
|
||||
2. Список запущенных туннелей:
|
||||
|
||||
```
|
||||
|
|
@ -730,7 +745,7 @@ sshkeeper connect secure
|
|||
|
||||
```bash
|
||||
# В TUI: выбрать несколько серверов (Ins), затем:
|
||||
# Ctrl+X → Run template → выбрать шаблон
|
||||
# Ctrl+R → выбрать шаблон
|
||||
# Команда выполнится на всех выбранных серверах
|
||||
```
|
||||
|
||||
|
|
@ -746,13 +761,14 @@ sshkeeper connect secure
|
|||
| `Ctrl+A` | Добавить сервер |
|
||||
| `Ctrl+E` | Редактировать сервер |
|
||||
| `Ctrl+F` | Поиск |
|
||||
| `Ctrl+X` | Меню действий |
|
||||
| `Ctrl+X` | Действия выбранного сервера |
|
||||
| `m` | Глобальное меню Manage |
|
||||
| `Ins` | Выбрать/снять выбор |
|
||||
| `?` | Краткая справка по клавишам |
|
||||
| `Ctrl+H` | Полная справка по приложению |
|
||||
| `Ctrl+Q` | Выход |
|
||||
|
||||
### Меню действий (Ctrl+X)
|
||||
### Действия сервера (Ctrl+X)
|
||||
|
||||
| Действие | Описание |
|
||||
|----------|----------|
|
||||
|
|
@ -760,13 +776,21 @@ sshkeeper connect secure
|
|||
| Connect with tunnels | SSH + все активные forwards |
|
||||
| Start tunnels only | Туннель без shell |
|
||||
| Start tunnels in background | Фоновый туннель |
|
||||
| Manage port forwards | Управление forwards |
|
||||
| Manage tunnels | Список туннелей |
|
||||
| Manage route | Настройка маршрута |
|
||||
| Port forwards | Управление forwards выбранного сервера |
|
||||
| Route | Ordered chain бастионов выбранного сервера |
|
||||
| Test connection | Проверка подключения |
|
||||
| Edit | Редактирование сервера |
|
||||
| Delete | Удаление (с подтверждением) |
|
||||
| Import | Импорт из `~/.ssh/config` и обновление списка |
|
||||
|
||||
### Manage (`m`)
|
||||
|
||||
| Действие | Описание |
|
||||
|----------|----------|
|
||||
| Groups | Создание, переименование и удаление групп с количеством серверов |
|
||||
| Tags | Управление тегами |
|
||||
| Command templates | Глобальные шаблоны команд |
|
||||
| Running tunnels | Список и остановка фоновых туннелей |
|
||||
| Import SSH config | Импорт из `~/.ssh/config` |
|
||||
| Export | Выход в терминал и печать экспорта |
|
||||
| Vault: lock | Заблокировать vault в текущем процессе |
|
||||
| Vault: change password | Выход в терминал и смена master password |
|
||||
|
|
@ -777,7 +801,7 @@ sshkeeper connect secure
|
|||
|---------|----------|
|
||||
| `Tab` / `↓` | Следующее поле |
|
||||
| `Shift+Tab` / `↑` | Предыдущее поле |
|
||||
| `/` | Выбрать из списка (Auth Method, Group) |
|
||||
| `/` | Открыть picker/editor для Auth, key, Route, Group, Startup Command или Tags |
|
||||
| `Enter` | Действие / переход |
|
||||
| `Esc` | Назад / отмена |
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
# sshkeeper v0.4.0 — Model & Workflow Cleanup
|
||||
|
||||
v0.4.0 is a structural release. The main goal is to make sshkeeper's data model
|
||||
match what the user sees: server profiles are real reusable objects, routes
|
||||
reference those objects instead of mutable text, and the TUI offers pickers for
|
||||
things that already exist instead of asking you to retype them.
|
||||
|
||||
Existing databases and vaults are migrated automatically. No manual conversion
|
||||
is required.
|
||||
|
||||
## Routes are now real relationships
|
||||
|
||||
The old implementation stored both `ProxyJump` text and a second route
|
||||
representation. Different commands wrote different fields, and runtime SSH used
|
||||
one in preference to the other. That made it possible for `edit --proxy-jump` to
|
||||
say "Saved" while the old structured route was still used.
|
||||
|
||||
v0.4.0 makes `Route` canonical and stores profile hops in a normalized
|
||||
`server_route_hops` table with foreign keys to stable server IDs.
|
||||
|
||||
- Renaming a bastion no longer breaks dependent routes.
|
||||
- Deleting a profile that is still used as a route hop is rejected and names
|
||||
the dependent profiles.
|
||||
- Self references, duplicate hops and route cycles are rejected.
|
||||
- `proxy_jump` and legacy `route_hops` remain compatibility projections for old
|
||||
databases/tools, not competing sources of truth.
|
||||
- Existing `group_name` strings are likewise migrated to first-class `groups`
|
||||
with stable IDs.
|
||||
|
||||
### Profile hops no longer depend on `~/.ssh/config`
|
||||
|
||||
A route hop that references a sshkeeper profile now resolves that profile's real
|
||||
host, user, port and identity file from SQLite. sshkeeper generates a temporary
|
||||
OpenSSH config for the connection and passes it with `ssh -F`.
|
||||
|
||||
This fixes the old accidental requirement that a sshkeeper alias such as
|
||||
`bastion-prod` also had to exist as a matching `Host` in the user's OpenSSH
|
||||
config.
|
||||
|
||||
CLI route syntax is explicit when needed:
|
||||
|
||||
```bash
|
||||
# exact known aliases are profile references
|
||||
sshkeeper route set prod --jumps bastion,dmz-gw
|
||||
|
||||
# force the interpretation
|
||||
sshkeeper route set prod --jumps profile:bastion,raw:ops@external-gw:2222
|
||||
```
|
||||
|
||||
An unprefixed value matching an existing sshkeeper alias becomes a profile hop;
|
||||
an unknown value remains a raw OpenSSH target.
|
||||
|
||||
Password or key-passphrase authentication on an *intermediate* profile hop is
|
||||
rejected with a clear error for now. The current PTY secret flow can safely feed
|
||||
the target profile, but it cannot reliably route different vault secrets to
|
||||
multiple OpenSSH prompts in a jump chain. Key/agent bastions are supported.
|
||||
|
||||
## Route editor in the TUI
|
||||
|
||||
`Ctrl+X` → **Route**, or `/` while the Route field is focused, opens an ordered
|
||||
route editor.
|
||||
|
||||
- `Enter` adds an existing server profile as a hop.
|
||||
- `x` / Delete removes a hop.
|
||||
- `[` / `]` moves a hop up/down in the chain.
|
||||
- `/` filters the available profiles.
|
||||
- `raw:<target>` remains available in the editable field for arbitrary OpenSSH
|
||||
targets.
|
||||
|
||||
The server form no longer claims that a picker exists while still requiring a
|
||||
comma-separated string.
|
||||
|
||||
## Server Actions vs Manage
|
||||
|
||||
`Ctrl+X` is now strictly about the selected server:
|
||||
|
||||
- Connect
|
||||
- Connect with tunnels
|
||||
- Start tunnels only / in background
|
||||
- Port forwards
|
||||
- Route
|
||||
- Test connection
|
||||
- Edit
|
||||
- Delete
|
||||
|
||||
Press **`m`** for global management:
|
||||
|
||||
- Groups
|
||||
- Tags
|
||||
- Command templates
|
||||
- Running tunnels
|
||||
- Import SSH config
|
||||
- Export
|
||||
- Vault lock / password change
|
||||
|
||||
Groups now have their own manager with server counts, create/rename/delete
|
||||
operations, and safe delete consequences.
|
||||
|
||||
## Context-aware server form
|
||||
|
||||
The form now exposes only authentication fields that matter:
|
||||
|
||||
| Auth | Fields |
|
||||
|------|--------|
|
||||
| password | Password |
|
||||
| key | Identity File |
|
||||
| key_passphrase | Identity File + Key passphrase |
|
||||
| agent | no credential fields |
|
||||
|
||||
`/` opens context-specific pickers:
|
||||
|
||||
- Auth method → auth list
|
||||
- Identity File → detected private keys in `~/.ssh`
|
||||
- Route → profile/chain editor
|
||||
- Group → existing groups
|
||||
- Startup Command → global command templates (the command is copied, not linked)
|
||||
- Tags → multi-select existing tags; new tags can still be typed manually
|
||||
|
||||
## CLI consistency fixes
|
||||
|
||||
All writers now go through the same route semantics.
|
||||
|
||||
- `add`, `edit`, `route set`, TUI save and SSH config import all create the same
|
||||
canonical route model.
|
||||
- SSH config import is two-pass: profiles are created first, then `ProxyJump`
|
||||
aliases are resolved against the complete imported/existing profile set.
|
||||
- `edit` uses Cobra's `Changed()` state, so `--group ''`, `--notes ''`,
|
||||
`--startup-command ''`, `--identity-file ''`, `--proxy-jump ''` and
|
||||
`--tags ''` can actually clear values.
|
||||
- An empty server `User` no longer produces the invalid target `@host`; OpenSSH
|
||||
is allowed to choose its configured/current user.
|
||||
- Shared server/auth/route validation replaced duplicated partial checks.
|
||||
|
||||
## Vault identity follows the server, not its alias
|
||||
|
||||
New and migrated server secrets are stored under stable server IDs. Renaming a
|
||||
profile no longer requires a risky copy/delete of secrets keyed by alias.
|
||||
|
||||
Legacy `server:<alias>:<type>` records remain readable and are lazily migrated
|
||||
when used. `vault list` understands both legacy and stable-ID records and
|
||||
resolves stable IDs back to current aliases when the database is available.
|
||||
|
||||
TUI server save now commits the database change before rewriting vault state;
|
||||
if the vault step fails, the profile/tags are rolled back instead of leaving the
|
||||
database and vault disagreeing.
|
||||
|
||||
## Port forward fixes
|
||||
|
||||
Two concrete TUI bugs are fixed:
|
||||
|
||||
- Editing a disabled forward no longer silently re-enables it.
|
||||
- Remote-forward preview now uses the same semantic builder as validation/save,
|
||||
so listen/target endpoints cannot be shown reversed.
|
||||
|
||||
The editor has an explicit Enabled toggle and the forward list supports `Space`
|
||||
to enable/disable a rule quickly.
|
||||
|
||||
## Tunnel fixes
|
||||
|
||||
Profile routes work consistently for foreground and background tunnels.
|
||||
Background tunnels keep their generated temporary SSH config for the lifetime of
|
||||
the process and remove it on stop/stop-all.
|
||||
|
||||
Tunnel Manager now reports `running` separately from `tracked`; stale tracked
|
||||
state is no longer counted as a running process.
|
||||
|
||||
## Cleanup
|
||||
|
||||
- Removed the stale per-server `CommandTemplate.ServerID` field; command
|
||||
templates are global.
|
||||
- Removed an unused legacy `model.Secret` type; the encrypted vault has its own
|
||||
actual storage model.
|
||||
- Added regression coverage for stable route references, deletion protection,
|
||||
cycle detection, stable-ID vault metadata, contextual auth fields, Manage,
|
||||
route/identity/tag/startup pickers, and forward semantics.
|
||||
|
||||
## Upgrade notes
|
||||
|
||||
On first start, v0.4.0 automatically creates `groups` and
|
||||
`server_route_hops`, links existing group names, and converts existing route
|
||||
text/JSON. The old columns are retained for compatibility.
|
||||
|
||||
As always, keep a copy of `~/.local/share/sshkeeper/` before a major upgrade if
|
||||
the data matters to you.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
tar -xzf sshkeeper_v0.4.0_linux_amd64.tar.gz
|
||||
sudo install -m 0755 sshkeeper_v0.4.0_linux_amd64/sshkeeper /usr/local/bin/sshkeeper
|
||||
```
|
||||
|
||||
Verify downloads against `checksums.txt`. Linux and macOS are the primary
|
||||
release targets. Windows remains experimental and requires OpenSSH Client
|
||||
(`ssh.exe`) in `PATH`.
|
||||
Loading…
Reference in New Issue