feat: clean install (Gitea en dur, scan off) + durcissement sécurité entreprise

Gitea
- lien « Code source » hardcodé (REPO_SOURCE_URL) vers le dépôt, toujours visible
- retrait complet du réglage configurable (api.ts, route+store settings, SettingsView, i18n, help, tests)

Découverte des dépôts
- aucune racine de scan par défaut → pas de scan au premier démarrage (clean install)
- corrige la découverte des dépôts à l'INTÉRIEUR d'une racine qui est elle-même un repo
  (depth 0 = conteneur de scan, on descend ; depth > 0 = feuille)

Sécurité « enterprise-deployable »
- en-têtes HTTP durcis (CSP, X-Frame-Options, nosniff, Referrer-Policy, HSTS conditionnel, no-store API), header Server retiré
- permissions DB 0o600 / dossier de données 0o700 ; error handler sanitisé ; garde Content-Type sur les mutations
- chiffrement au repos AES-256-GCM des secrets (server_secret, clé privée VAPID) via SecretBox
- journal d'audit (migration #7) + endpoint /audit-logs + RGPD export/effacement + UI Réglages
- SECURITY.md, docs/ENTERPRISE_DEPLOYMENT.md, sections README EN/FR, SBOM CycloneDX en CI

CI
- pack-smoke packe depuis le contexte du package (cd packages/server) au lieu de « npm pack -w » :
  corrige l'embarquement de @arboretum/shared dans le tarball

Purge des données personnelles du dépôt public
- suppression de spikes/s4-discovery/result.json, reformulation du VERDICT
- chemin de test générique, anonymisation des 5 fixtures de dialogues

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-18 16:44:25 +02:00
parent cc055739f1
commit c88ae9b2ae
41 changed files with 973 additions and 338 deletions

View File

@@ -1,7 +1,6 @@
// Réglages de la découverte auto des repos, persistés dans la table `settings` (clé/valeur).
// Frontière de sécurité : ces clés sont NON sensibles et n'entrent dans l'allow-list du PATCH
// /api/v1/settings que via les validateurs ci-dessous. Aucun secret ne transite par ici.
import { homedir } from 'node:os';
import { getSetting } from '../db/index.js';
import type { Db } from '../db/index.js';
import { isSafeAbsolutePath } from './git.js';
@@ -15,12 +14,14 @@ export const DEFAULT_SCAN_INTERVAL_MIN = 5;
export const MAX_SCAN_INTERVAL_MIN = 1440;
export const MAX_SCAN_ROOTS = 16;
/** Racines à scanner. Défaut : le home de l'utilisateur. Lecture tolérante (JSON malformé → défaut). */
/**
* Racines à scanner. Défaut : AUCUNE racine → aucun scan (clean install).
* L'utilisateur ajoute ses racines via Réglages → Découverte. Lecture tolérante (JSON malformé → []).
*/
export function readScanRoots(db: Db): string[] {
const raw = getSetting(db, SCAN_ROOTS_KEY);
if (!raw) return [homedir()];
const parsed = normalizeScanRoots(safeParse(raw));
return parsed && parsed.length > 0 ? parsed : [homedir()];
if (!raw) return [];
return normalizeScanRoots(safeParse(raw)) ?? [];
}
/** Intervalle périodique en minutes (0 = désactivé). Défaut DEFAULT_SCAN_INTERVAL_MIN. */