Parámetros dinámicos

Este documento explica cómo funciona la configuración de la plataforma, los dos mecanismos en juego, su precedencia y los peligros que se deben tener en cuenta.


Resumen: dos sistemas separados

Gitrust utiliza dos sistemas de configuración independientes:

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)

Hay un caso híbrido para OAuth (base de datos prioritaria, .env como alternativa).


1. Configuración estática (.env)

Principio

Las variables de entorno se cargan una vez al inicio mediante dotenvy::dotenv() y se almacenan en estructuras Rust inmutables. Nunca se vuelven a leer después del arranque.

Archivos de referencia

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

Estructuras de carga

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

Comportamiento

  • Cargado en RustwardenApp::build() al inicio
  • Almacenado en Arc<Config> compartido a través del estado axum
  • Cambiar el .env sin reiniciar no tiene ningún efecto
  • Estas variables NO se muestran en la interfaz de administración

Lista de variables estáticas (no exhaustiva)

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. Configuración dinámica (tabla app_settings)

Principio

Las configuraciones dinámicas se almacenan en la base de datos PostgreSQL en la tabla app_settings y se leen en cada solicitud a través de AppSettingsService. Un administrador puede modificarlos sobre la marcha desde la interfaz /admin/settings.

Diagrama de tabla

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

Inicialización al inicio

En el arranque, AppSettingsService::initialize_default_settings() crea la configuración predeterminada solo si aún no existe en la base:

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

Consecuencia crítica: una vez que existe una configuración en la base (creada en el primer inicio o modificada a través de la interfaz de usuario), nunca se sobrescribe en un reinicio posterior.

Lista de configuraciones dinámicas y sus valores predeterminados

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 híbrido: OAuth

OAuth es el único subsistema que combina ambas fuentes. La lógica en 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() se llama al inicio. El resultado se almacena en un "Arc" y no se reproduce dinámicamente. ENTONCES :

  • Cambiar una configuración de OAuth a través de la interfaz de usuario del administrador requiere un reinicio para que se vuelva a cargar OAuthConfig
  • El .env es solo un recurso alternativo si la base de datos no tiene valor

4. Comportamiento de precedencia y reinicio

Configuraciones estáticas (solo .env)

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

Configuraciones dinámicas (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

Configuración híbrida (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. Error principal: variables fantasma .env

Ciertas variables presentes en .env.example dan la ilusión de configurar ajustes que en realidad son administrados por la base de datos:

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

Para ALLOW_REGISTRATION y EMAIL_VALIDATION_REQUIRED:

  • La variable .env está documentada en .env.example pero nunca se accede a ella mediante initialize_default_settings()
  • El valor inicial está codificado en el servicio.
  • Sólo el valor en la base de datos (modificable a través de /admin/settings) es auténtico

Para app_domain, esta es la única configuración dinámica que lee .env como semilla inicial.


6. Diagrama de decisión

                    ┌─────────────────────────────┐
                    │  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. Guía para administradores

Cambiar una configuración de infraestructura

Edite .env (o .env.production) y luego reinicie el servicio:

# Éditer
vim .env

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

Cambiar una configuración funcional

Inicie sesión como administrador, vaya a /admin/settings, modifique el valor y haga clic en "Guardar". El efecto es inmediato, no es necesario reiniciar.

Cambiar una configuración de OAuth

A través de /admin/settings, modifique los valores de OAuth y luego reinicie el servicio (la configuración de OAuth se carga en la memoria durante el arranque y no se vuelve a leer dinámicamente).

Verifique el valor real de una configuración

Para configuraciones dinámicas, consulte la base de datos directamente:

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

Para configuraciones estáticas, verifique los registros al inicio (RUST_LOG=debug).


8. Guía para desarrolladores

Agregar una nueva configuración dinámica

  1. Agregue la tupla (clave, valor_predeterminado, descripción) en AppSettingsService::initialize_default_settings():

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

  2. Lea el valor en el código a través del servicio:

    // 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. El valor aparecerá automáticamente en /admin/settings.

Agregar una nueva configuración estática

  1. Agregue variable en .env.example con documentación completa
  2. Lea la variable en la estructura Config correspondiente a través de env::var()
  3. El valor no será visible en la interfaz de administración.

Agregar configuración híbrida (DB + respaldo .env)

Siga el patrón OAuth en 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()),
};