Périmètre — HUB-19, suite du pilote ShaarIt (0.7.0, en production) : Flowdeck consomme le registre des rôles du Hub (plan Hub v2, décision D3(a)) pour l'application flowdeck. Branche hub19-roles-flowdeck sur main (v7.85.1, commit distant 5203b62 — vérifié par l'API avant la PR, aucun écart), version 7.85.2 (VERSION + littéral app/main.py + entrée CHANGELOG). Aucune fusion : branche + PR seulement.
Contrat — À l'ouverture de session draco, consultation de GET {hub}/api/roles/flowdeck en relayant l'en-tête Cookie complet de la requête, Accept: application/json, délai 2 s → 200 {"app","sub","role","explicite","ttl_secondes":60}, rôle ∈ {aucun, utilisateur, administrateur}. Nouveau client app/services/hub_roles.py, portage Python du patron Rust du pilote (hub_roles.rs) : cache mémoire par sub, TTL 60 s, horodatage posé avant l'appel (échec = ancien cache conservé, pas de rafale). URL du Hub résolue comme la barre commune (draco_urls.hub_url() : explicite HUB_URL > hôte de la requête > dérivation par l'hôte sœur de l'agent > défaut officiel) — jamais d'URL dev figée.
Effets (sessions draco seulement)
Rôle connu aucun → refus avant la création de la session locale, au point d'insertion unique où un cookie draco aboutit à une session : le pont GET /auth/draco, qui appelle désormais user_for_draco(..., refuser_aucun=True). Réponse 403 en français nommant le registre des rôles du Hub. Exemptions (patron du pilote) : session locale préexistante (accès de secours par mot de passe — le pont ne refuse pas), page de connexion, santé (/api/health) et statiques (jamais passées par le pont), contrats API propres (OAuth externe Gitea/GitHub et jetons Bearer/SCIM de Flowdeck ne sont pas draco, intacts), et recherche fédérée /api/search (repli draco sans création de session : défaut refuser_aucun=False, aucun refus nouveau).
Surfaces d'administration de l'instance gardées par hub_roles.admin_hub_ok (session draco + rôle connu → administrateur exigé, en plus du drapeau local) : /api/admin/* (admin_required), configuration des fournisseurs de l'agent (agent._current_admin), journal d'audit unifié (branche session), administration SCIM/domaines (branche session), configuration SSO (branche session de _require_admin). Les voies Bearer de ces surfaces et l'administration d'espace de travail (rôles de membre) ne sont pas touchées.
Ordre JIT/refus : RoleAucunRefuse est levée dans user_for_draco après validation du jeton et extraction du sub, avant la résolution de compte (_linked_user) et donc avant le provisionnement JIT de HUB-15 — aucun compte ni lien draco_links n'est créé pour un sub refusé (vérifié par test). Le provisionnement JIT lui-même est inchangé.
Repli — Toute erreur (401/404/réseau/JSON illisible/rôle hors ensemble) = rôle inconnu → comportement actuel intégralement conservé ; le registre ne crée jamais un verrouillage nouveau.
Tests lus — Nouveau tests/test_hub_roles.py : 28 réussis (contrat exact de l'appel Hub — URL, cookie complet, Accept, délai 2 s —, cache par sub, ancien cache après échec, erreurs → inconnu ; intégration : 403 français au pont, refus avant JIT avec compte et lien absents, rôle utilisateur avec JIT intact, repli rôle inconnu, session préexistante exemptée, garde /api/admin/* selon le rôle). Balayage de régression (hub_roles, fusion_draco, draco_urls, barre, SSO v67, API publique v2, recherche, PWA, agent, audit, permissions) : 266 réussis, 4 échecs — tous préexistants et reconfirmés identiques sur main vierge : les 3 du fonds HUB-15 (test_audit_p0_fixes : test_csp_no_cdn_and_vendor, test_http_client_shared_and_loop_scoped, test_og_metadata_rejects_private_host) et test_public_api_v2::test_v2_webhooks_crud (fonds connu depuis la 7.84.11).
**Périmètre** — HUB-19, suite du pilote ShaarIt (0.7.0, en production) : Flowdeck consomme le registre des rôles du Hub (plan Hub v2, décision D3(a)) pour l'application `flowdeck`. Branche `hub19-roles-flowdeck` sur `main` (v7.85.1, commit distant 5203b62 — vérifié par l'API avant la PR, aucun écart), version **7.85.2** (VERSION + littéral `app/main.py` + entrée CHANGELOG). **Aucune fusion** : branche + PR seulement.
**Contrat** — À l'ouverture de session draco, consultation de `GET {hub}/api/roles/flowdeck` en relayant l'en-tête Cookie complet de la requête, `Accept: application/json`, délai 2 s → 200 `{"app","sub","role","explicite","ttl_secondes":60}`, rôle ∈ {`aucun`, `utilisateur`, `administrateur`}. Nouveau client `app/services/hub_roles.py`, portage Python du patron Rust du pilote (`hub_roles.rs`) : cache mémoire par `sub`, TTL 60 s, horodatage posé **avant** l'appel (échec = ancien cache conservé, pas de rafale). URL du Hub résolue comme la barre commune (`draco_urls.hub_url()` : explicite `HUB_URL` > hôte de la requête > dérivation par l'hôte sœur de l'agent > défaut officiel) — jamais d'URL dev figée.
**Effets (sessions draco seulement)**
1. Rôle connu `aucun` → refus **avant** la création de la session locale, au point d'insertion unique où un cookie draco aboutit à une session : le pont `GET /auth/draco`, qui appelle désormais `user_for_draco(..., refuser_aucun=True)`. Réponse 403 en français nommant le registre des rôles du Hub. Exemptions (patron du pilote) : session locale préexistante (accès de secours par mot de passe — le pont ne refuse pas), page de connexion, santé (`/api/health`) et statiques (jamais passées par le pont), contrats API propres (OAuth externe Gitea/GitHub et jetons Bearer/SCIM de Flowdeck ne sont pas draco, intacts), et recherche fédérée `/api/search` (repli draco sans création de session : défaut `refuser_aucun=False`, aucun refus nouveau).
2. Surfaces d'administration de l'instance gardées par `hub_roles.admin_hub_ok` (session draco + rôle connu → `administrateur` exigé, en plus du drapeau local) : `/api/admin/*` (`admin_required`), configuration des fournisseurs de l'agent (`agent._current_admin`), journal d'audit unifié (branche session), administration SCIM/domaines (branche session), configuration SSO (branche session de `_require_admin`). Les voies Bearer de ces surfaces et l'administration d'espace de travail (rôles de membre) ne sont pas touchées.
3. **Ordre JIT/refus** : `RoleAucunRefuse` est levée dans `user_for_draco` après validation du jeton et extraction du `sub`, **avant** la résolution de compte (`_linked_user`) et donc avant le provisionnement JIT de HUB-15 — aucun compte ni lien `draco_links` n'est créé pour un `sub` refusé (vérifié par test). Le provisionnement JIT lui-même est inchangé.
**Repli** — Toute erreur (401/404/réseau/JSON illisible/rôle hors ensemble) = rôle **inconnu** → comportement actuel intégralement conservé ; le registre ne crée jamais un verrouillage nouveau.
**Tests lus** — Nouveau `tests/test_hub_roles.py` : **28 réussis** (contrat exact de l'appel Hub — URL, cookie complet, Accept, délai 2 s —, cache par `sub`, ancien cache après échec, erreurs → inconnu ; intégration : 403 français au pont, refus avant JIT avec compte et lien absents, rôle `utilisateur` avec JIT intact, repli rôle inconnu, session préexistante exemptée, garde `/api/admin/*` selon le rôle). Balayage de régression (hub_roles, fusion_draco, draco_urls, barre, SSO v67, API publique v2, recherche, PWA, agent, audit, permissions) : **266 réussis, 4 échecs — tous préexistants et reconfirmés identiques sur `main` vierge** : les 3 du fonds HUB-15 (`test_audit_p0_fixes` : `test_csp_no_cdn_and_vendor`, `test_http_client_shared_and_loop_scoped`, `test_og_metadata_rejects_private_host`) et `test_public_api_v2::test_v2_webhooks_crud` (fonds connu depuis la 7.84.11).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Périmètre — HUB-19, suite du pilote ShaarIt (0.7.0, en production) : Flowdeck consomme le registre des rôles du Hub (plan Hub v2, décision D3(a)) pour l'application
flowdeck. Branchehub19-roles-flowdecksurmain(v7.85.1, commit distant5203b62— vérifié par l'API avant la PR, aucun écart), version 7.85.2 (VERSION + littéralapp/main.py+ entrée CHANGELOG). Aucune fusion : branche + PR seulement.Contrat — À l'ouverture de session draco, consultation de
GET {hub}/api/roles/flowdecken relayant l'en-tête Cookie complet de la requête,Accept: application/json, délai 2 s → 200{"app","sub","role","explicite","ttl_secondes":60}, rôle ∈ {aucun,utilisateur,administrateur}. Nouveau clientapp/services/hub_roles.py, portage Python du patron Rust du pilote (hub_roles.rs) : cache mémoire parsub, TTL 60 s, horodatage posé avant l'appel (échec = ancien cache conservé, pas de rafale). URL du Hub résolue comme la barre commune (draco_urls.hub_url(): expliciteHUB_URL> hôte de la requête > dérivation par l'hôte sœur de l'agent > défaut officiel) — jamais d'URL dev figée.Effets (sessions draco seulement)
aucun→ refus avant la création de la session locale, au point d'insertion unique où un cookie draco aboutit à une session : le pontGET /auth/draco, qui appelle désormaisuser_for_draco(..., refuser_aucun=True). Réponse 403 en français nommant le registre des rôles du Hub. Exemptions (patron du pilote) : session locale préexistante (accès de secours par mot de passe — le pont ne refuse pas), page de connexion, santé (/api/health) et statiques (jamais passées par le pont), contrats API propres (OAuth externe Gitea/GitHub et jetons Bearer/SCIM de Flowdeck ne sont pas draco, intacts), et recherche fédérée/api/search(repli draco sans création de session : défautrefuser_aucun=False, aucun refus nouveau).hub_roles.admin_hub_ok(session draco + rôle connu →administrateurexigé, en plus du drapeau local) :/api/admin/*(admin_required), configuration des fournisseurs de l'agent (agent._current_admin), journal d'audit unifié (branche session), administration SCIM/domaines (branche session), configuration SSO (branche session de_require_admin). Les voies Bearer de ces surfaces et l'administration d'espace de travail (rôles de membre) ne sont pas touchées.RoleAucunRefuseest levée dansuser_for_dracoaprès validation du jeton et extraction dusub, avant la résolution de compte (_linked_user) et donc avant le provisionnement JIT de HUB-15 — aucun compte ni liendraco_linksn'est créé pour unsubrefusé (vérifié par test). Le provisionnement JIT lui-même est inchangé.Repli — Toute erreur (401/404/réseau/JSON illisible/rôle hors ensemble) = rôle inconnu → comportement actuel intégralement conservé ; le registre ne crée jamais un verrouillage nouveau.
Tests lus — Nouveau
tests/test_hub_roles.py: 28 réussis (contrat exact de l'appel Hub — URL, cookie complet, Accept, délai 2 s —, cache parsub, ancien cache après échec, erreurs → inconnu ; intégration : 403 français au pont, refus avant JIT avec compte et lien absents, rôleutilisateuravec JIT intact, repli rôle inconnu, session préexistante exemptée, garde/api/admin/*selon le rôle). Balayage de régression (hub_roles, fusion_draco, draco_urls, barre, SSO v67, API publique v2, recherche, PWA, agent, audit, permissions) : 266 réussis, 4 échecs — tous préexistants et reconfirmés identiques surmainvierge : les 3 du fonds HUB-15 (test_audit_p0_fixes:test_csp_no_cdn_and_vendor,test_http_client_shared_and_loop_scoped,test_og_metadata_rejects_private_host) ettest_public_api_v2::test_v2_webhooks_crud(fonds connu depuis la 7.84.11).