# ssh-connection-manager: TUI для хостов из ~/.ssh/config

Индекс LLMS: [llms.txt](/llms.txt)

---

Когда в `~/.ssh/config` десятки стендов, bastion и jump-хостов, вспоминать алиасы уже не хочется. **ssh-connection-manager** — это TUI поверх обычного OpenSSH: список хостов, фильтр, подключение штатным `ssh`, добавление новой записи в конфиг.

Команда в терминале — `ssh-connect`. Репозиторий: [gitlab.com/unsorted-projects/ssh-connection-manager](https://gitlab.com/public-projects-docff-devops/ssh-connection-manager).

## Зачем не ещё один SSH-клиент

Клиент уже есть: системный `ssh`. Нужен не новый протокол, а навигация по конфигу.

Утилита:

- читает `~/.ssh/config` или другой файл (`-c`);
- показывает только конкретные `Host`, без wildcard-шаблонов вроде `Host *`;
- учитывает `Include` (до 16 уровней вложенности);
- на `Enter` приостанавливает TUI и запускает `ssh -F <config> <alias>`;
- после выхода из сессии снова открывает список.

Под капотом Python 3.11+ и [Textual](https://textual.textualize.io/). Свой SSH-стек не пишется: ключи, `ProxyJump`, агент — всё остаётся на OpenSSH.

## Что видно в таблице

Колонки названы так, чтобы не путать алиас и адрес:

| Поле | Смысл |
| --- | --- |
| HostName | алиас из директивы `Host` |
| ConnectPoint | адрес из `HostName` в конфиге (IP или DNS) |
| User | пользователь, если задан |
| Port | порт или `22` по умолчанию |

В строке деталей — `IdentityFile` и `ProxyJump`, если они есть. Если у хоста нет `User` (и его нет в `Host *`), перед подключением спрашивается имя.

Фильтр (`/`) ищет по алиасу и ConnectPoint.

## Клавиши

| Клавиша | Действие |
| --- | --- |
| `Enter` | подключиться |
| `a` | добавить хост в конфиг |
| `/` | фильтр |
| `q` | выход |

Добавление **дописывает** блок в файл, существующие секции не перезаписываются. Если файла ещё нет, он создаётся с правами `0600`. Wildcard в имени хоста не принимаются: в список попадают только явные алиасы.

Пример того, что попадёт в конфиг:

```sshconfig
Host prod
    HostName 10.0.0.5
    User deploy
    Port 22
    IdentityFile ~/.ssh/id_ed25519
```

## Установка

На Debian/Ubuntu пакет нельзя ставить в системный Python (`externally-managed-environment`). Нужен venv или pipx.

```bash
git clone git@gitlab.com:unsorted-projects/ssh-connection-manager.git
cd ssh-connection-manager
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```

Дальше команда `ssh-connect` есть в активированном venv. Чтобы вызывать её из любого каталога:

```bash
mkdir -p ~/.local/bin
ln -sf "$(pwd)/.venv/bin/ssh-connect" ~/.local/bin/ssh-connect
```

Либо `pipx install -e .` — pipx сам изолирует окружение и кладёт бинарник в `~/.local/bin`.

Нужен интерактивный TTY: без терминала Textual не сможет «отдать» экран клиенту `ssh`.

```bash
ssh-connect
ssh-connect -c /path/to/other/config
```

> [!NOTE]
> Утилита не редактирует чужие блоки конфига и не трогает `Match`. В список попадают только именованные `Host` без `*?[`.

## Что это даёт в работе

Один конфиг — источник правды. TUI не дублирует inventory в YAML и не хранит пароли: только то, что уже лежит в OpenSSH. Для Lead DevOps это привычный контур: bastion, prod, jump — выбираешь строку и сразу в сессии.
