Paramètres dynamiques¶
Ce document explique comment fonctionne la configuration de la plateforme, les deux mécanismes en jeu, leur précédence, et les pièges à connaître.
Vue d'ensemble : deux systèmes distincts¶
Gitrust utilise deux systèmes de configuration indépendants :
| Système | Source | Modifiable à chaud | Visible dans l'UI admin |
|---|---|---|---|
| Configuration statique | Fichier .env + variables d'environnement |
Non (restart requis) | Non |
| Configuration dynamique | Table app_settings (PostgreSQL) |
Oui (effet immédiat) | Oui (/admin/settings) |
Il existe un cas hybride pour OAuth (DB prioritaire, .env en fallback).
1. Configuration statique (.env)¶
Principe¶
Les variables d'environnement sont chargées une seule fois au démarrage par dotenvy::dotenv() et stockées dans des structs Rust immuables. Elles ne sont jamais relues après le boot.
Fichiers de référence¶
| Fichier | Rôle |
|---|---|
.env.example |
Template documenté avec toutes les variables |
.env |
Configuration locale (gitignore) |
.env.production |
Configuration de déploiement |
.env.test |
Configuration de tests |
Structs de chargement¶
| Struct | Variables concernées |
|---|---|
GitrustConfig |
GIT_REPOS_BASE_PATH, SSH_PORT, SSH_LISTEN_ADDR, SSH_HOST_KEY_PATH, CI_*, IMPORT_* |
AppConfig |
APP_NAME, APP_THEME, APP_DEBUG |
AuthConfig |
JWT_SECRET, JWT_EXPIRATION_MINUTES, SESSION_*, RATE_LIMIT_*, COOKIE_* |
EmailConfig |
SMTP_*, EMAIL_*, IMAP_* |
Comportement¶
- Chargées dans
RustwardenApp::build()au démarrage - Stockées dans des
Arc<Config>partagés via l'état axum - Modifier le
.envsans redémarrer n'a aucun effet - Ces variables ne sont PAS affichées dans l'interface admin
Liste des variables statiques (non exhaustive)¶
DATABASE_URL, SERVER_HOST, SERVER_PORT, RUST_LOG,
SSH_HOST_KEY_PATH, SSH_PORT, SSH_LISTEN_ADDR, SSH_PUBLIC_HOST,
JWT_SECRET, JWT_EXPIRATION_MINUTES, JWT_ISSUER,
REFRESH_TOKEN_EXPIRATION_DAYS, REMEMBER_ME_EXPIRATION_DAYS,
SESSION_TIMEOUT_MINUTES, SESSION_BACKEND,
RATE_LIMIT_LOGIN_PER_MINUTE, RATE_LIMIT_REFRESH_PER_MINUTE,
RATE_LIMIT_GENERAL_PER_MINUTE,
APP_DEBUG, COOKIE_SECURE, COOKIE_SAME_SITE,
ADMIN_USERNAME, ADMIN_EMAIL, ADMIN_PASSWORD,
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD, SMTP_FROM,
EMAIL_BASE_URL, EMAIL_QUEUE_*,
APP_NAME, APP_THEME, DEFAULT_LOCALE,
GIT_REPOS_BASE_PATH,
CI_ENABLED, CI_MAX_CONCURRENT, CI_REMOTE_HOST, CI_WORKSPACE_PATH
2. Configuration dynamique (table app_settings)¶
Principe¶
Les réglages dynamiques sont stockés en base PostgreSQL dans la table app_settings et lus à chaque requête via AppSettingsService. Ils sont modifiables à chaud par un administrateur depuis l'interface /admin/settings.
Schéma de la table¶
CREATE TABLE app_settings (
id UUID PRIMARY KEY,
key VARCHAR(100) UNIQUE NOT NULL,
value TEXT NOT NULL,
description TEXT,
updated_by UUID REFERENCES users(id) ON DELETE SET NULL,
updated_at TIMESTAMPTZ NOT NULL
);
Initialisation au démarrage¶
Au boot, AppSettingsService::initialize_default_settings() crée les réglages par défaut uniquement s'ils n'existent pas encore en base :
let existing = Self::get_setting(db, key).await?;
if existing.is_none() {
// ... insert valeur par défaut
}
Conséquence critique : une fois qu'un réglage existe en base (créé au premier démarrage ou modifié via l'UI), il n'est jamais écrasé par un redémarrage ultérieur.
Liste des réglages dynamiques et leurs valeurs par défaut¶
| Clé | Défaut | Description |
|---|---|---|
app_domain |
env::var("APP_DOMAIN") ou "localhost" |
Domaine de l'application |
allow_registration |
false |
Autoriser l'inscription publique |
validation_email_required |
true |
Exiger la validation email |
audit_log_level |
INFO |
Niveau de log d'audit |
audit_log_actions |
["create","update","delete","reset_password"] |
Actions auditées |
password_min_length |
8 |
Longueur minimum mot de passe |
password_require_uppercase |
false |
Exiger des majuscules |
password_require_lowercase |
false |
Exiger des minuscules |
password_require_digits |
false |
Exiger des chiffres |
password_require_special |
false |
Exiger des caractères spéciaux |
password_change_require_email |
true |
Confirmation email pour changement mdp |
password_expiration_enabled |
false |
Activer l'expiration des mots de passe |
password_expiration_days |
0 |
Durée d'expiration (jours) |
password_expiration_alert_enabled |
false |
Alerte email avant expiration |
password_expiration_alert_days_before |
7 |
Jours avant expiration pour alerter |
oauth_enabled |
false |
Activer OAuth/SSO |
oauth_google_enabled |
false |
Activer Google OAuth |
oauth_github_enabled |
false |
Activer GitHub OAuth |
oauth_discord_enabled |
false |
Activer Discord OAuth |
oauth_microsoft_enabled |
false |
Activer Microsoft OAuth |
oauth_redirect_base_url |
"" |
URL de base pour les callbacks OAuth |
oauth_auto_register |
true |
Créer un compte auto au premier login OAuth |
oauth_link_existing_account |
true |
Lier un compte OAuth à un utilisateur existant |
oauth_{provider}_client_id |
"" |
Client ID du provider OAuth |
oauth_{provider}_client_secret |
"" |
Client secret (chiffré AES-256-GCM en base) |
oauth_microsoft_tenant |
"" |
Tenant Azure AD |
3. Cas hybride : OAuth¶
OAuth est le seul sous-système qui combine les deux sources. La logique dans OAuthConfig::load() :
Pour chaque réglage OAuth :
1. Chercher dans app_settings (DB)
→ si trouvé et non vide : utiliser cette valeur
2. Sinon : fallback sur la variable d'environnement
→ si absente : utiliser la valeur par défaut codée en dur
Important : OAuthConfig::load() est appelé au démarrage. Le résultat est stocké dans un Arc et n'est pas relu dynamiquement. Donc :
- Modifier un réglage OAuth via l'UI admin nécessite un redémarrage pour que
OAuthConfigsoit rechargé - Le
.envn'est qu'un fallback si la DB n'a pas de valeur
4. Précédence et comportement au redémarrage¶
Réglages statiques (.env uniquement)¶
| Action | Effet immédiat | Après restart |
|---|---|---|
Modifier .env |
Non | Oui |
Réglages dynamiques (DB uniquement)¶
| Action | Effet immédiat | Après restart |
|---|---|---|
| Modifier via UI admin | Oui | Oui (valeur en DB persiste) |
Modifier le .env |
Aucun effet | Aucun effet |
Réglages hybrides (OAuth)¶
| Action | Effet immédiat | Après restart |
|---|---|---|
| Modifier via UI admin | Non (OAuthConfig est en Arc) | Oui (DB prime sur .env) |
Modifier .env |
Non | Seulement si aucune valeur en DB |
5. Piège principal : les variables .env fantômes¶
Certaines variables présentes dans .env.example donnent l'illusion de configurer des réglages qui sont en réalité gérés par la base de données :
Variable .env |
Réglage DB correspondant | La variable .env est-elle lue ? |
|---|---|---|
ALLOW_REGISTRATION=true |
allow_registration |
Non — valeur par défaut codée en dur ("false") |
EMAIL_VALIDATION_REQUIRED=true |
validation_email_required |
Non — valeur par défaut codée en dur ("true") |
OAUTH_ENABLED=true |
oauth_enabled |
Oui, mais seulement en fallback si la DB n'a pas de valeur |
Pour ALLOW_REGISTRATION et EMAIL_VALIDATION_REQUIRED :
- La variable
.envest documentée dans.env.examplemais n'est jamais consultée parinitialize_default_settings() - La valeur initiale est codée en dur dans le service
- Seule la valeur en base de données (modifiable via
/admin/settings) fait foi
Pour app_domain, c'est le seul réglage dynamique qui lit le .env comme seed initial.
6. Diagramme de décision¶
┌─────────────────────────────┐
│ Quel type de réglage ? │
└──────────┬──────────────────-┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
Infrastructure Fonctionnel OAuth
(port, JWT, SMTP) (inscription, (providers,
mots de passe) secrets)
│ │ │
▼ ▼ ▼
.env seul DB seule DB + fallback .env
│ │ │
▼ ▼ ▼
Restart requis Effet immédiat Restart requis
via /admin/ (OAuthConfig en Arc)
settings
7. Guide pour les administrateurs¶
Modifier un réglage d'infrastructure¶
Éditer .env (ou .env.production) puis redémarrer le service :
Modifier un réglage fonctionnel¶
Se connecter en tant qu'administrateur, aller dans /admin/settings, modifier la valeur, et cliquer "Save". L'effet est immédiat, aucun redémarrage nécessaire.
Modifier un réglage OAuth¶
Via /admin/settings, modifier les valeurs OAuth puis redémarrer le service (la config OAuth est chargée en mémoire au boot et n'est pas relue dynamiquement).
Vérifier la valeur effective d'un réglage¶
Pour les réglages dynamiques, interroger la base directement :
Pour les réglages statiques, vérifier les logs au démarrage (RUST_LOG=debug).
8. Guide pour les développeurs¶
Ajouter un nouveau réglage dynamique¶
-
Ajouter le tuple
(clé, valeur_défaut, description)dansAppSettingsService::initialize_default_settings(): -
Lire la valeur dans le code via le service :
-
La valeur apparaîtra automatiquement dans
/admin/settings.
Ajouter un nouveau réglage statique¶
- Ajouter la variable dans
.env.exampleavec documentation complète - Lire la variable dans le struct
Configcorrespondant viaenv::var() - La valeur ne sera pas visible dans l'interface admin
Ajouter un réglage hybride (DB + fallback .env)¶
Suivre le pattern OAuth dans crates/rustwarden-core/src/config/oauth.rs :