Vue d'ensemble de l'architecture

Gitrust est une plateforme d'hébergement Git auto-hébergée construite sur le framework rustwarden-core. L'application expose deux points d'entrée réseau (HTTP + SSH) et persiste ses données dans PostgreSQL.

Vue d'ensemble

graph TB
    subgraph Clients
        Browser["Navigateur Web"]
        GitCLI["Git CLI (ssh/https)"]
    end

    subgraph "Gitrust Binary (src/main.rs)"
        Main["main()"]
    end

    subgraph "Crates Gitrust"
        Web["gitrust-web
Routes HTTP, templates,
handlers Axum
"] SSH["gitrust-ssh
Serveur SSH (russh),
auth par clé, sessions
"] SshGuard["gitrust-ssh-guard
SecureListener, détecteurs,
BanManager, AuthTracker
"] Hooks["gitrust-hooks
impl RustwardenHooks
(on_user_registered, ...)
"] Core["gitrust-core
Models, services, migrations,
rôles, types, DTOs
"] Git["gitrust-git
Bare repos, tree browser,
pack protocol (git2)
"] end subgraph "Framework" RW["rustwarden-core
Auth, users, JWT, sessions,
ResourceService, i18n
"] end subgraph "Stockage" PG[(PostgreSQL)] FS[("Système de fichiers
bare repos .git")] end subgraph "CI/CD (optionnel)" CiWorker["CiWorker
tokio::spawn, mpsc,
sous-processus Dagger
"] Dagger["Dagger Engine
Containers isolés,
cache, exécution
"] CiEngine["ci-engine
Module Dagger Python
(Easy Mode)
"] Syft["Syft (optionnel)
Génération SBOM
CycloneDX
"] DTrack["Dependency-Track
(optionnel)
Analyse vulnérabilités"] end Browser -->|HTTP :4000| Web GitCLI -->|SSH :2222| SshGuard SshGuard -->|"AcceptOutcome::Accepted"| SSH GitCLI -->|HTTPS :4000| Web Main --> Web Main --> SSH Main --> SshGuard Main --> Hooks Main -.->|"si CI_ENABLED"| CiWorker Web --> Core Web --> Git Web -.->|"admin ACL/ban"| SshGuard SSH --> Core SSH --> Git SSH --> SshGuard SshGuard --> Core Hooks --> Core Core --> RW Core --> PG Git --> FS CiWorker --> Core CiWorker -->|"dagger call"| Dagger Dagger -->|"Easy Mode"| CiEngine Dagger -->|"Power Mode"| FS CiWorker -.->|"si CI_SBOM_ENABLED"| Syft Syft -.->|"si CI_DTRACK_ENABLED"| DTrack

Démarrage de l'application

Le diagramme suivant détaille la séquence d'initialisation depuis main() jusqu'au démarrage des serveurs HTTP et SSH.

sequenceDiagram
    participant Main as main()
    participant Builder as RustwardenBuilder
    participant App as RustwardenApp
    participant Mig as AppMigrator
    participant DB as PostgreSQL
    participant SMTP as Serveur SMTP

    Main->>Main: GitrustConfig::from_env()
    Main->>Main: Arc (hooks FS)

    Main->>Builder: builder().from_env()
    Note over Builder: Charge .env, init tracing
    Main->>Builder: .headless().auto_migrate(false)
    Main->>Builder: .merge_routes(app_routes(hooks))
    Note over Builder: Routes = framework API
+ pages SSR gitrust
+ Extension(hooks) Main->>Builder: .build().await Builder->>DB: Connexion pool Builder->>DB: Migrations rustwarden-core Builder->>SMTP: EmailQueueProcessor.start() Note over SMTP: Worker de fond : dépile
email_queue toutes les 30s Builder-->>Main: RustwardenApp Main->>Mig: run_migrations(app.database()) Mig->>DB: core_migrations() + gitrust_migrations() Note over DB: Tables: users, resources,
repositories, ssh_keys,
teams, team_members,
team_repository_access Mig-->>Main: Ok Main->>Main: tokio::spawn(SSH server :2222) alt CI_ENABLED=true Main->>Main: CiWorker::start(config.ci) Note over Main: Vérifie dagger dans PATH
Si CI_SBOM_ENABLED: vérifie syft
Si CI_DTRACK_ENABLED: vérifie API DT Main->>Main: tokio::spawn(CiWorker loop) Note over Main: Écoute mpsc channel
pour les jobs CI end Main->>App: app.run().await Note over App: HTTP :4000 démarre

Principes de conception

Séparation framework / métier gitrust

Gitrust est construit au-dessus de rustwarden-core, un framework Rust d'authentification et de gestion d'utilisateurs. Cette séparation est intentionnelle :

  • rustwarden-core gère : auth JWT, sessions, users, roles génériques, i18n, SMTP, OAuth, audit log générique.
  • gitrust-core gère : tout ce qui est spécifique à la forge Git — dépôts, clés SSH, équipes, permissions RBAC à 4 niveaux, CI, import de dépôts.

La règle fondamentale : ne jamais modifier crates/rustwarden-core/. Toute extension passe par des wrappers, des hooks (RustwardenHooks) ou des traits implémentés côté gitrust.

Mode headless

gitrust-web opère en mode headless() : les pages UI standard de rustwarden (login, register, settings) sont désactivées et réimplémentées entièrement dans gitrust-web/templates/. Cela permet un design cohérent (sidebar Git, DaisyUI) sans compromis avec l'UI générique du framework.

SSR + HTMX, zéro CDN

L'interface est rendue côté serveur via Askama (templates Rust compilés). HTMX gère les interactions dynamiques (mises à jour partielles de page, SSE pour les notifications et les logs CI). Aucun asset externe : tout CSS/JS est servi depuis static/ — imposé par la Content Security Policy du framework.

Bare repos sur le système de fichiers

gitrust-git est découplé de la base de données. Les opérations Git (navigation d'arbre, lecture de blobs, pack protocol) travaillent directement sur les bare repos ({GIT_REPOS_BASE_PATH}/{owner}/{slug}.git/) via libgit2. La base ne stocke que les métadonnées (nom, description, visibilité, ownership). Ce découplage permet de remplacer ou tester gitrust-git indépendamment.

CI hybride : Dagger comme abstraction d'exécution

Plutôt que d'implémenter un runner CI from scratch, gitrust délègue l'exécution à Dagger, qui garantit l'isolation (containers), la reproductibilité (cache) et la portabilité (local ou runner distant via SSH+rsync). Le CiWorker est une tâche Tokio dans le processus principal — pas un daemon séparé — ce qui simplifie le déploiement (un seul binaire).


Pour aller plus loin