UPSTREAM_RUSTWARDEN.md 8080 octets

Usage du framework Rustwarden (vendored)

Version synchronisée : voir .rustwarden-version à la racine. Resynchronisation uniquement via update-project (depuis le dépôt Rustwarden) — jamais de modification manuelle de crates/rustwarden-core/. Référence API : docs/SERVICES_REFERENCE.md (resynchronisé à chaque update).

Services consommés

Service / primitiveUsage BotPlace
Auth JWT + sessions (mode headless)Login SSR fourni côté app ; pages protégées via register_protected_prefix (/config, /chat dans src/main.rs ; /home, /profile, /settings, /admin via botplace_ui::with_ssr_auth_policy)
rustwarden_core::auth::auth_api_routes()Routeur machine canonique (/api/v1/auth/* : login, refresh, 2FA, reset, vérification, changement d'email, limite IP sur les routes pré-session) monté tel quel par botplace_ui::machine_routes() + /health (plan 006, tranche C)
Users / teamsIdentités et groupes du cabinet (teams = « groupes » de la spec)
RBAC (rôles/permissions)Distinction admin vs collaborateur (file des déviances, adoption)
EmailChangeService::admin_force_changeCorrection d'adresse par l'admin depuis la fiche compte (PUT /admin/users/{id}) — audit framework email_changed_by_admin, sessions de la cible révoquées (plan 006, tranche D)
ensure_default_admin (bootstrap)Création de l'admin au démarrage (seul chemin qui accepte le nom réservé admin) ; réutilisé par les harnais de tests (tests/common/mod.rs)
SecurityHeadersConfigCSP explicite (DEFAULT_CONTENT_SECURITY_POLICY, avec 'unsafe-eval') via botplace_ui::with_alpine_csp — voir Workarounds
CSRF structurel (canal browser)Toutes les routes HTMX du plan 001
Rate limitingDéfauts du framework ; limite IP sur login/register/refresh/2FA héritée d'auth_api_routes()
Hooks on_audit_eventPrévu : alimentation du journal d'audit métier (tranche 6)
Personal Access TokensPrévu : authentification des instances hermes-agent (canal machine, plan ultérieur)

Hooks implémentés

on_user_login (src/main.rs, BotplaceHooks) : couche utilisateur, composition scellée, provisionnement de l'instance — jamais bloquant.

Workarounds / besoins upstream

Format : date, besoin, workaround appliqué, renvoi RFC upstream si le besoin persiste.

2026-10-02 — CSP par défaut sans 'unsafe-eval' vs build Alpine standard

  • Besoin : les écrans de gouvernance chargent crates/web/static/alpine.min.js (build Alpine 3.14.9 standard, 98 expressions inline dans 10 templates) qui compile ses expressions par new Function. La CSP par défaut 1.1.0 (RFC 0039 phase 2) retire 'unsafe-eval' : toute l'interactivité casserait en silence.
  • Workaround : botplace_ui::with_alpine_csp(builder) repose la politique 1.0.1 (DEFAULT_CONTENT_SECURITY_POLICY), constante fournie par le framework exactement pour ce retour arrière. Test : crates/botplace-ui/tests/politique_csp.rs.
  • Sortie : migration vers @alpinejs/csp + composants Alpine.data(..) (chantier à formuler). Aucune RFC upstream : le framework documente ce chemin.

2026-10-02 — .auth_failure_mode(..) / .login_path(..) du builder non honorés par AuthService/AdminService

  • Besoin : garantir la redirection SSR vers /login quel que soit l'environnement (plan 005, A2).
  • Constat : dans RustwardenApp::build, les couches AuthService et AdminService sont posées à l'extérieur de l'Extension(Arc<AuthConfig>). Au moment où elles s'exécutent l'extension est absente ; elles retombent sur AuthConfig::from_env() (fallback assumé par un commentaire du code) et lisent donc AUTH_FAILURE_MODE / LOGIN_PATH dans l'environnement. Les overrides du builder ne sont honorés que par les extracteurs internes (auth_required, admin_required). Mis en évidence le 2026-10-02 par prefixes_proteges.rs (première exécution sur base disponible).
  • Workaround : AUTH_FAILURE_MODE=redirect documenté dans .env.example (défaut framework identique si absent) ; le builder garde l'override pour les chemins qui le lisent ; le test fixe l'environnement à cette valeur.
  • RFC upstream à ouvrir : AuthService::new / AdminService::new doivent recevoir l'AuthConfig résolue à la construction (comme security_headers_middleware capture son Arc), ou l'Extension doit être posée plus à l'extérieur que ces couches.

Adaptations aux breaking changes

2026-10-02 — update-project vers 9f3c757 (1.1.0 + RFC 0039 phase 2)

cargo check vert sans modification : ruptures comportementales uniquement. Détail, Gherkin et décisions : docs/plans/006-rustwarden-1.1-adaptation.md. Hors crates/rustwarden-* :

  1. RFC 0036 (Username) — create_user("admin") refusé (nom réservé) : les harnais de tests bootstrapent l'admin par ensure_default_admin (crates/{web,botplace-ui}/tests/common/mod.rs), le nom admin restant nécessaire (couche users/admin des fixtures, relue depuis la base par les handlers). Formulaires user_new, user_edit, profile : pattern, maxlength="39", aide en français.
  2. 1.0.1 (AdminConfig::validate) — ADMIN_PASSWORD=password refusé sur le chemin de création : mot de passe fort dans les tests (admin_env()) ; .env local à corriger (secret).
  3. 1.0.1 (limiteurs partagés) — les services reset / validation partagent un limiteur « 3 emails / heure / adresse » par processus : les scénarios de comptes.rs invitent « claire » sur une adresse propre à chacun.
  4. RFC 0039 phase 2 — CSP : voir Workarounds.
  5. auth_api_routes() enrichi — machine_routes() délègue au routeur canonique au lieu d'une liste recopiée (qui n'avait ni limite IP sur le login, ni routes email-change). Test : tests/canal_machine.rs.
  6. RFC 0041 — update_profile refuse toute nouvelle adresse : fiche admin → admin_force_change ; profil → email en lecture seule (self-service à formuler). Tests : comptes.rs.
  7. Migrations 10 et 11 (totp_last_used_step, pending_email_changes) : jouées sur la base de dev par cargo run --bin migrate ; auto_migrate(true) les joue au boot en production mono-instance.

Non concernés : RFC 0037 (aucun patch TOTP local), contrainte chk_email_queue_email_type (non redéfinie), hook auth.login_blocked (non implémenté), pin SeaORM (déjà 2.0.0), ADMIN_USERNAME=admin (bootstrap).

2026-08-01 — update-project vers 6261a6b

Trois adaptations, toutes hors crates/rustwarden-* (voir docs/plans/005-rustwarden-a3-protected-prefixes-migration.md) :

  1. Pin SeaORM — le core est passé de 2.0.0-rc.20 à 2.0.0 stable ; Cargo.toml racine (jamais touché par update-project) épinglait =2.0.0-rc.41 → résolution de dépendances impossible. Pin aligné sur 2.0.0. Aucune rupture d'API métier (cargo check vert sans autre modification).
  2. A3 — préfixes protégés vidés par défaut (with_ui les réenregistre, BotPlace ne l'appelle pas) : /home, /profile, /settings et /admin seraient devenus publics. Réenregistrés via botplace_ui::PROTECTED_PREFIXES / with_ssr_auth_policy.
  3. A2 — .headless() bascule auth_failure_mode sur Json401 : l'UI SSR aurait renvoyé 401 {"error":"unauthorized"} au lieu d'une redirection vers /login. AuthFailureMode::Redirect imposé par le builder. Concerne aussi /admin, dont AdminService honore désormais le même mode d'échec. Correctif 2026-10-02 : l'override du builder n'atteint pas les couches AuthService/AdminService (voir Workarounds) ; le contrat réel est AUTH_FAILURE_MODE=redirect dans l'environnement.

Non-régression : crates/botplace-ui/tests/prefixes_proteges.rs (monte l'application par le vrai builder ; ✅ vert le 2026-10-02 avec AUTH_FAILURE_MODE=redirect).