Architettura per casse

riferimento strutturale gitrust: casse, moduli, percorsi, dipendenze e componenti CI.

Dipendenze tra casse

graph LR
    RW["rustwarden-core"]

    Git["gitrust-git"]
    Core["gitrust-core"]
    Hooks["gitrust-hooks"]
    SSH["gitrust-ssh"]
    SshGuard["gitrust-ssh-guard"]
    Web["gitrust-web"]
    Bin["gitrust (binaire)"]

    Core --> RW
    Git -.->|"indépendant
(git2, tokio)"| RW Hooks --> Core Hooks --> RW SSH --> Core SSH --> Git SSH --> SshGuard SshGuard -.->|"SeaORM bans/ACL/events"| Core Web --> Core Web --> Git Web -.->|"CI pages"| Git Web -.->|"admin ACL/ban via Extension"| SshGuard Bin --> Core Bin --> Git Bin --> SSH Bin --> SshGuard Bin --> Web Bin --> Hooks Bin --> RW subgraph "Externes CI (Phase 5b)" Dagger["Dagger CLI"] CiEng["ci-engine (Python)"] Syft["Syft"] DTrack["Dependency-Track"] end Core -.->|"CiWorker
sous-processus"| Dagger Dagger -.-> CiEng Core -.-> Syft Syft -.-> DTrack

Casse – Responsabilità

gitrust-core

Attività principale. Dipende solo dalle casse Rust standard e con nucleo antiruggine.

Module Rôle
config GitrustConfig::from_env() — ports SSH, chemin repos, limites
error GitrustError — erreurs domaine Git + IntoResponse HTTP
roles enum Role { Reader, Developer, Maintainer, Owner } avec Ord
types Newtypes validés : RepoSlug, TeamSlug, Fingerprint, TokenHash
models/ Entités SeaORM : repository, ssh_key, team, team_member, team_repository_access, ci_pipeline, ci_job, ci_log, ci_config, ci_variable
migrations/ Migrations SeaORM (tables gitrust) combinées avec les migrations core
services/ SshKeyService, RepositoryService, TeamService, AccessService, CiService, CiVariableService, CiDetectionService, CiWorker, NotificationService
dto/ Structures d'entrée/sortie pour les services

gitrust-git

Operazioni Git sul file system. Utilizza "git2" (libgit2). Nessuna dipendenza dal database.

Module Rôle
errors enum GitError (Git, RepoNotFound, RefNotFound, PathTraversal, ...)
bare_repo Init, open, delete, exists + validation chemin canonique sous base
branch / tag Listing branches (BranchInfo) et tags (TagInfo, annotated/lightweight)
reference resolve_ref (branch -> tag -> SHA -> revparse)
tree_browser list_tree (dirs first, sorted), TreeEntry, EntryKind
blob_reader read_blob -> Text/Binary, détection binaire (null bytes)
commit_log list_commits (paginé), find_commit, CommitInfo
readme find_readme (README.md > README > readme.md > ...)
pack_protocol advertise_refs, serve_pack (async, git-upload-pack/git-receive-pack)

gitrust-ssh

Server SSH basato su "russh". Autenticazione con chiave pubblica.

Module (prévu) Rôle
server Démarrage, génération clé hôte Ed25519, wrapper du TcpListener par SecureListener (ssh-guard)
auth Authentification par fingerprint -> SshKeyService, appel à AuthTracker.record_auth_attempt après chaque tentative
session Handler SSH (exec, shell), porte ClientIdentity du listener jusqu'aux décisions auth
command_handler Parsing git-upload-pack/git-receive-pack

gitrust-ssh-guard

Couche de durcissement SSH intercalée entre le TcpListener et russh. Voir la page dédiée Crate gitrust-ssh-guard pour le détail des modules et l'API publique. Synthèse :

Module Rôle
config GuardConfig::from_env() — lecture SSH_GUARD_*, sélection DeploymentProfile, validation
runtime GuardHandles::build(db) — assemblage partageable entre serveur SSH et routeur admin
listener SecureListener wrappe TcpListener : extraction IP réelle (PROXY v1/v2), ACL, flood, retour AcceptOutcome
proxy Parseur PROXY protocol v1/v2 avec timeout
identity ClientIdentity — IP + session_id + user/fingerprint enrichis pendant l'auth
tracker AuthTracker — persiste, émet, dispatche aux détecteurs
ban BanManager + EffectiveStatus — priorité deny > auto_ban > allow > default
events GuardEvent — schéma JSON stable (tag = "event") pour fail2ban / SIEM
sinks TracingSink, FileSink, MultiSink — destination des événements
detector/{brute_force,user_enumeration,key_scanning,connection_flood} 4 motifs d'attaque, push-based
store/{memory,postgres,hybrid} Backend bans/ACL/events — hybrid (RAM + write-through) par défaut

gitrust-web

Interfaccia web SSR (Server-Side Rendering) con Askama (modelli compilati) + HTMX (interazioni dinamiche). Funziona in modalità headless(): le pagine dell'interfaccia utente del framework (rustwarden-ui) non sono montate, gitrust-web reimplementa tutte le pagine con un design specifico (barra laterale contestuale, navigazione Git, DaisyUI).

Architettura stradale:

gitrust (port 4000)
├── /api/v1/auth/*          ← Routes API du framework (JSON)
│   ├── POST /login            AuthService::authenticate_user
│   ├── POST /register         UserService::create_user
│   ├── POST /refresh          RefreshTokenService (rotation JWT)
│   ├── POST /logout           JwtBlacklistService
│   ├── GET  /me               Claims extraction
│   ├── POST /forgot-password  PasswordResetService::request_reset
│   ├── POST /reset-password   PasswordResetService::reset_password
│   ├── GET  /verify-email/{t} EmailValidationService::verify_email
│   └── POST /resend-verif     EmailValidationService::resend
├── /api/v1/*                ← API REST Gitrust (JSON, auth JWT/PAT)
│   ├── /user, /user/repos     Profil utilisateur
│   ├── /repos/{o}/{r}         Détail dépôt, branches, tags, commits
│   ├── /repos/{o}/{r}/issues  CRUD issues + commentaires
│   ├── /repos/{o}/{r}/pulls   CRUD PRs + merge
│   └── /repos/{o}/{r}/ci/*   Pipelines CI (list, trigger, cancel, logs)
├── /*                       ← Pages SSR gitrust (HTML)
│   ├── /login, /register       Pages formulaires (design gitrust)
│   ├── /dashboard, /teams      Pages utilisateur
│   ├── /settings/*             Profile, SSH keys, sessions, notifications
│   ├── /notifications          Liste notifications + SSE stream
│   ├── /admin/*                Administration (+ admin CI)
│   ├── /{owner}/{repo}/*       Navigation dépôt Git
│   └── /{owner}/{repo}/ci/*    Pages CI (pipelines, logs, config, variables)
└── /static/*                ← Assets locaux (CSS, JS, HTMX)

Les routes API du framework sont montées via framework_api_routes() dans routes.rs. Elles sont utilisées par : - Collegamenti nelle e-mail (verifica, reimpostazione password) - Il token di aggiornamento (rotazione JWT, sessione a lungo termine) - Accesso programmatico (GET /me, POST /logout)

Le pagine SSR e i percorsi API coesistono: i moduli HTML vengono inviati ai gestori gitrust (SSR), mentre i servizi framework generano collegamenti ai percorsi API.

Module Rôle
routes.rs Routeur principal : framework API + API REST Gitrust + pages SSR + fichiers statiques
handlers/ Handlers Axum SSR (un fichier par domaine) + handlers API JSON
templates.rs Structs Askama + SidebarContext + RepoNav
helpers.rs require_auth, require_admin, sidebar_*, resolve_repo_access
templates/ Templates HTML (Askama, extends base.html)
static_files.rs ServeDir pour /static

ganci gitrust

Implementato "RustwardenHooks" per reagire agli eventi del framework. Gli hook vengono inseriti nel router Axum tramite Arc<dyn RustwardenHooks> + axum::Extension (in main.rs).

Hook Action
on_user_registered Crée le répertoire utilisateur sur le FS (anti path-traversal)
on_user_deleted Supprime le répertoire utilisateur + bare repos sur le FS
on_resource_shared Audit log si resource_type = "repository"
on_resource_unshared Audit log si resource_type = "repository"

Notifiche

Sistema di notifica a due canali: in-app (SSE in tempo reale + pagina) e email (framework SMTP work).

Événement (pipeline échoue, PR commentée, etc.)
NotificationService::notify(user_id, event_type, title, body, link)
    ├── INSERT INTO notifications (in-app)
    │     → broadcast::Sender → SSE /notifications/stream
    │     → Badge header mis à jour en temps réel (HTMX)
    └── if user.email_on_{event} = true:
          EmailQueueService::enqueue() (framework SMTP worker)

Le preferenze di notifica sono per utente (email attivata/disattivata per tipo di evento).


CI/CD: modalità e componenti

Sistema CI ibrido a due livelli, abilitato tramite "CI_ENABLED=true".

Mode

Mode Détection Exécution
Easy .gitrust-ci.yml à la racine du repo Module Dagger Python générique (ci-engine) interprète le YAML
Power .dagger/ à la racine du repo dagger call -m .dagger/ exécute le module utilisateur directement
Aucun Ni l'un ni l'autre Pas de CI pour ce repo

Architettura CI

git push (HTTP ou SSH)
receive-pack handler
    ├── CiDetectionService::detect(bare_repo, commit_sha)
    │     → Easy / Power / None
    ├── CiService::create_pipeline(repo_id, sha, mode)
    └── mpsc::Sender.send(job) ──► CiWorker (tokio::spawn)
                                       ├── 1. Validation statique
                                       │     Easy: schéma YAML, whitelist images/packages
                                       │     Power: analyse code .dagger/ (si activé)
                                       ├── 2. SBOM Gate (si CI_SBOM_ENABLED)
                                       │     syft scan → sbom.cdx.json
                                       │     → Dependency-Track (si CI_DTRACK_ENABLED)
                                       │     → PASS/FAIL selon politique
                                       ├── 3. Résolution variables (héritage team → repo)
                                       │     CiVariableService::resolve_for_pipeline()
                                       ├── 4. Exécution Dagger (isolé, timeout, cgroups)
                                       │     Easy: dagger call -m ci-engine test --profile=...
                                       │     Power: dagger call -m .dagger/ <function>
                                       └── 5. Rapport + audit
                                             Status, logs (broadcast SSE), ci_audit_log

Componenti esterni (tutti opzionali tranne Dagger)

Composant Rôle Variable de contrôle
Dagger Engine Exécution des pipelines dans des containers isolés CI_ENABLED
ci-engine (Python) Moteur générique pour Easy Mode CI_DAGGER_MODULE_PATH
Syft Génération SBOM CycloneDX CI_SBOM_ENABLED
Dependency-Track Analyse de vulnérabilités sur les SBOM CI_DTRACK_ENABLED

Variabili CI e segreti

Ereditarietà team → repository: le variabili definite a livello di team sono condivise tra tutti i repository del team. Il repository può sovraccaricare una chiave del team con il proprio valore. I segreti sono crittografati di base (AES-256-GCM) e nascosti nei registri (***).


Sicurezza (ANSSI PA-074)

Directive Scope
#![forbid(unsafe_code)] gitrust-core, gitrust-web, gitrust-hooks, gitrust-ssh-guard
#![deny(unsafe_code)] gitrust-git, gitrust-ssh (FFI libgit2/russh)
deny(clippy::unwrap_used, expect_used, panic) Tous les crates
deny(clippy::indexing_slicing) Tous les crates
deny(clippy::mem_forget) Tous les crates
Zeroize on drop TokenHash (ANSSI R23)
RSA minimum 4096 bits SshKeyService
Path traversal validation RepositoryService, gitrust-git
Slug validation + noms réservés RepoSlug, TeamSlug