Architecture overview¶
Gitrust is a self-hosted Git hosting platform built on the rustwarden-core framework. The application exposes two network entry points (HTTP + SSH) and persists its data in PostgreSQL.
Overview¶
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
Starting the application¶
The following diagram details the initialization sequence from main() to starting the HTTP and SSH servers.
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
Design principles¶
Framework/business separation gitrust¶
Gitrust is built on top of rustwarden-core, a Rust authentication and user management framework. This separation is intentional:
- rustwarden-core manages: JWT auth, sessions, users, generic roles, i18n, SMTP, OAuth, generic audit log.
- gitrust-core manages: everything specific to the Git forge — repositories, SSH keys, teams, 4-level RBAC permissions, CI, repository import.
The fundamental rule: never modify crates/rustwarden-core/. Any extension goes through wrappers, hooks (RustwardenHooks) or features implemented on the gitrust side.
Headless mode¶
gitrust-web operates in headless() mode: the standard rustwarden UI pages (login, register, settings) are deactivated and reimplemented entirely in gitrust-web/templates/. This allows a coherent design (Git sidebar, DaisyUI) without compromising with the generic UI of the framework.
SSR + HTMX, zero CDN¶
The interface is rendered server-side via Askama (compiled Rust templates). HTMX manages dynamic interactions (partial page updates, SSE for notifications and CI logs). No external assets: all CSS/JS is served from static/ — imposed by the framework's Content Security Policy.
Bare rest on file system¶
gitrust-git is decoupled from the database. Git operations (tree navigation, blob reading, pack protocol) work directly on bare repos ({GIT_REPOS_BASE_PATH}/{owner}/{slug}.git/) via libgit2. The database only stores metadata (name, description, visibility, ownership). This decoupling allows gitrust-git to be replaced or tested independently.
Hybrid CI: Dagger as execution abstraction¶
Rather than implementing a CI runner from scratch, gitrust delegates execution to Dagger, which guarantees isolation (containers), reproducibility (cache) and portability (local or remote runner via SSH+rsync). The CiWorker is a Tokio task in the main process — not a separate daemon — which simplifies deployment (a single binary).
To go further¶
- Référence structurelle complète (tables de modules, routes, dépendances) : Architecture des crates
- Diagrammes de séquence détaillés (clone SSH, push, permissions) : Flux de requêtes
- Conception de la couche de durcissement SSH : Conception de ssh-guard et Crate gitrust-ssh-guard
- Règles de code et gates QA : Règles QA et conformité ANSSI