Dynamische Parameter

In diesem Dokument wird erläutert, wie die Konfiguration der Plattform funktioniert, welche beiden Mechanismen im Spiel sind, welche Priorität sie haben und welche Fallstricke es zu beachten gilt.


Überblick: zwei separate Systeme

Gitrust verwendet zwei unabhängige Konfigurationssysteme:

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)

Es gibt einen Hybridfall für OAuth (Prioritäts-DB, „.env“ im Fallback).


1. Statische Konfiguration (.env)

Prinzip

Umgebungsvariablen werden einmal beim Start von „dotenvy::dotenv()“ geladen und in unveränderlichen Rust-Strukturen gespeichert. Sie werden nach dem Booten nie wieder gelesen.

Referenzdateien

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

Laden von Strukturen

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

Verhalten

  • Wird beim Start in „RustwardenApp::build()“ geladen
  • Gespeichert in „Arc“, geteilt über den Axum-Status
  • Das Ändern der „.env“ ohne Neustart hat keine Auswirkung
  • Diese Variablen werden NICHT in der Admin-Oberfläche angezeigt

Liste statischer Variablen (nicht erschöpfend)

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. Dynamische Konfiguration (Tabelle „app_settings“)

Prinzip

Dynamische Einstellungen werden in der PostgreSQL-Datenbank in der Tabelle „app_settings“ gespeichert und bei jeder Anfrage über „AppSettingsService“ gelesen. Sie können von einem Administrator über die Schnittstelle „/admin/settings“ im laufenden Betrieb geändert werden.

Tabellendiagramm

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

Initialisierung beim Start

Beim Booten erstellt „AppSettingsService::initialize_default_settings()“ die Standardeinstellungen nur wenn sie noch nicht in der Basis vorhanden sind:

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

Kritische Konsequenz: Sobald eine Einstellung in der Basis vorhanden ist (beim ersten Start erstellt oder über die Benutzeroberfläche geändert), wird sie bei einem nachfolgenden Neustart niemals überschrieben.

Liste der dynamischen Einstellungen und ihrer Standardwerte

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. Hybridfall: OAuth

OAuth ist das einzige Subsystem, das beide Quellen kombiniert. Die Logik 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

Wichtig: „OAuthConfig::load()“ wird beim Start aufgerufen. Das Ergebnis wird in einem „Arc“ gespeichert und nicht dynamisch wiedergegeben. ALSO :

  • Das Ändern einer OAuth-Einstellung über die Admin-Benutzeroberfläche erfordert einen Neustart, damit „OAuthConfig“ neu geladen wird
  • Die „.env“ ist nur ein Fallback, wenn die Datenbank keinen Wert hat

4. Vorrang und Neustartverhalten

Statische Einstellungen (nur „.env“)

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

Dynamische Einstellungen (nur 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

Hybrideinstellungen (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. Hauptfalle: Geister-„.env“-Variablen

Bestimmte in „.env.example“ vorhandene Variablen erwecken die Illusion, Einstellungen zu konfigurieren, die in Wirklichkeit von der Datenbank verwaltet werden:

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

Für „ALLOW_REGISTRATION“ und „EMAIL_VALIDATION_REQUIRED“:

  • Die Variable „.env“ ist in „.env.example“ dokumentiert, wird aber von „initialize_default_settings()“ niemals aufgerufen
  • Der Anfangswert ist im Dienst fest codiert
  • Nur der Wert in der Datenbank (änderbar über „/admin/settings“) ist authentisch

Für „app_domain“ ist dies die einzige dynamische Einstellung, die „.env“ als anfänglichen Startwert liest.


6. Entscheidungsdiagramm

                    ┌─────────────────────────────┐
                    │  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. Leitfaden für Administratoren

Ändern Sie eine Infrastruktureinstellung

Bearbeiten Sie „.env“ (oder „.env.produktion“) und starten Sie dann den Dienst neu:

# Éditer
vim .env

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

Ändern Sie eine Funktionseinstellung

Melden Sie sich als Administrator an, gehen Sie zu „/admin/settings“, ändern Sie den Wert und klicken Sie auf „Speichern“. Der Effekt ist sofort, kein Neustart erforderlich.

Ändern Sie eine OAuth-Einstellung

Ändern Sie über „/admin/settings“ die OAuth-Werte und starten Sie dann den Dienst neu (die OAuth-Konfiguration wird beim Booten in den Speicher geladen und nicht dynamisch erneut gelesen).

Überprüfen Sie den tatsächlichen Wert einer Einstellung

Für dynamische Einstellungen fragen Sie die Datenbank direkt ab:

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

Überprüfen Sie für statische Einstellungen die Protokolle beim Start („RUST_LOG=debug“).


8. Leitfaden für Entwickler

Fügen Sie eine neue dynamische Einstellung hinzu

  1. Fügen Sie das Tupel „(key, default_value, description)“ in „AppSettingsService::initialize_default_settings()“ hinzu:

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

  2. Lesen Sie den Wert im Code über den Dienst:

    // 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. Der Wert wird automatisch in „/admin/settings“ angezeigt.

Fügen Sie eine neue statische Einstellung hinzu

  1. Fügen Sie eine Variable in „.env.example“ mit vollständiger Dokumentation hinzu
  2. Lesen Sie die Variable in der entsprechenden „Config“-Struktur über „env::var()“.
  3. Der Wert wird in der Admin-Oberfläche nicht sichtbar sein

Hybrideinstellung hinzufügen (DB + Fallback .env)

Folgen Sie dem OAuth-Muster 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()),
};