Parametri dinamici

Questo documento spiega come funziona la configurazione della piattaforma, i due meccanismi in gioco, la loro precedenza e le insidie ​​​​di cui essere consapevoli.


Panoramica: due sistemi separati

Gitrust utilizza due sistemi di configurazione indipendenti:

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)

Esiste un caso ibrido per OAuth (DB prioritario, .env in fallback).


1. Configurazione statica (.env)

Principio

Le variabili d'ambiente vengono caricate una volta all'avvio da dotenvy::dotenv() e archiviate in strutture Rust immutabili. Non vengono mai più letti dopo l'avvio.

File di riferimento

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

Strutture di carico

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_*

Comportamento

  • Caricato in RustwardenApp::build() all'avvio
  • Memorizzato in "Arc" condiviso tramite axum state
  • La modifica di .env senza riavviare non ha alcun effetto
  • Queste variabili NON vengono visualizzate nell'interfaccia di amministrazione

Elenco delle variabili statiche (non esaustivo)

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. Configurazione dinamica (tabella app_settings)

Principio

Le impostazioni dinamiche vengono archiviate nel database PostgreSQL nella tabella "app_settings" e lette su ogni richiesta tramite "AppSettingsService". Possono essere modificati al volo da un amministratore dall'interfaccia /admin/settings.

Diagramma della tabella

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
);

Inizializzazione all'avvio

All'avvio, AppSettingsService::initialize_default_settings() crea le impostazioni predefinite solo se non esistono ancora in base:

let existing = Self::get_setting(db, key).await?;
if existing.is_none() {
    // ... insert valeur par défaut
}

Conseguenza critica: una volta che un'impostazione esiste in base (creata al primo avvio o modificata tramite l'interfaccia utente), essa non viene mai sovrascritta al successivo riavvio.

Elenco delle impostazioni dinamiche e dei relativi valori predefiniti

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. Caso ibrido: OAuth

OAuth è l'unico sottosistema che combina entrambe le origini. La logica in 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

Importante: OAuthConfig::load() viene chiamato all'avvio. Il risultato viene memorizzato in un "Arco" e non viene riprodotto dinamicamente. COSÌ :

  • La modifica di un'impostazione OAuth tramite l'interfaccia utente di amministrazione richiede un riavvio per il ricaricamento di OAuthConfig
  • Il .env è solo un fallback se il DB non ha valore

4. Precedenza e comportamento di riavvio

Impostazioni statiche (solo .env)

Action Effet immédiat Après restart
Modifier .env Non Oui

Impostazioni dinamiche (solo DB)

Action Effet immédiat Après restart
Modifier via UI admin Oui Oui (valeur en DB persiste)
Modifier le .env Aucun effet Aucun effet

Impostazioni ibride (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. Principale trappola: variabili fantasma .env

Alcune variabili presenti in .env.example danno l'illusione di configurare impostazioni che in realtà sono gestite dal database:

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

Per "ALLOW_REGISTRATION" e "EMAIL_VALIDATION_REQUIRED":

  • La variabile .env è documentata in .env.example ma non è mai accessibile da initialize_default_settings()
  • Il valore iniziale è hardcoded nel servizio
  • Solo il valore nel database (modificabile tramite /admin/settings) è autentico

Per "app_domain", questa è l'unica impostazione dinamica che legge ".env" come seed iniziale.


6. Diagramma decisionale

                    ┌─────────────────────────────┐
                    │  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. Guida per gli amministratori

Modificare un'impostazione dell'infrastruttura

Modifica .env (o .env.production) quindi riavvia il servizio:

# Éditer
vim .env

# Redémarrer
systemctl restart gitrust    # production
# ou Ctrl+C + cargo run      # dev

Modificare un'impostazione funzionale

Accedi come amministratore, vai su /admin/settings, modifica il valore e fai clic su "Salva". L'effetto è immediato, non è necessario riavviare.

Modifica un'impostazione OAuth

Tramite /admin/settings, modifica i valori OAuth quindi riavvia il servizio (la configurazione OAuth viene caricata in memoria all'avvio e non viene riletta dinamicamente).

Controllare il valore effettivo di un'impostazione

Per le impostazioni dinamiche, interroga direttamente il database:

SELECT key, value, updated_at, updated_by
FROM app_settings
WHERE key = 'allow_registration';

Per le impostazioni statiche, controlla i log all'avvio (RUST_LOG=debug).


8. Guida per gli sviluppatori

Aggiungi una nuova impostazione dinamica

  1. Aggiungi la tupla (key, default_value, description) in AppSettingsService::initialize_default_settings():

    ("ma_nouvelle_cle", "valeur_par_defaut", Some("Description pour l'UI admin")),
    

  2. Leggi il valore nel codice tramite il servizio:

    // Boolean avec défaut
    let enabled = AppSettingsService::get_bool(&db, "ma_nouvelle_cle", false).await?;
    
    // String
    let val = AppSettingsService::get_setting(&db, "ma_nouvelle_cle").await?;
    

  3. Il valore verrà visualizzato automaticamente in "/admin/settings".

Aggiungi una nuova impostazione statica

  1. Aggiungi la variabile in .env.example con la documentazione completa
  2. Leggi la variabile nella struttura Config corrispondente tramite env::var()
  3. Il valore non sarà visibile nell'interfaccia di amministrazione

Aggiungi impostazione ibrida (DB + fallback .env)

Segui il modello OAuth in crates/rustwarden-core/src/config/oauth.rs:

let ma_valeur = match db_val("ma_cle").await {
    Some(v) => v,
    None => env::var("MA_CLE").unwrap_or_else(|_| "defaut".to_string()),
};