Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7492743
docs(site): ajoute les logos des outils dans les pages de la document…
astronas Jul 7, 2026
fcd81e9
docs(site): uniformise la taille des logos (height 32)
astronas Jul 7, 2026
260afbe
docs(site): menu a 4 onglets, accueil succinct, contexte detaille (vo…
astronas Jul 7, 2026
d521e6d
docs(site): reduit la taille des logos (height 24)
astronas Jul 7, 2026
52a89c6
docs(site): corrige la taille des logos via une classe CSS (le theme …
astronas Jul 7, 2026
82aa186
docs(site): logos a 40px et places directement sous les titres
astronas Jul 7, 2026
ae299e6
docs(site): logos centres + bandeau accueil reduit, contenu elargi, M…
astronas Jul 7, 2026
084867d
docs(site): accents sur les libelles de navigation et la config
astronas Jul 7, 2026
a0f5bad
docs(site): organise Implementation en sous-menus (Vue d'ensemble, Se…
astronas Jul 7, 2026
558f1c4
docs(site): ajoute le logo RAM sous 'Dechiffrement au runtime'
astronas Jul 7, 2026
b376b2b
docs(site): logos CI et CD sous leurs titres (Pipeline CI, Deploiement)
astronas Jul 7, 2026
d7789cd
docs(site): logo GitHub sous 'Gouvernance Git'
astronas Jul 7, 2026
54bf262
docs(site): accueil - contexte grand public + section 'L'Equipe sur c…
astronas Jul 7, 2026
8319b5f
docs(site): restructure 'comment on s'y prend' en demarche factuelle …
astronas Jul 7, 2026
a3d02d0
docs(site): contexte - retire 'Ce qu'on nous demande', deux-points su…
astronas Jul 7, 2026
955873d
docs(site): contexte plus verbeux (mode rapport, explique le cours) +…
astronas Jul 7, 2026
0fc5f48
docs(site): accueil - bandeau Ynov + DevSecOps et accroche 'projet de…
astronas Jul 7, 2026
d061230
docs(site): accueil - image CI/CD en heros + stack technique agrandie…
astronas Jul 7, 2026
e58c74d
docs(site): accueil facon ynov-virtu (image heros arrondie, section a…
astronas Jul 7, 2026
a8f4de9
docs(site): accueil en pleine largeur, sans sommaire 'Sur cette page'
astronas Jul 7, 2026
3db916e
docs(site): accueil - masque aussi la colonne gauche, contenu aligne …
astronas Jul 7, 2026
4ada074
docs(site): rend le sujet PDF et le skeleton ZIP telechargeables sur …
astronas Jul 7, 2026
167ecfb
docs(site): stylise les 'Notre demarche' en stepper colore (emoji + b…
astronas Jul 7, 2026
49e5bcf
docs(site): contexte - etiquettes-bulles colorees par categorie + con…
astronas Jul 7, 2026
6bbb544
docs(site): accueil - bandeau Ynov/DevSecOps remis et page allegee
astronas Jul 7, 2026
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
2 changes: 1 addition & 1 deletion documentation/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Deux composants distincts dans un même dépôt, industrialisés par une **uniqu
│ └── vercel.json
├── .github/
│ ├── workflows/ci-cd.yml # pipeline principal durci (staging + main)
│ ├── actions/trivy-scan/ # composite action scan SBOM CycloneDX
│ ├── actions/trivy-scan/ # composite action : scan SBOM CycloneDX
│ ├── branch-protection/main.yml # politique de protection documentée
│ └── secrets-prod.yaml # secrets chiffrés SOPS (valeurs ENC[...])
├── scripts/
Expand Down
Binary file added documentation/docs/assets/Gitleaks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/cd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/ci-cd.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/ci.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/codeql.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/docker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/github.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/github_actions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/github_pages.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/nodejs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/ram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file added documentation/docs/assets/sops.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/sujet-projet-final.pdf
Binary file not shown.
Binary file added documentation/docs/assets/trivy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/docs/assets/vercel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions documentation/docs/ci.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Pipeline CI durci

![Intégration continue](assets/ci.png){ .logo }

Le workflow [`ci-cd.yml`](https://github.com/Sorway/DevSecOps/blob/main/.github/workflows/ci-cd.yml)
agit comme une **barrière** : rien ne se déploie sans le succès complet des contrôles.

Expand Down
4 changes: 3 additions & 1 deletion documentation/docs/composite-action.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Composite Action Trivy SBOM
# Composite Action : Trivy SBOM

Pour centraliser la gouvernance de sécurité et éviter la redondance, le scan de dépendances au format
SBOM est isolé dans une **action composite** locale, réutilisable en boîte noire.
Expand All @@ -11,6 +11,8 @@ et expose des entrées / sorties strictes.

## L'action `trivy-scan`

![Trivy](assets/trivy.png){ .logo }

Fichier [`.github/actions/trivy-scan/action.yml`](https://github.com/Sorway/DevSecOps/blob/main/.github/actions/trivy-scan/action.yml).

```yaml
Expand Down
229 changes: 197 additions & 32 deletions documentation/docs/conformite.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,228 @@
# Conformité aux consignes

Récapitulatif exigence par exigence, avec le lien vers l'implémentation. :material-check-decagram:
Chaque exigence de l'énoncé, avec **sa preuve** : extrait de code réel, configuration, ou
déploiement en ligne. Les blocs « Preuve » sont repliés, cliquez pour les ouvrir.

[![CI CD durcie](https://github.com/Sorway/DevSecOps/actions/workflows/ci-cd.yml/badge.svg?branch=main)](https://github.com/Sorway/DevSecOps/actions/workflows/ci-cd.yml)

**Preuves en ligne :** [Frontend](https://sorway.github.io/DevSecOps/) ·
[API `/api/health`](https://projet-final-inky-iota.vercel.app/api/health) ·
[Dépôt](https://github.com/Sorway/DevSecOps) ·
[Image GHCR](https://github.com/Sorway/DevSecOps/pkgs/container/devsecops%2Fbackend)

## Gouvernance Git

- [x] `staging` pivot d'intégration, CI complète à chaque événement — [détails](gouvernance.md)
- [x] `staging` pivot d'intégration, CI complète à chaque événement
- [x] `main` production, push directs interdits (ruleset `REVIEW_REQUIRED`)
- [x] `on: push/pull_request: [staging, main]`
- [x] Blocs `if: github.ref == 'refs/heads/main'` + matrice `needs` stricte
- [x] Job de production lié à un `environment` nommé (`production` / `github-pages`)
- [x] Déclenché sur `staging` **et** `main`, `if` sur `main`, `needs` strict, `environment` nommé

??? example "Preuve : déclenchement, gating conditionnel et environnement (`ci-cd.yml`)"

```yaml
on:
push:
branches: [staging, main] # déclenché sur les deux branches
pull_request:
branches: [staging, main]

jobs:
deploy-backend:
if: github.ref == 'refs/heads/main' # bloc conditionnel de job
needs: [test, gitleaks, codeql, sbom-scan, docker-image] # dépendance stricte
environment: production # environnement nommé
```

La protection de `main` est **effective** : toute PR y est en état `REVIEW_REQUIRED` et ne peut
être fusionnée sans revue (ruleset GitHub).

## Durcissement local (Shift-Left)

- [x] Hook `pre-commit` : `actionlint` + `gitleaks --staged` (bloquants)
- [x] Refus des fichiers `.env` / `.pem` / `.key` avec message rouge, commit avorté
- [x] Règle Gitleaks sur-mesure `SECWALLET_` + 24 caractères + entropie

??? example "Preuve : contrôle de structure du hook (`scripts/pre-commit.sh`)"

```bash
if [[ "$file" == *.env || "$file" == *.pem || "$file" == *.key ]]; then
echo -e "${RED}Sécurité : Tentative de commit d'un fichier de configuration ou d'une clé en clair. Opération annulée.${RESET}"
exit 1
fi
```

## Durcissement local
??? example "Preuve : règle Gitleaks sur-mesure (`gitleaks.toml`)"

- [x] Hook `pre-commit` : `actionlint` + `gitleaks --staged` (bloquants) — [détails](shift-left.md)
- [x] Contrôle de structure `.env` / `.pem` / `.key` + message rouge, commit avorté
- [x] Règle Gitleaks sur-mesure `SECWALLET_[A-Z0-9]{24}` + entropie
```toml
[[rules]]
id = "secwallet-internal-token"
regex = '''SECWALLET_[A-Z0-9]{24}'''
entropy = 3.5
keywords = ["SECWALLET_"]
```

## Secrets par enveloppe
## Secrets par enveloppe (SOPS / age)

- [x] Paire de clés **age** (privée `ops.txt`, ignorée par Git) — [détails](secrets.md)
- [x] `.github/secrets-prod.yaml` chiffré SOPS : valeurs `ENC[...]`, clés lisibles (`encrypted_regex`)
- [x] Déchiffrement runtime **en RAM**, aucun secret sur le disque du runner
- [x] Paire de clés **age**, privée `ops.txt` (ignorée par Git)
- [x] Chiffrement SOPS **sélectif** : valeurs `ENC[...]`, clés lisibles
- [x] Déchiffrement runtime **en RAM**, aucun secret sur le disque

??? example "Preuve : chiffrement sélectif (`.github/secrets-prod.yaml`)"

```yaml
production:
DATABASE_URL: ENC[AES256_GCM,data:TCwiv...,type:str] # valeur chiffrée
JWT_SECRET: ENC[AES256_GCM,data:5bSz4...,type:str]
API_KEY: ENC[AES256_GCM,data:oV5AU...,type:str]
sops:
encrypted_regex: ^(DATABASE_URL|JWT_SECRET|API_KEY)$ # seules ces valeurs
```

??? example "Preuve : déchiffrement en RAM, sans fichier (`ci-cd.yml`, job `deploy-backend`)"

```bash
export SOPS_AGE_KEY # clé en mémoire seulement
secrets_json="$(sops -d --output-type json .github/secrets-prod.yaml)" # déchiffré en RAM
# aucun mktemp, aucun SOPS_AGE_KEY_FILE : rien n'est écrit sur le disque du runner
```

## Conteneurisation & GHCR

- [x] `Dockerfile` multi-stage, non-root (`node:24-alpine`) — [détails](conteneurisation.md)
- [x] Build conditionné au filtrage de chemins (`dorny/paths-filter`)
- [x] Scan de l'image (Trivy `HIGH,CRITICAL`) avant publication
- [x] Publication GHCR conditionnelle (scan OK + `main`), tag = SHA du commit
- [x] `Dockerfile` multi-stage, non-root (`node:24-alpine`)
- [x] Build conditionné au filtrage de chemins
- [x] Scan Trivy de l'image avant publication
- [x] Publication GHCR conditionnelle (scan OK + `main`), tag = SHA

??? example "Preuve : Dockerfile multi-stage non-root (`backend/Dockerfile`)"

```dockerfile
FROM node:24-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev

FROM node:24-alpine AS runtime
RUN apk upgrade --no-cache \
&& addgroup -S nodeapp && adduser -S nodeapp -G nodeapp
COPY --from=deps /app/node_modules ./node_modules
USER nodeapp
```

??? example "Preuve : filtrage, scan et push conditionnel (`ci-cd.yml`, job `docker-image`)"

```yaml
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
backend:
- 'backend/**'
- '.github/workflows/ci-cd.yml'
- name: Scan backend image
if: steps.filter.outputs.backend == 'true'
run: trivy image --exit-code 1 --severity HIGH,CRITICAL "${{ steps.meta.outputs.image }}"
- name: Push backend image to GHCR
if: github.ref == 'refs/heads/main' && steps.filter.outputs.backend == 'true'
run: docker push "ghcr.io/${GITHUB_REPOSITORY,,}/backend:${GITHUB_SHA}"
```

## Pipeline CI durci

- [x] `permissions: contents: read` global, écritures isolées au job — [détails](ci.md)
- [x] `permissions: contents: read` global, écritures isolées au job
- [x] Cache des dépendances Node
- [x] CodeQL + upload SARIF, échec sur `High`/`Error` — [détails](sast.md)
- [x] Tests bloquants ; Gitleaks exit ≠ 0 ; **aucun `continue-on-error: true`**
- [x] CodeQL + upload SARIF, échec sur `High`/`Error`
- [x] Tests bloquants, Gitleaks exit ≠ 0, **aucun `continue-on-error`**

??? example "Preuve : moindre privilège (`ci-cd.yml`)"

```yaml
permissions:
contents: read # global : lecture seule

jobs:
docker-image:
permissions:
packages: write # écriture isolée à ce job
codeql:
permissions:
security-events: write
```

??? example "Preuve : CodeQL fait échouer sur une faille majeure (`ci-cd.yml`)"

```yaml
- name: Fail on CodeQL high severity
run: |
jq -e '[ .runs[].results[]
| select((.level=="error") or (.properties["security-severity"] // "0" | tonumber >= 7.0))
] | length == 0' codeql-results/javascript.sarif
```

## Composite Action

- [x] `.github/actions/trivy-scan/action.yml` de type composite — [détails](composite-action.md)
- [x] Entrée obligatoire = chemin du SBOM CycloneDX JSON
- [x] `.github/actions/trivy-scan/action.yml` de type composite
- [x] Entrée obligatoire = chemin du SBOM CycloneDX
- [x] `trivy sbom` : échec sur `CRITICAL`, avertissement sur `HIGH`/`MEDIUM`
- [x] Installe Trivy elle-même (boîte noire réutilisable)
- [x] Installe Trivy elle-même (boîte noire)

??? example "Preuve : action composite (`.github/actions/trivy-scan/action.yml`)"

```yaml
inputs:
sbom-path:
required: true # entrée obligatoire
runs:
using: composite
steps:
- name: Ensure Trivy is installed # boîte noire : elle s'installe seule
shell: bash
run: command -v trivy >/dev/null 2>&1 || { curl -sfL ... ; sudo install trivy /usr/local/bin/ ; }
- name: Scan CRITICAL vulnerabilities
shell: bash
run: trivy sbom --exit-code 1 --severity CRITICAL --format table "${{ inputs.sbom-path }}"
- name: Summarize HIGH and MEDIUM # avertissement seulement
shell: bash
run: trivy sbom --exit-code 0 --severity HIGH,MEDIUM ... >> "$GITHUB_STEP_SUMMARY"
```

## Déploiement continu

- [x] Frontend GitHub Pages, `main` uniquement, OIDC (`pages` + `id-token: write`) — [détails](deploiement.md)
- [x] Frontend GitHub Pages, `main` uniquement, OIDC (`pages` + `id-token: write`)
- [x] `upload-pages-artifact` du `/frontend` + `deploy-pages` (hermétique)
- [x] Backend Vercel en CLI, `needs` sécurité + livraison
- [x] Déchiffrement SOPS en RAM, injection à la volée (`--env`)
- [x] Backend Vercel, `needs` sécurité + livraison, secrets en RAM

??? example "Preuve : frontend en OIDC (`ci-cd.yml`, job `deploy-frontend`)"

```yaml
if: github.ref == 'refs/heads/main'
needs: [test, gitleaks, codeql, sbom-scan, docker-image]
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
pages: write
id-token: write
```

??? example "Preuve : backend Vercel, secrets injectés à la volée (`ci-cd.yml`)"

```bash
vercel pull --yes --environment=production --token "$VERCEL_TOKEN"
vercel deploy backend --prod --yes --token "$VERCEL_TOKEN" "${env_args[@]}" # --env=K=V en RAM
```

## Robustesse

- [x] Concurrence annulante (`cancel-in-progress: true`) — [détails](robustesse.md)
- [x] Concurrence annulante (`cancel-in-progress: true`)
- [x] Healthcheck `curl --fail /api/health`, échec si ≠ 200

---
??? example "Preuve : concurrence et healthcheck (`ci-cd.yml`)"

```yaml
concurrency:
group: ci-cd-${{ github.ref }}
cancel-in-progress: true

!!! success "Livrables"
- **Frontend** : [sorway.github.io/DevSecOps](https://sorway.github.io/DevSecOps/)
- **API** : [projet-final-inky-iota.vercel.app](https://projet-final-inky-iota.vercel.app) (`/api/health`)
- **Dépôt** : [github.com/Sorway/DevSecOps](https://github.com/Sorway/DevSecOps)
# ... en fin de job deploy-backend :
- name: Healthcheck
run: curl --fail --silent --show-error "${{ steps.vercel.outputs.url }}/api/health"
```
2 changes: 2 additions & 0 deletions documentation/docs/conteneurisation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Conteneurisation & GHCR

![Docker](assets/docker.png){ .logo }

L'artefact serveur du backend est construit et publié en image Docker **sécurisée**.

## Dockerfile multi-stage non-root
Expand Down
Loading
Loading