Skip to content
Open
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
14 changes: 14 additions & 0 deletions apps/nginx-strangler/conf.d/routing.conf
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,26 @@ server {
# proxy_set_header X-Forwarded-Proto $scheme;
# }

# Healthcheck de nginx-strangler lui-même
location = /health {
access_log off;
add_header 'Content-Type' 'application/json';
return 200 '{"status":"UP"}';
}

#################################################
# BASCULE DES ROUTES LEGACY->NESTJS
#
# [Vague 1 - service-chains/opencds] 2026-03-20
location /api/v1/service-chains {
proxy_pass http://server-nestjs;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

# ── Fallback : tout le reste vers le server legacy ────────────────────────
location /api/ {
proxy_pass http://server-legacy;
Expand Down
8 changes: 8 additions & 0 deletions apps/server-nestjs/.env.docker-example
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ SERVER_PORT=3001
DB_URL=postgresql://admin:admin@postgres:5432/dso-console-db?schema=public
# Adresse e-mail de contact affichée dans l'interface
CONTACT_EMAIL=cloudpinative-relations@interieur.gouv.fr

# --- Configuration OpenCDS ---
# URL de l'API OpenCDS (laisser vide pour désactiver)
OPENCDS_URL=
# Token d'authentification pour l'API OpenCDS
OPENCDS_API_TOKEN=token
# Vérification du certificat TLS de l'API OpenCDS (true | false)
OPENCDS_API_TLS_REJECT_UNAUTHORIZED=true
6 changes: 6 additions & 0 deletions apps/server-nestjs/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ COPY --chown=node:root plugins/ ./plugins/
COPY --chown=node:root packages/ ./packages/
COPY --chown=node:root apps/server-nestjs/ ./apps/server-nestjs/

# Build shared (nécessaire pour que les imports @cpn-console/shared fonctionnent)
RUN pnpm --filter @cpn-console/shared run build

# Réinjecter shared buildé dans node_modules (injected workspace packages)
RUN pnpm --filter @cpn-console/server-nestjs install --frozen-lockfile

# Générer le client Prisma (schéma multi-fichiers : pointer sur le dossier)
RUN pnpm --filter @cpn-console/server-nestjs exec prisma generate \
--schema=src/prisma/schema
Expand Down
101 changes: 101 additions & 0 deletions apps/server-nestjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,107 @@ flowchart TD
ApplicationInitializationService --> LoggerService
```

## Architecture du module ServiceChain (Vague 1)

Le module ServiceChain est le **premier module métier migré** depuis le legacy
vers server-nestjs via le pattern Strangler Fig. Il sert de proxy HTTP vers
l'API externe OpenCDS (gestion des chaînes de service réseau).

### Flux de proxying OpenCDS

```
┌──────────┐ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Client │────▶│ nginx-strangler │────▶│ server-nestjs │────▶│ API OpenCDS │
│ (browser/ │ │ │ │ │ │ (externe) │
│ script) │ │ /api/v1/ │ │ ServiceChain │ │ │
│ │◀────│ service-chains │◀────│ Controller │◀────│ /requests │
│ │ │ ──▶ nestjs │ │ ──▶ Service │ │ /validate │
└──────────┘ │ │ │ ──▶ axios │ │ /flows │
│ /api/* (reste) │ └──────────────────┘ └──────────────┘
│ ──▶ legacy │
└─────────────────┘
```

### Structure du module

```
src/cpin-module/
├── infrastructure/
│ └── auth/ # Auth transverse (réutilisable)
│ ├── auth.module.ts # Module NestJS
│ ├── auth.service.ts # Lookup token SHA256 → Prisma
│ ├── admin-permission.guard.ts # Guard : vérifie x-dso-token + permissions
│ ├── admin-permission.decorator.ts @RequireAdminPermission('ListSystem')
│ └── admin-permission.guard.spec.ts
└── service-chain/ # Module métier
├── service-chain.module.ts # Imports: ConfigurationModule, AuthModule
├── service-chain.controller.ts # 5 endpoints sous /api/v1/service-chains
├── service-chain.service.ts # Proxy axios → OpenCDS + validation Zod
├── service-chain.controller.spec.ts
└── service-chain.service.spec.ts
```

### Authentification

Seule l'**auth par token** (`x-dso-token`) est supportée pour l'instant.
L'auth par session Keycloak sera ajoutée lors de la migration globale du
mécanisme de session vers NestJS (les cookies de session Fastify ne sont pas
déchiffrables par Express).

```
Requête HTTP
┌──────────────────────┐
│ AdminPermissionGuard │
│ │
│ 1. Lire header │
│ x-dso-token │──── absent ──▶ 401 Unauthorized
│ │
│ 2. SHA256(token) │
│ → Prisma lookup │──── invalide ──▶ 401 Unauthorized
│ (PersonalAccess │ (expiré, révoqué, introuvable)
│ Token ou Admin │
│ Token) │
│ │
│ 3. Vérifier perms │
│ bitwise via │──── insuffisant ──▶ 403 Forbidden
│ AdminAuthorized │
│ │
│ 4. OK → continuer │──────────────────▶ Controller
└──────────────────────┘
```

### Endpoints

| Méthode | Route | Permission | Description |
|---------|-------|------------|-------------|
| `GET` | `/api/v1/service-chains` | `ListSystem` | Liste toutes les chaînes |
| `GET` | `/api/v1/service-chains/:id` | `ListSystem` | Détails d'une chaîne |
| `GET` | `/api/v1/service-chains/:id/flows` | `ListSystem` | Flux d'une chaîne |
| `POST` | `/api/v1/service-chains/:id/retry` | `ManageSystem` | Relancer une chaîne |
| `POST` | `/api/v1/service-chains/validate/:id` | `ManageSystem` | Valider une chaîne |

### Différences avec le legacy

- **403 systématique** : le legacy retournait `[]` sur `GET /` sans permission ;
le NestJS retourne 403 pour tous les endpoints sans permission.
- **Pas d'auth session** : seul `x-dso-token` fonctionne (le legacy supportait
aussi les sessions Keycloak).
- **Validation UUID** : les paramètres d'URL sont validés via `ParseUUIDPipe`
(400 si format invalide).

### Variables d'environnement

| Variable | Description | Défaut |
|----------|-------------|--------|
| `OPENCDS_URL` | URL de base de l'API OpenCDS | _(vide = désactivé)_ |
| `OPENCDS_API_TOKEN` | Token d'API OpenCDS (header `X-API-Key`) | — |
| `OPENCDS_API_TLS_REJECT_UNAUTHORIZED` | Vérification TLS (`true`/`false`) | `true` |

---

Pour mettre à jour `old-server` (après avoir rebasé sur `origin/master`, par exemple) :

```bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ Cette modularisation est documentée dans plusieurs fichiers :
- **S10** : 80% migré (Plugins, comme ArgoCD, Gitlab, etc.)
- **S12** : 100% migré

### Migrations anticipées
- **ServiceChain (OpenCDS)** : Migré le 2026-03-26, en avance sur le planning
initial (prévu V3/S8). Ce module isolé (proxy HTTP vers API externe, aucune
dépendance entrante) a servi de premier test de bout en bout du pipeline de
migration : module NestJS + AuthGuard + nginx-strangler + Docker.

## 🗓️ Dates clés

- **S1-S2** : Cartographie et setup
Expand Down Expand Up @@ -202,6 +208,6 @@ Cette modularisation est documentée dans plusieurs fichiers :

---

**Version** : 1.0
**Dernière mise à jour** : 2026-01-07
**Version** : 1.1
**Dernière mise à jour** : 2026-03-26
**Prochaine revue** : Fin S2
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Cartographie des modules - Modularisation Backend

> Derniere mise a jour : **2026-02-23** (Sprint 2 - Cartographie finalisee)
> Derniere mise a jour : **2026-03-26** (Migration ServiceChain finalisee)

---

Expand Down Expand Up @@ -52,17 +52,19 @@ plus **5 couches transverses** et **7 plugins** a encapsuler.
+--------------------------------------------------------------+
| Couche 4 : Evenements (EventEmitter, remplacement hooks) | A CREER
+--------------------------------------------------------------+
| Couche 3 : Securite (AuthGuard, PermissionsGuard, Filters) | A CREER
| Couche 3 : Securite (AuthGuard, PermissionsGuard, Filters) | PARTIEL
+--------------------------------------------------------------+
| Couche 2 : Core (AppService, FastifyService) | FAIT
+--------------------------------------------------------------+
| Couche 1 : Infrastructure (Config, Logger, DB, HTTP) | FAIT
+--------------------------------------------------------------+
```

Les couches 1 et 2 sont en place. Les couches 3 et 4 sont les **pre-requis
critiques** avant toute migration de module metier. C'est la priorite absolue
de la Vague 0.
Les couches 1 et 2 sont en place. La couche 3 est **partiellement** en place :
l'auth par token (`x-dso-token`) fonctionne via `AdminPermissionGuard` +
`AuthService`. Il reste a implementer l'auth par session Keycloak
(`@CurrentUser()`), le `PermissionsGuard` projet, et le `GlobalExceptionFilter`.
Les couches 4 et 5 restent a creer.

---

Expand All @@ -74,18 +76,26 @@ qui suivent. Les creer en premier permet que chaque migration de module soit un
exercice de "remplissage" des couches superieures, sans reinventer
l'infrastructure a chaque fois.

### 0a. AuthGuard + decorateur @CurrentUser()
### 0a. AuthGuard + decorateur @CurrentUser() — PARTIEL

**Sprint** : S3 (Dev A)
**Remplace** : `authUser()` dans `apps/server/src/utils/controller.ts`

Fonctionnalites a porter :
**Etat actuel (2026-03-26)** : La partie auth par token est implementee dans
`infrastructure/auth/` :
- ✅ `AuthService` : validation token SHA256, lookup Prisma
(PersonalAccessToken + AdminToken), verification status/expiration, calcul
permissions bitwise (y compris roles globaux)
- ✅ `AdminPermissionGuard` : lit `x-dso-token`, verifie permissions via
`AdminAuthorized` de `@cpn-console/shared`
- ✅ `@RequireAdminPermission()` : decorateur de metadata pour les permissions admin

**Reste a faire** :
- Validation de session Keycloak (`req.session.user`)
- Fallback sur token PAT (header `x-dso-token`)
- Fallback session → token (actuellement token uniquement)
- Chargement optionnel du projet (par slug, id, environmentId, repositoryId)
- Injection du profil utilisateur dans la request via `@CurrentUser()`

Types a definir : `UserProfile`, `UserProjectProfile`, `ProjectPermState`
- Types a definir : `UserProfile`, `UserProjectProfile`, `ProjectPermState`

### 0b. GlobalExceptionFilter

Expand Down Expand Up @@ -164,36 +174,36 @@ Plus le score est eleve, plus le module est prioritaire.

### Resultats ordonnes par score

| Rang | Module | Type | Score | Vague | Sprint |
|------|--------|------|-------|-------|--------|
| 1 | vault (encapsulation) | Plugin | 8.5 | V3 | S7-S8 |
| 2 | system (health/version) | Metier | 7.8 | V1 | S3 |
| 3 | system/settings | Metier | 7.4 | V1 | S3 |
| 4 | system/config | Metier | 7.4 | V1 | S3-S4 |
| 5 | keycloak (encapsulation) | Plugin | 7.4 | V3 | S8 |
| 6 | admin-token | Metier | 7.1 | V1 | S3-S4 |
| 7 | user/tokens | Metier | 7.1 | V1 | S3-S4 |
| 8 | gitlab (encapsulation) | Plugin | 6.7 | V4 | S9 |
| 9 | service-monitor | Metier | 6.6 | V2 | S5 |
| 10 | user | Metier | 6.6 | V2 | S5 |
| 11 | stage | Metier | 6.5 | V2 | S5-S6 |
| 12 | log | Metier | 6.5 | V1 | S4 |
| 13 | zone | Metier | 6.4 | V2 | S6 |
| 14 | environment | Metier | 6.3 | V3 | S7 |
| 15 | admin-role | Metier | 6.1 | V2 | S5 |
| 16 | project-core | Metier | 5.8 | V4 | S9 |
| 17 | service-chain | Metier | 5.9 | V3 | S8 |
| 18 | repository | Metier | 5.8 | V3 | S7-S8 |
| 19 | cluster | Metier | 5.7 | V3 | S7 |
| 20 | harbor (encapsulation) | Plugin | 5.6 | V4 | S9-S10 |
| 21 | project-service | Metier | 5.6 | V3 | S8 |
| 22 | argocd (encapsulation) | Plugin | 5.3 | V5 | S10-S11 |
| 23 | project-role | Metier | 5.2 | V3 | S7-S8 |
| 24 | nexus (encapsulation) | Plugin | 5.1 | V4 | S10 |
| 25 | project-member | Metier | 4.7 | V3 | S8 |
| 26 | project-secrets | Metier | 4.6 | V4 | S9 |
| 27 | project-bulk | Metier | 4.2 | V4 | S9-S10 |
| 28 | sonarqube (encapsulation) | Plugin | 4.2 | V5 | S11 |
| Rang | Module | Type | Score | Vague | Sprint | Statut |
|------|--------|------|-------|-------|--------|--------|
| 1 | vault (encapsulation) | Plugin | 8.5 | V3 | S7-S8 | |
| 2 | system (health/version) | Metier | 7.8 | V1 | S3 | |
| 3 | system/settings | Metier | 7.4 | V1 | S3 | |
| 4 | system/config | Metier | 7.4 | V1 | S3-S4 | |
| 5 | keycloak (encapsulation) | Plugin | 7.4 | V3 | S8 | |
| 6 | admin-token | Metier | 7.1 | V1 | S3-S4 | |
| 7 | user/tokens | Metier | 7.1 | V1 | S3-S4 | |
| 8 | gitlab (encapsulation) | Plugin | 6.7 | V4 | S9 | |
| 9 | service-monitor | Metier | 6.6 | V2 | S5 | |
| 10 | user | Metier | 6.6 | V2 | S5 | |
| 11 | stage | Metier | 6.5 | V2 | S5-S6 | |
| 12 | log | Metier | 6.5 | V1 | S4 | |
| 13 | zone | Metier | 6.4 | V2 | S6 | |
| 14 | environment | Metier | 6.3 | V3 | S7 | |
| 15 | admin-role | Metier | 6.1 | V2 | S5 | |
| 16 | project-core | Metier | 5.8 | V4 | S9 | |
| 17 | service-chain | Metier | 5.9 | V3 | S8 | ✅ MIGRE |
| 18 | repository | Metier | 5.8 | V3 | S7-S8 | |
| 19 | cluster | Metier | 5.7 | V3 | S7 | |
| 20 | harbor (encapsulation) | Plugin | 5.6 | V4 | S9-S10 | |
| 21 | project-service | Metier | 5.6 | V3 | S8 | |
| 22 | argocd (encapsulation) | Plugin | 5.3 | V5 | S10-S11 | |
| 23 | project-role | Metier | 5.2 | V3 | S7-S8 | |
| 24 | nexus (encapsulation) | Plugin | 5.1 | V4 | S10 | |
| 25 | project-member | Metier | 4.7 | V3 | S8 | |
| 26 | project-secrets | Metier | 4.6 | V4 | S9 | |
| 27 | project-bulk | Metier | 4.2 | V4 | S9-S10 | |
| 28 | sonarqube (encapsulation) | Plugin | 4.2 | V5 | S11 | |

**Note** : Le score brut ne dicte pas directement l'ordre de migration.
L'ordre reel est contraint par le graphe de dependances (bottom-up), les
Expand Down Expand Up @@ -707,34 +717,47 @@ NestJS injectables.

---

### 18. service-chain
### 18. service-chain — ✅ MIGRE (2026-03-26)

| Attribut | Valeur |
|----------|--------|
| **Routes** | 5 |
| **Score** | 5.9 |
| **Sprint** | S8 |
| **Dev** | B |

**Routes** :
- `GET /api/v1/projects/:projectId/service-chains` - Liste des chaines de service
- `GET /api/v1/projects/:projectId/service-chains/:chainId` - Details d'une chaine
- `POST /api/v1/projects/:projectId/service-chains/:chainId/retry` - Relance d'une chaine
- `POST /api/v1/projects/:projectId/service-chains/:chainId/validate` - Validation
- `GET /api/v1/projects/:projectId/service-chains/:chainId/flows` - Flux de la chaine

**Dependances sortantes** : `queries-index` (queries propres), API externe OpenCDS (HTTP via axios)
| **Sprint prevu** | S8 |
| **Migration effective** | 2026-03-26 (en avance de phase) |
| **Dev** | @stephane.trebel |

**Routes (implementation reelle)** :
- `GET /api/v1/service-chains` - Liste des chaines de service
- `GET /api/v1/service-chains/:id` - Details d'une chaine
- `GET /api/v1/service-chains/:id/flows` - Flux de la chaine
- `POST /api/v1/service-chains/:id/retry` - Relance d'une chaine
- `POST /api/v1/service-chains/validate/:id` - Validation

> **Note** : Les routes n'ont pas de scope projet (`/projects/:projectId/`),
> contrairement a ce qui etait initialement documente. Le module est un proxy
> admin vers l'API OpenCDS, pas un module lie a un projet specifique.

**Dependances sortantes** : API externe OpenCDS (HTTP via axios)
**Dependances entrantes** : Aucune

**Points d'attention** :
- Module isole du reste du codebase. Appelle une API externe (OpenCDS) via HTTP
- Pas de hooks
- Utilise axios directement : a remplacer par HttpClientService (HttpModule NestJS)
- Bon candidat pour une extraction en module NestJS optionnel (ThirdPartyModule)
comme envisage dans le README de server-nestjs
- Migrable a tout moment, place ici par opportunite

**Estimation** : 1.5 jours
**Implementation** :
- Module place dans `ThirdPartyModules` (module optionnel CPin) comme envisage
- Auth par token uniquement (`x-dso-token`) via `AdminPermissionGuard`
- Validation UUID sur les parametres d'URL (`ParseUUIDPipe`)
- Validation des reponses OpenCDS via schemas Zod de `@cpn-console/shared`
- Telemetrie via `@StartActiveSpan()` (OpenTelemetry)

**Differences avec le legacy** :
- 403 systematique si permissions insuffisantes (le legacy renvoyait `[]` sur GET /)
- Pas d'auth session Keycloak (token uniquement)
- Validation UUID stricte (400 si format invalide)

**Fichiers** :
- `src/cpin-module/service-chain/service-chain.module.ts`
- `src/cpin-module/service-chain/service-chain.controller.ts`
- `src/cpin-module/service-chain/service-chain.service.ts`
- `src/cpin-module/infrastructure/auth/` (AuthModule partage)

---

Expand Down
Loading
Loading