README : couvrir les 14 phases precedentes, mettre en avant la confidentialite

Le README ne decrivait encore que les toutes premieres fonctionnalites
(sessions, tunnels -L/-R, SFTP, terminaux locaux, cles, known_hosts) : rien
sur ~/.ssh/config, ProxyJump, le SOCKS dynamique, le keepalive/reconnexion
automatique, le terminal divise, les workspaces, les snippets, les tags/
groupes, le coffre-fort d'identifiants ni l'assistant IA.

Reecriture complete en gardant le ton et la structure d'origine (description
concrete, raccourcis clavier, "pourquoi" plutot que juste "quoi") :
  - Nouveau chapeau explicite : aucun compte cloud, aucune telemetrie, les
    identifiants restent locaux, l'IA est entierement optionnelle.
  - Fonctionnalites reorganisees par theme (terminal / connexion et auth /
    organisation / SFTP / cles et secrets / assistant IA), chaque nouvelle
    fonctionnalite decrite avec le menu ou bouton exact pour y acceder -
    verifie contre le code plutot que suppose.
  - "Structure du projet" reecrite pour refleter l'arborescence actuelle
    (controllers/, ui/, services/, storage/, security/, ai/, openssh/...).
  - "Tests" et nouvelle section "Qualite" mis a jour pour pytest/ruff/pyright/
    CI (Phases 13-14), en gardant la possibilite de lancer un script seul.
  - "Limites connues" mise a jour avec les limites reelles actuelles
    (ProxyJump a un seul rebond, coffre-fort Windows uniquement, socle de
    typage pyright non resorbe) plutot que celles, resolues depuis, de la
    version initiale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Florian
2026-09-05 07:50:24 +02:00
parent c39ef9c038
commit 6cceb3f3b2

240
README.md
View File

@@ -1,9 +1,17 @@
# PySSH Client
Client SSH/SFTP personnel (type MobaXterm/Termius/Bitvise), 100% local, sans compte ni service tiers.
Client SSH/SFTP personnel (type MobaXterm/Termius/Bitvise), **100% local**.
**Aucun compte requis, aucun service cloud, aucune telemetrie.** Sessions, cles, mots de passe
memorises et snippets restent dans des fichiers locaux (ou le trousseau securise de Windows) —
rien n'est jamais envoye a un serveur tiers. La seule fonctionnalite qui communique vers
l'exterieur est l'**assistant IA**, entierement optionnel, desactive par defaut, et qui n'envoie
quoi que ce soit qu'au fournisseur que *vous* configurez avec *votre propre* cle API (voir plus bas).
## Fonctionnalites
### Terminal SSH
- Sessions SSH multiples dans des onglets, avec terminal ANSI colore et trois themes
- Copier-coller **a la souris, comme dans un terminal Unix** : selectionner copie aussitot
(double-clic pour un mot), et le clic droit colle directement — ni menu, ni raccourci.
@@ -12,41 +20,114 @@ Client SSH/SFTP personnel (type MobaXterm/Termius/Bitvise), 100% local, sans com
- Confort d'affichage : zoom `Ctrl+molette` ou `Ctrl+ +/-` (`Ctrl+0` remet a zero, la taille est
memorisee), barre de defilement de l'historique, `Maj+PagePrec/Suiv`, `Ctrl+Fin` pour revenir
en direct, et recherche dans l'historique avec `Ctrl+F`
- Onglets renommables (double-clic sur l'onglet, ou clic droit) et deplaçables ;
le clic droit permet aussi de fermer les autres onglets
- Panneau des sessions redimensionnable en attrapant le separateur, et masquable entierement
(`F9`, menu Affichage, ou la croix du panneau) pour donner tout l'ecran au terminal
- **Tunnels SSH** (redirection de ports) : bouton "Tunnels" dans la barre d'un onglet SSH.
Redirection locale (`-L`) pour atteindre depuis votre poste un service qui n'ecoute que sur la
boucle locale du serveur, et redirection distante (`-R`) dans l'autre sens
- **Envoi simultane** : le bouton "⇉ Multi" du panneau lateral diffuse ce que vous tapez vers tous
les onglets terminal ouverts, pour piloter plusieurs serveurs d'un coup
- Journalisation de session dans un fichier (bouton "Journal"), sequences ANSI retirees pour rester lisible
- Reconnexion en un clic quand une session tombe (bouton dans la barre de l'onglet) : pratique
avec des serveurs de test qui redemarrent souvent
- Les hotes deja approuves par votre commande `ssh` (`~/.ssh/known_hosts`) sont reconnus : pas de
double confirmation d'empreinte. Les nouvelles cles vont dans le fichier propre a l'application
- Terminaux locaux accessibles en un clic, **sans session enregistree**. L'application detecte les
shells presents sur le poste et les propose tous : PowerShell, cmd, et surtout les **shells Unix**
s'ils sont installes (Bash de Git for Windows, MSYS2, Cygwin, WSL, ou un busybox pose a cote de
l'application). Comme le terminal local de MobaXterm, on retrouve alors `ls`, `grep`, `sed`, `awk`,
`vi`, `scp`... sous Windows. **Un shell Unix est choisi par defaut** quand il y en a un ;
sinon PowerShell. Rien n'est embarque : l'application reutilise ce qui est deja installe
- Carnet d'adresses de serveurs (JSON local, `data/sessions.json`) organise par dossiers, connexion en un clic
- Gestion des cles SSH : generation **Ed25519, ECDSA (courbes NIST P-256 / P-384 / P-521) et RSA**,
import de cles existantes, export (cle publique/privee), protection par passphrase
- Client SFTP integre facon WinSCP : double panneau local/distant avec colonnes triables (nom, taille, date, droits),
glisser-deposer entre les panneaux, renommage (F2), suppression (Suppr), creation de dossier, permissions distantes
(chmod), et file de transferts avec progression. **Aucun favori n'est necessaire pour l'utiliser** — voir ci-dessous
- **SFTP sur la connexion en cours** : depuis n'importe quel terminal ou vous avez tape `ssh user@hote` a la main, le
bouton "📁 SFTP sur cette connexion" lit l'hote, l'utilisateur et le port dans la commande saisie et ouvre le
gestionnaire de fichiers dessus. Pense pour les serveurs de test en DHCP, qu'on n'a aucune envie d'enregistrer
- **Authentification automatique** (mode par defaut) : comme la commande `ssh`, l'application utilise l'agent SSH et les
cles de `~/.ssh` sans que vous ayez a designer quoi que ce soit, et ne demande un mot de passe qu'en dernier recours
- Verification des empreintes de cles d'hote (TOFU) avant premiere connexion, comme un client SSH classique
- Gestionnaire des hotes connus (menu "Hotes connus" ou bouton "⚙" du panneau lateral) : si une adresse en DHCP change de machine, la cle d'hote presentee ne correspond plus a celle enregistree — l'application le detecte et propose de remplacer l'ancienne entree directement au moment de la connexion, sans avoir a vider le fichier `known_hosts` a la main. Le gestionnaire permet aussi un nettoyage manuel (par hote ou en une fois).
- Onglets renommables (double-clic, ou clic droit) et deplaçables ; le clic droit permet
aussi de les diviser en **2 ou 4 panneaux** (cote a cote, empiles, ou grille), de deplacer un
autre onglet ouvert dans un panneau, ou de fermer les autres onglets
- **Keepalive et reconnexion automatique** configurables par session (intervalle, nombre de
tentatives, delai avec recul progressif) : une coupure reseau n'oblige plus a rouvrir
la session et ressaisir les identifiants
- Journalisation de session dans un fichier (bouton "Journal"), sequences ANSI retirees pour
rester lisible
- Reconnexion manuelle en un clic (bouton dans la barre de l'onglet)
Aucun mot de passe n'est stocke sur le disque : l'authentification par mot de passe est demandee a chaque connexion, et les passphrases de cles sont demandees uniquement en memoire au moment de la connexion.
### Connexion et authentification
- **Authentification automatique** (mode par defaut) : comme la commande `ssh`, l'application
utilise l'agent SSH et les cles de `~/.ssh` sans que vous ayez a designer quoi que ce soit, et
ne demande un mot de passe qu'en dernier recours
- **Import de votre `~/.ssh/config`** : les `Host` deja definis (HostName, User, Port,
IdentityFile, ProxyJump, ForwardAgent...) apparaissent directement dans le panneau lateral
(section "⚙ Configuration OpenSSH"), utilisables sans les ressaisir, ou importables comme
session PySSH en un clic
- **Bastion / ProxyJump** : une session peut passer par un rebond SSH, choisi parmi vos sessions
existantes, un `Host` de `~/.ssh/config`, ou une configuration manuelle. Un groupe de sessions
peut aussi heriter d'un bastion commun (voir Groupes ci-dessous)
- **Tunnels SSH** (bouton "🔀 Tunnels" dans la barre d'un onglet SSH) : redirection locale
(`-L`, atteindre depuis votre poste un service qui n'ecoute que sur la boucle locale du
serveur), distante (`-R`), et **proxy SOCKS dynamique** (`-D`, pour faire transiter tout le
trafic d'une application par le tunnel)
- Verification des empreintes de cles d'hote (TOFU) avant premiere connexion, comme un client
SSH classique. Les hotes deja approuves par votre commande `ssh` (`~/.ssh/known_hosts`) sont
reconnus : pas de double confirmation d'empreinte
- Gestionnaire des hotes connus (menu "Hotes connus") : si une adresse en DHCP change de
machine, la cle d'hote presentee ne correspond plus a celle enregistree — l'application le
detecte et propose de remplacer l'ancienne entree directement au moment de la connexion
### Organisation
- Carnet d'adresses de serveurs (JSON local, `data/sessions.json`) organise par dossiers,
connexion en un clic
- **Tags** (plusieurs par session) avec filtre/recherche dans le panneau lateral
- **Groupes** : un dossier de sessions peut porter des parametres par defaut (utilisateur, port,
cle SSH, bastion, keepalive) via clic droit > "Parametres du groupe...". Le bouton
"↓ Heriter du groupe" du formulaire de session les reprend en pre-remplissage, sans empecher
de les modifier au cas par cas pour une session donnee
- **Workspaces** : sauvegardent l'etat complet d'une disposition de travail — onglets ouverts,
ordre, divisions et tailles de panneaux, sessions associees — et la restaurent en un clic
(menu "Workspaces", `Ctrl+Shift+W`). Une case optionnelle restaure le dernier workspace au
demarrage. **Aucun mot de passe n'est jamais stocke dans un workspace**
- **Recherche rapide** (`Ctrl+K`) : palette façon lanceur d'applications, recherche floue parmi
sessions, hotes OpenSSH, workspaces, snippets et actions, entierement au clavier
- **Snippets** : commandes enregistrees par categorie (des exemples Linux/Docker/Proxmox sont
fournis au premier lancement), gerables (creer/modifier/supprimer/rechercher) depuis le menu
"Snippets" ou le bouton "📋 Snippets" de chaque onglet. Un snippet peut etre **insere** (le
texte est ecrit, jamais valide automatiquement), **execute**, ou **execute sur tous les
onglets a la fois** via Multi-Send
- **Envoi simultane** : le bouton "⇉ Multi" du panneau lateral diffuse ce que vous tapez vers
tous les onglets terminal ouverts (y compris dans les panneaux divises), pour piloter
plusieurs serveurs d'un coup
### SFTP
- Client SFTP integre facon WinSCP : double panneau local/distant avec colonnes triables (nom,
taille, date, droits), glisser-deposer entre les panneaux, renommage (F2), suppression
(Suppr), creation de dossier, permissions distantes (chmod), et file de transferts avec
progression — le tout en arriere-plan, sans jamais geler l'interface
- **Aucun favori n'est necessaire pour l'utiliser** — trois façons d'y arriver :
- *Vous avez tape `ssh user@hote` dans un terminal* : bouton "📁 SFTP sur cette connexion"
dans la barre de l'onglet. L'hote et l'utilisateur sont deduits de la commande tapee
- *Connexion ponctuelle* : bouton "📁 SFTP" du panneau lateral, ou `Ctrl+Shift+F`
- *Session enregistree* : le panneau de fichiers est deja affiche a cote du terminal des
l'ouverture, comme dans MobaXterm ; ou clic droit > "Ouvrir en SFTP" pour un onglet dedie
### Cles et secrets
- Gestion des cles SSH : generation **Ed25519, ECDSA (courbes NIST P-256/P-384/P-521) et RSA**,
import de cles existantes, export, protection par passphrase. Sous Windows, les cles privees
generees ou importees reçoivent des permissions NTFS restreintes (ACL), equivalent du
`chmod 600` Unix
- **Coffre-fort de mots de passe optionnel** : a la creation d'une session par mot de passe, une
case "Memoriser de maniere securisee" permet de ne plus le ressaisir a chaque connexion. Le
mot de passe est alors stocke dans le **Gestionnaire d'identifiants Windows** (chiffre par
DPAPI), **jamais en clair dans un fichier de PySSH**. Sans cette case cochee (comportement par
defaut), rien n'est memorise : le mot de passe est redemande a chaque connexion, comme
aujourd'hui
### Assistant IA (optionnel, desactive par defaut)
Une aide ponctuelle pour l'administration systeme, pas un pilote automatique : **aucune commande
n'est jamais executee automatiquement**.
- **Desactive par defaut**, et sans le moindre fournisseur impose : compatible avec toute API de
type OpenAI (OpenAI, OpenRouter, un proxy interne, ou un modele local exposant la meme API) —
vous indiquez l'URL et le modele, il n'y a pas de liste figee. Se configure depuis le menu
"Assistant IA > Parametres...", avec un bouton "Tester la connexion"
- Depuis un onglet terminal, le bouton "🤖 Assistant IA" permet, sur la selection courante :
**Expliquer cette sortie**, **Diagnostiquer cette erreur**, **Proposer une solution**, ou
**Poser une question** en y ajoutant la selection comme contexte. Les reponses s'affichent
dans un panneau lateral (conversation en memoire uniquement, jamais journalisee ni ecrite sur
le disque)
- **Generer une commande** (a partir d'une description en langage naturel, sans selection
necessaire) affiche toujours la commande proposee avant tout usage, avec trois choix : la
**copier**, l'**inserer dans le terminal** (le texte est ecrit, jamais valide automatiquement),
ou **annuler**. Une commande correspondant a un motif reconnu comme destructeur (`rm -rf`,
`mkfs`, `dd`, un `DROP DATABASE`...) est signalee par un avertissement explicite
- **Avant tout envoi** au fournisseur configure : un avis de principe s'affiche une seule fois,
et chaque envoi est verifie localement a la recherche de secrets evidents (mot de passe, cle
privee, jeton d'authentification) — si quelque chose est detecte, vous choisissez de le
masquer automatiquement, de l'envoyer tel quel, ou d'annuler l'envoi
- **La cle API** passe exclusivement par le meme coffre-fort securise que les mots de passe de
session (Gestionnaire d'identifiants Windows) : jamais dans `settings.json`, jamais journalisee
## Installation (Windows)
@@ -56,7 +137,15 @@ Necessite Python 3.10+ installe sur le poste (verifiable avec `py -3 --version`)
setup.bat
```
Ce script cree un environnement virtuel local (`venv/`) et y installe les dependances (PySide6, paramiko, pyte, cryptography, pywinpty) — rien n'est installe globalement sur le poste.
Ce script cree un environnement virtuel local (`venv/`) et y installe les dependances (PySide6,
paramiko, pyte, cryptography, pywinpty) — rien n'est installe globalement sur le poste.
Pour contribuer au code (tests, lint, verification de types), installez plutot les dependances
de developpement :
```bash
venv\Scripts\pip install -r requirements-dev.txt
```
## Lancement
@@ -109,8 +198,8 @@ automatiquement sur `%APPDATA%\PySSHClient\`.
## Premiers pas
1. **Terminal local immediat** : bouton "💻 Terminal" dans le panneau lateral (ou `Ctrl+Shift+T`), ou double-clic sur "PowerShell"/"Invite de commandes" dans la section "Terminaux locaux" de l'arborescence — aucune session a creer.
2. **Nouvelle session SSH** (bouton "+ Session" ou `Ctrl+N`) : renseignez l'hote, le port, l'utilisateur et le mode d'authentification.
1. **Terminal local immediat** : bouton "💻 Terminal" dans le panneau lateral (ou `Ctrl+Shift+T`), ou double-clic sur "PowerShell"/"Invite de commandes" dans la section "💻 Terminaux locaux" de l'arborescence — aucune session a creer.
2. **Nouvelle session SSH** (bouton "+ Session" ou `Ctrl+N`) : renseignez l'hote, le port, l'utilisateur et le mode d'authentification. Vous avez deja un `~/.ssh/config` ? Ses `Host` apparaissent tout seuls dans la section "⚙ Configuration OpenSSH", inutile de les ressaisir.
3. **Cles SSH** (menu "Cles SSH > Gestionnaire de cles") : generez une nouvelle paire de cles ou importez-en une existante, puis selectionnez-la dans le formulaire de session.
4. Double-cliquez sur une session dans l'arborescence pour ouvrir un onglet terminal SSH.
5. **SFTP — trois facons d'y arriver**, selon la situation :
@@ -123,46 +212,87 @@ automatiquement sur `%APPDATA%\PySSHClient\`.
Dans tous les cas : glisser-deposer entre les deux panneaux, F2 renomme, Suppr supprime, F5 actualise, et le clic
droit sur le panneau distant donne acces aux permissions (chmod).
6. **Aller plus vite** : `Ctrl+K` ouvre une recherche rapide parmi tout ce que vous avez deja ouvert ou enregistre.
7. **Retrouver une disposition de travail** : une fois plusieurs onglets/panneaux organises a votre gout, menu
"Workspaces > Gestionnaire de workspaces..." (`Ctrl+Shift+W`) pour l'enregistrer et la rouvrir en un clic.
8. **Assistant IA** (facultatif) : menu "Assistant IA > Parametres..." pour indiquer l'URL, le modele et la cle API
d'un fournisseur compatible OpenAI. Tant que cette etape n'est pas faite, l'assistant reste inactif et
n'envoie jamais rien nulle part.
## Structure du projet
```
main.py point d'entree
app/
theme.py feuille de style "bleu nuit" + icone d'application
session_manager.py base de sessions (JSON)
key_manager.py generation/import/export de cles SSH
ssh_connection.py connexion SSH en arriere-plan (paramiko + QThread)
main_window.py fenetre principale : assemble panneau lateral, onglets, menus
session_manager.py base de sessions (JSON), tags, parametres de bastion/keepalive/reconnexion
key_manager.py generation/import/export de cles SSH, empreintes
known_hosts_manager.py gestion du fichier known_hosts (lister/retirer/remplacer une cle d'hote)
ssh_connection.py connexion SSH en arriere-plan (paramiko + QThread), bastion, keepalive
local_terminal.py terminal local Windows (PowerShell/cmd via pywinpty)
terminal_widget.py emulateur de terminal ANSI (pyte + QPainter)
sftp_panel.py client SFTP a deux panneaux
main_window.py fenetre principale (arbre de sessions + onglets)
tunnels.py tunnels SSH (redirection de ports -L / -R)
dialogs/ boites de dialogue (session, cles, hotes, tunnels, connexion)
sftp_panel.py client SFTP a deux panneaux, transferts en arriere-plan
tunnels.py tunnels SSH : redirection -L / -R et proxy SOCKS dynamique -D
bastion.py resolution d'un ProxyJump (session / Host OpenSSH / manuel)
credentials.py coffre-fort optionnel (Gestionnaire d'identifiants Windows)
workspace.py, snippets.py, persistance des workspaces, snippets et parametres de groupe
groups.py, app_settings.py
theme.py feuille de style "bleu nuit" + icone d'application
ai/ assistant IA : fournisseur, redaction de secrets, detection de
commandes dangereuses, parametres, execution en arriere-plan
controllers/ logique d'assemblage : cycle de vie des onglets, panneau des
sessions, diffusion Multi-Send, restauration des workspaces
ui/ widgets d'onglet (SSH/local/SFTP), terminal divise, panneau IA
dialogs/ boites de dialogue (session, cles, hotes, tunnels, snippets,
workspaces, groupes, recherche rapide, parametres IA...)
openssh/ lecture de ~/.ssh/config
security/ protection des cles privees (ACL NTFS sous Windows)
storage/ ecriture atomique de fichiers JSON, migration de schema
services/ logique pure sans dependance Qt (detection ~cible SSH, recherche
floue, calcul du delai de reconnexion)
resources/
theme.qss feuille de style Qt "bleu nuit"
data/
sessions.json vos serveurs enregistres (non versionne)
keys.json registre des cles connues (non versionne)
keys/ cles generees par l'application (non versionne)
known_hosts empreintes d'hotes approuvees (non versionne)
sessions.json, keys.json, vos donnees locales (non versionnees) - voir .gitignore
workspaces.json, snippets.json,
groups.json, known_hosts, keys/
tests/ suite de tests (voir "Tests" ci-dessous)
```
## Tests
```bash
tests\run_all.bat
pytest
```
(necessite `pip install -r requirements-dev.txt`). Chaque fichier `tests/test_*.py` reste aussi
executable individuellement (`python tests/test_xxx.py`), pratique pour rejouer un seul scenario
pendant le developpement.
Les tests construisent de vraies fenetres Qt sans les afficher (`QT_QPA_PLATFORM=offscreen`) et
couvrent : le copier-coller et les raccourcis du terminal, la detection de l'hote dans une commande
`ssh` tapee a la main, la logique SFTP (transferts, renommage, tri, suppression recursive) avec un
serveur simule, et la construction complete de l'application.
couvrent, entre autres : le copier-coller et les raccourcis du terminal, la detection de l'hote
dans une commande `ssh` tapee a la main, la logique SFTP (transferts, renommage, tri, suppression
recursive) avec un serveur simule, le stockage atomique et la migration de schema, la lecture de
`~/.ssh/config`, la resolution de ProxyJump, le coffre-fort d'identifiants, la detection de
secrets et de commandes dangereuses, et l'ensemble de l'assistant IA (fournisseur HTTP, panneau,
integration dans les onglets) — sans jamais faire d'appel reseau reel.
## Qualite
```bash
ruff check app main.py tests # style et erreurs courantes
pyright # verification de types (mode progressif, voir pyproject.toml)
```
Une CI Gitea Actions (`.gitea/workflows/ci.yml`) execute le lint et les tests a chaque push, et
construit la version portable sur la branche principale.
## Limites connues / pistes d'amelioration
- L'emulation de terminal couvre les usages courants (bash, vim, htop...) mais n'est pas un xterm parfaitement complet.
- Le terminal local repose sur `pywinpty` (pseudo-console Windows). Si un onglet local reste bloque sur un ecran vide, tapez une touche : le rafraichissement de la console Windows peut etre paresseux dans certains contextes (notamment les sessions Windows non interactives) et se declenche a la premiere frappe.
- Le SFTP ne propose pas encore l'edition de fichier distant en place (telecharger / modifier / renvoyer a la main).
- Pas encore d'export/import global du carnet de sessions (le fichier `data/sessions.json` peut etre copie manuellement).
- Le ProxyJump ne gere qu'un seul rebond pour l'instant (pas de chainage de plusieurs bastions).
- Le coffre-fort d'identifiants (mots de passe de session, cle API IA) repose sur le Gestionnaire d'identifiants Windows : pas d'equivalent sur Linux/macOS pour l'instant, l'application fonctionne mais sans memorisation securisee sur ces systemes.
- L'application est concue et testee pour Windows uniquement (pywinpty, ACL NTFS, Gestionnaire d'identifiants).
- La verification de types (`pyright`) est volontairement en mode progressif : un socle de signalements existe encore dans `app/ui/tabs.py` et `app/ssh_connection.py` (voir `pyproject.toml`), a resorber au fil du temps plutot que d'un bloc.