Flusso di query¶
Diagrammi di sequenza che coprono le principali operazioni di gitrust: creazione del repository, clone e push SSH, registrazione della chiave SSH, risoluzione dei permessi, navigazione web, registrazione dell'utente.
1. Creazione di un repository (Web)¶
sequenceDiagram
actor User as Utilisateur
participant Web as gitrust-web
participant RepoSvc as RepositoryService
participant ResSvc as ResourceService
participant DB as PostgreSQL
participant Git as gitrust-git
participant FS as Système de fichiers
User->>Web: POST /new {name, description}
Web->>Web: Extraire user_id (session JWT)
Web->>RepoSvc: create(db, owner_id, username, base_path, input)
RepoSvc->>RepoSvc: RepoSlug::from_name(input.name)
RepoSvc->>DB: SELECT ... WHERE owner_id AND slug
DB-->>RepoSvc: None (pas de doublon)
RepoSvc->>RepoSvc: compute_disk_path(base, owner, slug)
Note over RepoSvc: Validation anti path-traversal
RepoSvc->>ResSvc: register(db, "repository", repo_id, owner_id)
ResSvc->>DB: INSERT INTO resources
DB-->>ResSvc: Ok
RepoSvc->>DB: INSERT INTO repositories
DB-->>RepoSvc: repository::Model
RepoSvc-->>Web: RepositoryOutput
Web->>Git: BareRepo::init(disk_path)
Git->>FS: git init --bare
FS-->>Git: Ok
Git-->>Web: Ok
Web-->>User: 302 Redirect /{owner}/{slug}
2. Clone SSH (clone git)¶
sequenceDiagram
actor Dev as Développeur
participant Client as Git CLI
participant SSH as gitrust-ssh
participant Auth as SshKeyService
participant Access as AccessService
participant Git as gitrust-git
participant DB as PostgreSQL
participant FS as Bare repo (.git)
Dev->>Client: git clone ssh://git@host:2222/alice/my-repo.git
Client->>SSH: Connexion TCP :2222
SSH-->>Client: Banner SSH + échange clés
Client->>SSH: Auth publickey (signature)
SSH->>Auth: find_by_fingerprint(db, fingerprint)
Auth->>DB: SELECT FROM ssh_keys WHERE fingerprint = ?
DB-->>Auth: ssh_key::Model {user_id, ...}
Auth-->>SSH: user_id
SSH->>Auth: update_last_used(db, key_id)
Auth->>DB: UPDATE ssh_keys SET last_used_at = now()
SSH-->>Client: Auth OK
Client->>SSH: exec "git-upload-pack 'alice/my-repo.git'"
SSH->>SSH: CommandHandler::parse("git-upload-pack alice/my-repo.git")
Note over SSH: Extraction owner=alice, repo=my-repo
SSH->>Access: effective_role(db, user_id, repo_id)
Access->>DB: Check ownership + shares + teams
DB-->>Access: Role::Developer
Access-->>SSH: can_read = true
SSH->>Git: pack_protocol::advertise_refs(repo_path)
Git->>FS: Lecture refs
FS-->>Git: refs/heads/main, ...
Git-->>SSH: advertise output
SSH-->>Client: refs advertisement
Client->>SSH: want/have negotiation
SSH->>Git: pack_protocol::serve_pack(repo_path, wants, haves)
Git->>FS: Pack objects
FS-->>Git: pack data
Git-->>SSH: pack stream
SSH-->>Client: pack data
Client-->>Dev: Dépôt cloné avec succès
3. Premi SSH (git push)¶
sequenceDiagram
actor Dev as Développeur
participant Client as Git CLI
participant SSH as gitrust-ssh
participant Access as AccessService
participant Git as gitrust-git
participant Hooks as gitrust-hooks
participant DB as PostgreSQL
participant FS as Bare repo (.git)
Note over Client,SSH: Session SSH déjà authentifiée
Client->>SSH: exec "git-receive-pack 'alice/my-repo.git'"
SSH->>SSH: CommandHandler::parse(...)
Note over SSH: Extraction owner=alice, repo=my-repo
SSH->>Access: effective_role(db, user_id, repo_id)
Access->>DB: Check ownership + shares + teams
DB-->>Access: Role::Developer
Access-->>SSH: can_push = true
SSH->>Git: pack_protocol::advertise_refs(repo_path)
Git->>FS: Lecture refs
Git-->>SSH: refs advertisement
SSH-->>Client: refs
Client->>SSH: pack data + commands
SSH->>Git: pack_protocol::serve_pack(repo_path, receive-pack)
Git->>FS: Écriture objets + update refs
FS-->>Git: Ok
Git-->>SSH: Ok
SSH->>DB: UPDATE repositories SET is_empty = false, updated_at = now()
SSH-->>Client: Push OK
Client-->>Dev: Push réussi
4. Registrazione di una chiave SSH¶
sequenceDiagram
actor User as Utilisateur
participant Web as gitrust-web
participant Svc as SshKeyService
participant DB as PostgreSQL
User->>Web: POST /settings/keys {title, key_data}
Web->>Web: Extraire user_id (session)
Web->>Svc: create(db, user_id, input)
Svc->>Svc: parse_public_key(key_data)
Note over Svc: Extraire type + décoder base64
Svc->>Svc: validate_key_type_and_size(type, bytes)
Note over Svc: ed25519 OK
RSA >= 4096 bits
ecdsa-p256/p384 OK
Svc->>Svc: compute_fingerprint(bytes)
Note over Svc: SHA256(key_bytes) -> base64-no-pad
Svc->>DB: SELECT FROM ssh_keys WHERE fingerprint = ?
DB-->>Svc: None (pas de doublon)
Svc->>DB: INSERT INTO ssh_keys
DB-->>Svc: ssh_key::Model
Svc-->>Web: SshKeyOutput
Web-->>User: 200 Clé ajoutée (fingerprint affiché)
5. Risoluzione dei permessi (AccessService)¶
sequenceDiagram
participant Caller as Handler / SSH Session
participant AS as AccessService
participant RS as ResourceService
participant DB as PostgreSQL
Caller->>AS: effective_role(db, user_id, repo_id)
AS->>RS: effective_permission(db, user_id, "repository", repo_id)
RS->>DB: SELECT FROM resources WHERE type AND id
DB-->>RS: resource {owner_id, is_public}
alt user_id == owner_id
RS-->>AS: "owner"
else Share exists
RS->>DB: SELECT FROM resource_shares WHERE resource AND user
DB-->>RS: share {permission_level}
RS-->>AS: permission_level
else Resource is public
RS-->>AS: "read"
else No access
RS-->>AS: None
end
AS->>AS: Role::from_permission(individual_level)
AS->>DB: SELECT team_members + team_repository_access
WHERE user_id AND repository_id
DB-->>AS: Vec
AS->>AS: team_role = max(team_permissions)
AS->>AS: effective = max(individual_role, team_role)
AS-->>Caller: Role (Reader / Developer / Maintainer / Owner)
6. Navigazione in un repository (Web)¶
sequenceDiagram
actor User as Utilisateur
participant Web as gitrust-web
participant Ext as RepoExtractor
participant Access as AccessService
participant Git as gitrust-git
participant DB as PostgreSQL
participant FS as Bare repo
User->>Web: GET /alice/my-repo/tree/main/src
Web->>Ext: RepoContext::extract(owner=alice, repo=my-repo, ref=main, path=src)
Ext->>DB: SELECT user WHERE username = 'alice'
DB-->>Ext: user {id}
Ext->>DB: SELECT repository WHERE owner_id AND slug
DB-->>Ext: repository::Model
Ext->>Access: effective_role(db, visitor_id, repo_id)
Access-->>Ext: Role::Reader
Ext-->>Web: RepoContext {repo, role, ref, path}
Web->>Git: tree_browser::list_tree(repo_path, "main", "src")
Git->>FS: Resolve ref main -> commit -> tree -> src/
FS-->>Git: Vec
Git-->>Web: entries (fichiers + dossiers)
Web->>Git: readme::find_readme(repo_path, "main", "src")
Git->>FS: Cherche README.md, README, readme.md
FS-->>Git: Option
Git-->>Web: Option
Web->>Web: Render template tree.html
Web-->>User: HTML (arbre + README)
7. Registrazione utente + creazione directory¶
sequenceDiagram
actor User as Nouvel utilisateur
participant Web as rustwarden-core (auth)
participant Hook as GitrustHooks
participant DB as PostgreSQL
participant FS as Système de fichiers
User->>Web: POST /register {username, email, password}
Web->>DB: INSERT INTO users
DB-->>Web: user {id, username}
Web->>Hook: on_user_registered(db, user_id, username)
Hook->>Hook: Valider username (anti path-traversal)
Hook->>FS: create_dir_all(repos_base_path / username)
FS-->>Hook: Ok
Hook-->>Web: Ok
Web-->>User: 302 Redirect /login