Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Typecheck
run: pnpm run typecheck

- name: Lint
run: pnpm run lint

Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,6 @@ vite.config.ts.timestamp-*
.pnpm-store/

# CLI credentials (per-user, not versioned)
.dev-auth-fetcher/
.dev-auth-fetcher/
# Ancien fichier de config local (désormais dans ~/.dev-auth-fetcher/config.json)
config/app.config.json
57 changes: 57 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Projet

`dev-auth-fetcher` — CLI Node/TypeScript qui s'authentifie sur un environnement de recette Edifice (ENT) et injecte les cookies de session (`VITE_XSRF_TOKEN`, `VITE_ONE_SESSION_ID`, `VITE_RECETTE`) dans les fichiers `.env` des frontends Vite locaux. Permet de pointer un front local sur un backend de recette sans relogin manuel.

## Stack

- **Node >= 24**, projet **ESM** (`"type": "module"`) — tous les imports internes portent l'extension `.js` (résolution NodeNext), même depuis des sources `.ts`.
- **pnpm** (gestionnaire de paquets).
- **commander** (CLI), **inquirer** (prompts interactifs), **ora** (spinners), **chalk** (couleurs).
- **tsup** pour le build, **tsx** pour l'exécution en dev, **vitest** pour les tests, **eslint** + **prettier**.

## Commandes

```bash
pnpm install
pnpm run dev <command> # exécute via tsx sans build (ex: pnpm run dev connect)
pnpm run build # bundle ESM dans dist/ via tsup
pnpm start # node dist/index.js (après build)
pnpm run typecheck # tsc --noEmit sur src + tests (tsconfig.typecheck.json)
pnpm test # vitest run (une passe). Un seul fichier : pnpm test tests/utils/envFile.test.ts
pnpm run test:watch # vitest en mode watch
pnpm run lint # eslint sur src/ et tests/
pnpm run format # prettier --write
pnpm run format:check
```

> Le build (tsup) type via `tsconfig.json` (src uniquement). `pnpm run typecheck` couvre **aussi** `tests/` via `tsconfig.typecheck.json` — c'est là que les erreurs de type des tests sont détectées (CI : typecheck → lint → format:check → test).

Le binaire (`bin/dev-auth-fetcher`) charge `dist/index.js` : il faut **builder avant** de lancer via `node bin/...`. Commandes CLI : `onboard`, `connect`, `list-apps`, `reconnect-last` (voir README pour les options).

## Architecture

Flux en couches, du plus haut au plus bas niveau :

- **`src/cli/`** — entrée commander (`index.ts`) et `commands/` : chaque commande délègue à un service.
- **`src/services/`** — orchestrateurs. `EnvSyncService` pilote `connect` (choix env → apps → identifiant → auth → écriture .env) ; `OnboardingService` pilote `onboard`.
- **`src/steps/`** — étapes interactives réutilisables (prompts inquirer), regroupées par parcours (`connect/`, `onboarding/`). Les services composent ces steps.
- **`src/core/`** — logique métier sans I/O interactif :
- `auth/` — `IAuthClient` + `FetchAuthClient` : POST `x-www-form-urlencoded` sur `<envUrl>/auth/login` avec `redirect: 'manual'` et timeout (`AbortController`), parse les `Set-Cookie`. Valide `authenticated=true` puis extrait `XSRF-TOKEN` (URL-décodé) et `oneSessionId`. Injecté dans `EnvSyncService` (constructeur) → service testable sans réseau.
- `env/EnvManager` — applique le patch de cookies aux `.env`, **en préservant les variables existantes**.
- `apps/AppDiscovery` — scanne `appsRoot` ; détecte **4 schémas** : `<app>/frontend`, `<app>/` directe (`.env` + `package.json` sans sous-dossier `frontend`), `entcore/<app>/frontend`, et `entcore/<app>/src/main/ts` (id = `entcore/<app>`).
- **`src/config/`** — `appConfig` (`~/.dev-auth-fetcher/config.json` : `appsRoot`, `defaultEnvironment`), `envConfigs` (environnements dans `~/.dev-auth-fetcher/environments/`, seedés depuis `DEFAULT_ENVIRONMENTS` — source partagée versionnée dans le code), `credentialsStore` (profils + historique des connexions récentes, **par utilisateur**, dans `~/.dev-auth-fetcher/credentials/`), `config.types.ts` (types + `VITE_ENV_KEYS`).
- **`src/utils/`** — `envFile` (parse/merge/write `.env`), `paths` (helpers cross-platform), `logger`, classes d'erreurs (`errors.ts`).

## Conventions & points de vigilance

- **Cross-platform** (macOS / Linux / Windows) : toujours passer par `path.join`/`path.resolve` (helpers dans `utils/paths.ts`), jamais de `/` concaténé en dur.
- **Données utilisateur centralisées hors du repo** : config + credentials vivent dans `~/.dev-auth-fetcher/` (`config.json` + `credentials/<user>.json`), surchargeable via `DEV_AUTH_FETCHER_HOME` (`getUserDataDir` dans `utils/paths.ts`). `<user>` = `DEV_AUTH_USER` ?? `os.userInfo().username`. `loadAppConfig`/`loadUserCredentialsStore` migrent une fois les anciens emplacements relatifs au cwd (`config/app.config.json`, `./.dev-auth-fetcher/`). Ne jamais logger de mot de passe.
- **Préserver les `.env` cibles** : `updateAppEnv` re-merge l'existant ; seules les clés `VITE_*` (cf. `VITE_ENV_KEYS`) sont écrasées, avec des commentaires d'en-tête (login + date).
- **Erreurs typées** : lever les classes de `utils/errors.ts` (`AuthError`, `AppConfigError`, `EnvFileError`, `AppDiscoveryError`) plutôt que des `Error` nus.
- **Imports** : règle eslint `import/order` (groupes triés, `newlines-between: always`). Prettier : `singleQuote: true`, `semi: true`, `printWidth: 100`.
- **Tests** dans `tests/`, miroir de `src/`, alias `@` → `src` (cf. `vitest.config.ts`). `tsconfig` exclut `tests` du build.
- **Tout l'état runtime vit dans `~/.dev-auth-fetcher/`** (config + credentials + environments) → la CLI est **indépendante du `process.cwd()`** et fonctionne en install global, pas seulement depuis la racine du repo. La liste partagée d'environnements est versionnée **dans le code** (`DEFAULT_ENVIRONMENTS`) et seedée vers le dossier utilisateur ; `listEnvironments` seede au premier usage (migration unique de l'ancien `config/environments/` si présent, sinon défauts du code).
49 changes: 37 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pnpm run dev onboard
node bin/dev-auth-fetcher onboard
```

Vous serez invité à saisir le chemin du répertoire contenant vos applications : soit des dossiers `<app>/frontend` à la racine, soit (ou en plus) un sous-dossier `entcore` avec des apps `entcore/<app>/frontend`. Les fichiers dans `config/environments/` (recette-ode1, recette-ode2, recette-release, local) sont créés par défaut.
Vous serez invité à saisir le chemin du répertoire contenant vos applications : soit des dossiers `<app>/frontend` à la racine, soit (ou en plus) un sous-dossier `entcore` avec des apps `entcore/<app>/frontend`. Les environnements par défaut (recette-ode1…ode4, recette-release, local) sont seedés dans `~/.dev-auth-fetcher/environments/`.

### Connexion et injection des cookies

Expand All @@ -60,8 +60,14 @@ Options de la commande `connect` :
- `-a, --app <name>` : nom ou id d'application (ex. `mon-app` ou `entcore/mediacentre` pour une app sous entcore)
- `--all` : cibler toutes les applications détectées
- `-l, --login <login>` : login utilisateur (sinon demandé en interactif)
- `--watch` : maintenir la session vivante par keep-alive (voir [Mode watch](#mode-watch--watch))
- `--watch-interval <minutes>` : intervalle des pings keep-alive (défaut 2)

Lors du premier `connect` pour un environnement, vous saisissez **login**, **mot de passe** et éventuellement un **rôle** (ex. Enseignant, Élève) pour identifier le compte. Après une connexion réussie, ces informations sont enregistrées. Aux connexions suivantes pour le même environnement, vous pouvez choisir un identifiant déjà enregistré (affiché avec le rôle entre parenthèses) ou « Nouvel identifiant ». Les credentials sont stockés par environnement et par utilisateur dans un fichier **non versionné** (voir [Structure des fichiers](#structure-des-fichiers)).
Lors du premier `connect` pour un environnement, vous saisissez **login**, **mot de passe** et éventuellement un **rôle** (ex. Enseignant, Élève) pour identifier le compte. Après une connexion réussie, ces informations sont enregistrées. Aux connexions suivantes pour le même environnement, vous pouvez choisir un identifiant déjà enregistré (affiché avec le rôle entre parenthèses) ou « Nouvel identifiant ». Les identifiants sont **triés en faisant remonter les derniers utilisés**. Les credentials sont stockés par environnement et par utilisateur dans un fichier **non versionné** (voir [Structure des fichiers](#structure-des-fichiers)).

#### Reconnexions rapides

En mode interactif (sans `-e`), `connect` propose en tête de liste les **dernières connexions** (jusqu'à 3 : combo *environnement / login / apps*), chacune annotée de sa fraîcheur (« connecté il y a 3h12 », avec ⚠️ si la session est probablement expirée). Sélectionnez-en une pour la rejouer directement. Pratique quand on jongle entre plusieurs sujets avec des comptes différents.

Exemples :

Expand All @@ -81,6 +87,22 @@ dev-auth-fetcher reconnect-last

À utiliser après avoir fait au moins une fois `connect` (avec sélection d'apps). Si aucune dernière connexion n'est enregistrée, un message vous invitera à lancer d'abord `connect`.

### Mode watch (`--watch`)

Les sessions de recette expirent après une période d'inactivité : votre front local se met alors à recevoir des 401. Le mode `--watch` **maintient la session vivante** par un **ping keep-alive régulier** (premier plan, `Ctrl+C` pour arrêter) :

```bash
dev-auth-fetcher connect -e recette-ode1 -a mon-app --watch
dev-auth-fetcher connect -e recette-ode1 -a mon-app --watch --watch-interval 3 # ping toutes les 3 min
```

À chaque intervalle (défaut **2 min**, réglable via `--watch-interval <minutes>`), l'outil sonde la session. L'intervalle doit rester **inférieur au timeout d'inactivité du serveur** (observé ≈ 5 min sur les recettes) pour que le ping réarme la session avant son expiration :

- **session vivante** → rien n'est touché. Le ping lui-même réarme le timeout d'inactivité côté serveur, donc la session reste active **sans réécrire le `.env`** et **sans reload Vite**.
- **session tombée** → l'outil **ré-authentifie et réinjecte** les `.env`. C'est le **seul** moment où le `.env` change.

> ⚠️ **À savoir** : quand le `.env` est réécrit (uniquement à la ré-authentification), Vite **surveille les `.env`**, **redémarre le dev-server** et **recharge la page** (perte de l'état HMR). En keep-alive nominal, ça n'arrive pas — le reload n'a lieu que si la session a réellement expiré.

### Lister les applications

Affiche les applications détectées (avec dossier `frontend`) dans le répertoire configuré :
Expand All @@ -91,23 +113,26 @@ dev-auth-fetcher list-apps

## Structure des fichiers

- **Configuration globale** : `config/app.config.json`
- `appsRoot` : chemin racine des applications
- `defaultEnvironment` : environnement par défaut
Les données **non versionnées** (propres à chaque dev) sont centralisées dans **un seul dossier**, hors du repo : `~/.dev-auth-fetcher/` (surchargeable via la variable d'environnement `DEV_AUTH_FETCHER_HOME`).

- **Configuration utilisateur** : `~/.dev-auth-fetcher/config.json`
- `appsRoot` : chemin racine des applications
- `defaultEnvironment` : environnement par défaut

- **Environnements** : un fichier par environnement dans `config/environments/`
- Ex. `recette-ode1.json` : `{ "id", "label", "url" }`
- **Identifiants enregistrés** : `~/.dev-auth-fetcher/credentials/<userId>.json`
- `userId` = nom d'utilisateur système par défaut ; surchargeable via `DEV_AUTH_USER`.
- Contenu : profils par environnement (login, mot de passe, rôle optionnel) et **historique des dernières connexions** (jusqu'à 3 : env, login, apps, horodatage et expiration estimée) pour les reconnexions rapides et `reconnect-last`.

> Migration automatique : si d'anciens fichiers existent (`config/app.config.json` et `./.dev-auth-fetcher/credentials/` à la racine du repo), ils sont repris une fois vers `~/.dev-auth-fetcher/` au premier lancement.

- **Environnements** : un fichier par environnement dans `~/.dev-auth-fetcher/environments/` (ex. `recette-ode1.json` : `{ "id", "label", "url" }`).
- La **liste partagée par défaut** est définie dans le code (`DEFAULT_ENVIRONMENTS`, versionné) et seedée automatiquement au premier usage. Pour ajouter/modifier un environnement partagé, éditer ce tableau ; pour un environnement perso, déposer un `.json` dans le dossier ci-dessus.

- **Fichier .env cible** (dans chaque `application/frontend/.env` ou `entcore/application/frontend/.env`) :
- `VITE_XSRF_TOKEN=...`
- `VITE_ONE_SESSION_ID=...`
- `VITE_RECETTE=<url>`

- **Identifiants enregistrés** (par utilisateur, **non versionnés**, répertoire dans `.gitignore`) :
- Répertoire : `.dev-auth-fetcher/credentials/` (à la racine du répertoire depuis lequel vous lancez la CLI).
- Fichier : `<userId>.json` (par défaut `userId` = nom d'utilisateur système ; peut être surchargé avec la variable d'environnement `DEV_AUTH_USER`).
- Contenu : profils par environnement (login, mot de passe, rôle optionnel) et dernière connexion (env, login, apps) pour `reconnect-last`.

## Scripts

| Commande | Description |
Expand Down
5 changes: 0 additions & 5 deletions config/app.config.json

This file was deleted.

5 changes: 0 additions & 5 deletions config/environments/local.json

This file was deleted.

5 changes: 0 additions & 5 deletions config/environments/recette-ode1.json

This file was deleted.

5 changes: 0 additions & 5 deletions config/environments/recette-ode2.json

This file was deleted.

5 changes: 0 additions & 5 deletions config/environments/recette-ode3.json

This file was deleted.

5 changes: 0 additions & 5 deletions config/environments/recette-ode4.json

This file was deleted.

5 changes: 0 additions & 5 deletions config/environments/recette-release.json

This file was deleted.

58 changes: 0 additions & 58 deletions old/config.json

This file was deleted.

16 changes: 0 additions & 16 deletions old/config.template.json

This file was deleted.

Loading
Loading