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