Flux de requêtes¶
Diagrammes de séquence couvrant les opérations principales de gitrust : création de dépôt, clone et push SSH, enregistrement de clé SSH, résolution des permissions, navigation web, inscription utilisateur.
1. Création d'un dépôt (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 (git clone)¶
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. Push 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. Enregistrement d'une clé 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. Résolution des permissions (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. Navigation dans un dépôt (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. Inscription utilisateur + création répertoire¶
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