@eqs/auth : aucun chemin de migration des comptes, sessions, clés API et groupes d'un dépôt rétrofitté #80
Closed
opened 2026-09-21 06:55:07 +00:00 by nicolas-fryder
·
2 comments
No Branch/Tag specified
main
dev
@eqs/tooling@0.24.3
@eqs/testing@0.24.3
@eqs/telemetry@0.24.3
@eqs/platform-next@0.24.3
@eqs/platform-nest@0.24.3
@eqs/http@0.24.3
@eqs/errors@0.24.3
@eqs/config@0.24.3
@eqs/cli@0.24.3
@eqs/auth@0.24.3
@eqs/tooling@0.24.2
@eqs/testing@0.24.2
@eqs/telemetry@0.24.2
@eqs/platform-next@0.24.2
@eqs/platform-nest@0.24.2
@eqs/http@0.24.2
@eqs/errors@0.24.2
@eqs/config@0.24.2
@eqs/cli@0.24.2
@eqs/auth@0.24.2
@eqs/tooling@0.24.1
@eqs/testing@0.24.1
@eqs/telemetry@0.24.1
@eqs/platform-next@0.24.1
@eqs/platform-nest@0.24.1
@eqs/http@0.24.1
@eqs/errors@0.24.1
@eqs/config@0.24.1
@eqs/cli@0.24.1
@eqs/auth@0.24.1
@eqs/tooling@0.24.0
@eqs/testing@0.24.0
@eqs/telemetry@0.24.0
@eqs/platform-next@0.24.0
@eqs/platform-nest@0.24.0
@eqs/http@0.24.0
@eqs/errors@0.24.0
@eqs/config@0.24.0
@eqs/cli@0.24.0
@eqs/auth@0.24.0
@eqs/tooling@0.23.0
@eqs/testing@0.23.0
@eqs/telemetry@0.23.0
@eqs/platform-next@0.23.0
@eqs/platform-nest@0.23.0
@eqs/http@0.23.0
@eqs/errors@0.23.0
@eqs/config@0.23.0
@eqs/cli@0.23.0
@eqs/auth@0.23.0
@eqs/tooling@0.22.0
@eqs/testing@0.22.0
@eqs/telemetry@0.22.0
@eqs/platform-next@0.22.0
@eqs/platform-nest@0.22.0
@eqs/http@0.22.0
@eqs/errors@0.22.0
@eqs/config@0.22.0
@eqs/cli@0.22.0
@eqs/auth@0.22.0
@eqs/tooling@0.21.0
@eqs/testing@0.21.0
@eqs/telemetry@0.21.0
@eqs/platform-next@0.21.0
@eqs/platform-nest@0.21.0
@eqs/http@0.21.0
@eqs/errors@0.21.0
@eqs/config@0.21.0
@eqs/cli@0.21.0
@eqs/auth@0.21.0
@eqs/tooling@0.20.0
@eqs/testing@0.20.0
@eqs/telemetry@0.20.0
@eqs/platform-next@0.20.0
@eqs/platform-nest@0.20.0
@eqs/http@0.20.0
@eqs/errors@0.20.0
@eqs/config@0.20.0
@eqs/cli@0.20.0
@eqs/auth@0.20.0
@eqs/tooling@0.19.0
@eqs/testing@0.19.0
@eqs/telemetry@0.19.0
@eqs/platform-next@0.19.0
@eqs/platform-nest@0.19.0
@eqs/http@0.19.0
@eqs/errors@0.19.0
@eqs/config@0.19.0
@eqs/cli@0.19.0
@eqs/auth@0.19.0
@eqs/tooling@0.17.1
@eqs/testing@0.17.1
@eqs/telemetry@0.17.1
@eqs/platform-next@0.17.1
@eqs/platform-nest@0.17.1
@eqs/http@0.17.1
@eqs/errors@0.17.1
@eqs/config@0.17.1
@eqs/cli@0.17.1
@eqs/auth@0.17.1
@eqs/tooling@0.17.0
@eqs/testing@0.17.0
@eqs/telemetry@0.17.0
@eqs/platform-next@0.17.0
@eqs/platform-nest@0.17.0
@eqs/http@0.17.0
@eqs/errors@0.17.0
@eqs/config@0.17.0
@eqs/cli@0.17.0
@eqs/auth@0.17.0
@eqs/tooling@0.16.0
@eqs/testing@0.16.0
@eqs/telemetry@0.16.0
@eqs/platform-next@0.16.0
@eqs/platform-nest@0.16.0
@eqs/http@0.16.0
@eqs/errors@0.16.0
@eqs/config@0.16.0
@eqs/cli@0.16.0
@eqs/auth@0.16.0
@eqs/tooling@0.15.0
@eqs/testing@0.15.0
@eqs/telemetry@0.15.0
@eqs/platform-next@0.15.0
@eqs/platform-nest@0.15.0
@eqs/http@0.15.0
@eqs/errors@0.15.0
@eqs/config@0.15.0
@eqs/cli@0.15.0
@eqs/auth@0.15.0
@eqs/tooling@0.14.0
@eqs/testing@0.14.0
@eqs/telemetry@0.14.0
@eqs/platform-next@0.14.0
@eqs/platform-nest@0.14.0
@eqs/http@0.14.0
@eqs/errors@0.14.0
@eqs/config@0.14.0
@eqs/cli@0.14.0
@eqs/auth@0.14.0
@eqs/tooling@0.13.0
@eqs/testing@0.13.0
@eqs/telemetry@0.13.0
@eqs/platform-next@0.13.0
@eqs/platform-nest@0.13.0
@eqs/http@0.13.0
@eqs/errors@0.13.0
@eqs/config@0.13.0
@eqs/cli@0.13.0
@eqs/auth@0.13.0
@eqs/tooling@0.12.2
@eqs/testing@0.12.2
@eqs/telemetry@0.12.2
@eqs/platform-next@0.12.2
@eqs/platform-nest@0.12.2
@eqs/http@0.12.2
@eqs/errors@0.12.2
@eqs/config@0.12.2
@eqs/cli@0.12.2
@eqs/auth@0.12.2
@eqs/tooling@0.12.1
@eqs/testing@0.12.1
@eqs/telemetry@0.12.1
@eqs/platform-next@0.12.1
@eqs/platform-nest@0.12.1
@eqs/http@0.12.1
@eqs/errors@0.12.1
@eqs/config@0.12.1
@eqs/cli@0.12.1
@eqs/auth@0.12.1
@eqs/tooling@0.12.0
@eqs/testing@0.12.0
@eqs/telemetry@0.12.0
@eqs/platform-next@0.12.0
@eqs/platform-nest@0.12.0
@eqs/http@0.12.0
@eqs/errors@0.12.0
@eqs/config@0.12.0
@eqs/cli@0.12.0
@eqs/auth@0.12.0
@eqs/tooling@0.11.2
@eqs/testing@0.11.2
@eqs/telemetry@0.11.2
@eqs/platform-next@0.11.2
@eqs/platform-nest@0.11.2
@eqs/http@0.11.2
@eqs/errors@0.11.2
@eqs/config@0.11.2
@eqs/cli@0.11.2
@eqs/auth@0.11.2
@eqs/tooling@0.11.1
@eqs/testing@0.11.1
@eqs/telemetry@0.11.1
@eqs/platform-next@0.11.1
@eqs/platform-nest@0.11.1
@eqs/http@0.11.1
@eqs/errors@0.11.1
@eqs/config@0.11.1
@eqs/cli@0.11.1
@eqs/auth@0.11.1
@eqs/tooling@0.11.0
@eqs/testing@0.11.0
@eqs/telemetry@0.11.0
@eqs/platform-next@0.11.0
@eqs/platform-nest@0.11.0
@eqs/http@0.11.0
@eqs/errors@0.11.0
@eqs/config@0.11.0
@eqs/cli@0.11.0
@eqs/auth@0.11.0
@eqs/tooling@0.10.1
@eqs/testing@0.10.1
@eqs/telemetry@0.10.1
@eqs/platform-next@0.10.1
@eqs/platform-nest@0.10.1
@eqs/http@0.10.1
@eqs/errors@0.10.1
@eqs/config@0.10.1
@eqs/cli@0.10.1
@eqs/auth@0.10.1
@eqs/tooling@0.10.0
@eqs/testing@0.10.0
@eqs/telemetry@0.10.0
@eqs/platform-next@0.10.0
@eqs/platform-nest@0.10.0
@eqs/http@0.10.0
@eqs/errors@0.10.0
@eqs/config@0.10.0
@eqs/cli@0.10.0
@eqs/auth@0.10.0
@eqs/tooling@0.9.0
@eqs/testing@0.9.0
@eqs/telemetry@0.9.0
@eqs/platform-next@0.9.0
@eqs/platform-nest@0.9.0
@eqs/http@0.9.0
@eqs/errors@0.9.0
@eqs/config@0.9.0
@eqs/cli@0.9.0
@eqs/auth@0.9.0
@eqs/tooling@0.8.1
@eqs/testing@0.8.1
@eqs/telemetry@0.8.1
@eqs/platform-next@0.8.1
@eqs/platform-nest@0.8.1
@eqs/http@0.8.1
@eqs/errors@0.8.1
@eqs/config@0.8.1
@eqs/cli@0.8.1
@eqs/auth@0.8.1
@eqs/tooling@0.8.0
@eqs/testing@0.8.0
@eqs/telemetry@0.8.0
@eqs/platform-next@0.8.0
@eqs/platform-nest@0.8.0
@eqs/http@0.8.0
@eqs/errors@0.8.0
@eqs/config@0.8.0
@eqs/cli@0.8.0
@eqs/auth@0.8.0
@eqs/tooling@0.7.0
@eqs/testing@0.7.0
@eqs/telemetry@0.7.0
@eqs/platform-next@0.7.0
@eqs/platform-nest@0.7.0
@eqs/http@0.7.0
@eqs/errors@0.7.0
@eqs/config@0.7.0
@eqs/cli@0.7.0
@eqs/auth@0.7.0
@eqs/tooling@0.6.0
@eqs/testing@0.6.0
@eqs/telemetry@0.6.0
@eqs/platform-next@0.6.0
@eqs/platform-nest@0.6.0
@eqs/http@0.6.0
@eqs/errors@0.6.0
@eqs/config@0.6.0
@eqs/cli@0.6.0
@eqs/auth@0.6.0
@eqs/tooling@0.5.1
@eqs/testing@0.5.1
@eqs/telemetry@0.5.1
@eqs/platform-next@0.5.1
@eqs/platform-nest@0.5.1
@eqs/http@0.5.1
@eqs/errors@0.5.1
@eqs/config@0.5.1
@eqs/cli@0.5.1
@eqs/auth@0.5.1
@eqs/tooling@0.5.0
@eqs/testing@0.5.0
@eqs/telemetry@0.5.0
@eqs/platform-next@0.5.0
@eqs/platform-nest@0.5.0
@eqs/http@0.5.0
@eqs/errors@0.5.0
@eqs/config@0.5.0
@eqs/cli@0.5.0
@eqs/auth@0.5.0
@eqs/tooling@0.4.0
@eqs/testing@0.4.0
@eqs/telemetry@0.4.0
@eqs/platform-next@0.4.0
@eqs/platform-nest@0.4.0
@eqs/http@0.4.0
@eqs/errors@0.4.0
@eqs/config@0.4.0
@eqs/cli@0.4.0
@eqs/auth@0.4.0
@eqs/tooling@0.2.0
@eqs/telemetry@0.2.0
@eqs/errors@0.2.0
@eqs/config@0.2.0
@eqs/tooling@0.1.0
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
Infrastructure/eqs-platform#80
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ce qui manque. Le cahier de
@eqs/auth(§8) abandonneLocalSession,ApiToken,permissions.tset les deux formats de hachage d'ATLAS, et (§10) affirme que « la migration des comptes scrypt d'ATLAS se fait sans réinitialisation ». C'est la seule phrase sur la migration d'un existant. Or ATLAS est le dépôt rétrofitté (D-001, ROADMAP #15), et il porte aujourd'hui, en production :local_users(scrypt N=2^16 au formatscrypt:<sel>:<hash>, quelques PBKDF2 hérités), avecrole(USER|EDITOR|ADMIN),active,forcePasswordChange,passwordSetBySeed;local_sessions(cookieeq-atlas-session) ;api_tokens(SHA-256 de la clé, préfixeeqatlas_,scopes[]= codes de permission, révocation, expiration,lastUsedAt) — dont celle du worker ;groups,group_permissions,user_groups), plusexternal_identities(Entra) etlogin_throttle(verrou par compte, persisté).Le fragment
schemas/auth.prismadéfinituser,session,account,verification,api_key. Rien ne dit comment on y arrive depuis un schéma existant.Questions, dans l'ordre où elles bloquent le rétrofit :
creerAuthet comment déclarer le vérificateur personnalisé ? Le format d'ATLAS estscrypt:<sel hex>:<dérivé hex>(N=65 536, r=8, p=1, keylen 64) etpbkdf2:<itérations>:<sel>:<dérivé>pour l'hérité. Faut-il les recopier tels quels dansaccount.password, ou les re-hacher au premier login (ce qu'ATLAS fait déjà pour PBKDF2 → scrypt) ?api_key.hashest un SHA-256 : celui d'ATLAS aussi. Une ligne migrée (hash, préfixe, scopes) est-elle lue telle quelle parprincipalDepuisCle, ou le préfixe doit-il valoirAPI_KEY_PREFIXpour que la clé soit reconnue ? Concrètement : peut-on gardereqatlas_en posantAPI_KEY_PREFIX=eqatlas_, ou faut-il réémettre les clés (donc reconfigurer le worker et les appelants) ?ingest.monuments) ; ceux du socle sont desoperationId(monuments.importer). Une clé migrée doit-elle voir ses scopes traduits, et par qui ?local_sessionsverssession(token, expiration), ou assume-t-on une reconnexion de tout le monde ? Si oui, il faut le dire dans le cahier : c'est une décision d'exploitation.roles.yamlremplace 4 groupes × 70 droits. Existe-t-il, ou est-il prévu, uneqs auth roles --depuis <permissions.ts>ou l'équivalent, ou la traduction est-elle manuelle ? EtLocalUser.role(USER|EDITOR|ADMIN) devient-iluser.roletel quel ?forcePasswordChange/passwordSetBySeed/login_throttle. Ces trois mécanismes sont des décisions d'ATLAS (audit passe 6). Le socle en couvre-t-il l'intention (mot de passe temporaire imposé côté serveur, verrou par compte indépendant des en-têtes), ou restent-ils dans l'application ?Ce que ça coûte. Bloquant pour l'étape 5 du plan. Sans réponse, chaque choix est une hypothèse qu'un futur rétrofit (photofront, metalfrom, nuage : mêmes questions) refera.
Proposition. Une section « Rétrofit d'un existant » dans le cahier de
@eqs/auth, avec le contrat du hachage personnalisé, la règle sur le préfixe des clés, et la position sur les sessions. Et, si les réponses sont mécaniques, une commandeeqs migrate auth --planqui lit le schéma Prisma existant et propose le SQL — le même esprit queeqs migrate plan.Contexte : rétrofit d'ATLAS, branche
epic/retrofitdeEQS/ATLAS,docs/retrofit-eqs.md. Je commence par les étapes 0–4 (tooling, config, errors, telemetry), qui n'en dépendent pas.Un second rétrofit tombe sur les mêmes questions, et en ajoute une
Le ticket prévoyait le cas : « photofront, metalfrom, nuage : mêmes questions ». C'est arrivé.
nuageest en rétrofit depuis aujourd'hui (EQS-Sandbox/NUAGE, brancheretrofit-socle-eqs,@eqs/*0.13.0, profilnest), et ses questions 1 à 6 sont les tiennes, avec d'autres chiffres.Mais il en pose une que la liste n'a pas, et elle est plus structurelle.
nuagene tient pas de session : il délègue à HQChaque compte porte un
hqUserIdet unhqRole. L'identité n'est pas locale : elle est empruntée à HQ à chaque requête.Les quatre fournisseurs entrants de
@eqs/authsupposent tous l'inverse — que le satellite tient sa propre session, contre Entra ou en local. Il n'y a pas de cinquième fournisseur entrant, et pas de point d'extension pour en brancher un :EqsAuthModule.forEqs(options)prendDepsPrincipalplus uncanAccess, et la résolution du principal est fermée.Précision, parce que je me suis trompé en première lecture :
src/delegue.tsexiste bien et s'annonce « Fournisseur 5 », mais il répond à l'autre question — au nom de qui le service sort, pas qui entre. Il ne s'applique pas ici.Ce que
nuageva faire, et pourquoiIl abandonne la délégation et rejoint le cas général : sa propre session better-auth contre le même locataire Entra que HQ. Le SSO vécu ne change pas (une seule connexion Microsoft couvre les deux, rebond silencieux), HQ reste propriétaire des données métier, appelées par client généré et
@eqs/http.Le raisonnement, pour qu'il soit opposable plus tard : D-007 §2 dit qu'un package contient ce qui est identique dans au moins deux applications. La délégation à HQ n'existe que dans
nuage. Elle ne devient donc pas un package, et unifdans@eqs/authpour un seul appelant serait exactement ce que la doctrine §7 refuse.Conséquence assumée, et c'est elle qui coûte :
hqRoledisparaît comme source de droits. Les droits viendront deroles.yamlet des groupes Entra. C'est la question 5 de ce ticket, posée autrement — chez ATLAS c'estgroups×group_permissionsqu'il faut traduire, cheznuagec'est un rôle hérité d'un autre service.Ce que ça ajoute à la demande initiale
La section « Rétrofit d'un existant » que tu proposes pour le cahier de
@eqs/authgagnerait une septième entrée :Parce que la vraie difficulté n'est pas technique — c'est de savoir à quoi on renonce, et de l'avoir écrit avant de commencer plutôt qu'après.
Conception du rétrofit :
docs/superpowers/specs/2026-09-30-retrofit-socle-eqs-design.mddansEQS-Sandbox/NUAGE. L'étage auth est le dernier des dix ; je reviendrai ici avec les chiffres quand j'y serai.Répondu dans
9cd35c2(§8 bis du cahier de@eqs/auth, D-056), avec une mesure à chaque fois. Les réponses courtes :<sel>:<dérivé>(N=16384, r=16), donc unscrypt:<sel>:<dérivé>d'ATLAS était lu de travers et refusé. La phrase du cahier sur la « migration sans réinitialisation » était fausse :creerAuthne permettait pas de brancher un vérificateur. C'est maintenant possible aveccreerAuth({ verifierMotDePasseHerite }): tu passes celui deprisma/passwordHash.ts, il rendundefinedpour un hash qui n'est pas de tes formats, et le mot de passe est re-haché au format better-auth à la première connexion réussie. C'est prouvé sur ton format exact (N=65536, r=8, sel hex pris comme chaîne). PBKDF2 passe par le même vérificateur.rawsanseqatlas_(api-tokens/route.ts) : les hashes ne correspondent pas et ne se recalculent pas sans les clés en clair. Pour 3 clés, réémettre. Une application qui hache la clé entière, elle, peut garder ses clés avecAPI_KEY_PREFIX.operationId.ingest.monumentsn'ouvre aucune route.AUTH_SECRETet porte un autre cookie. C'est une décision d'exploitation, à annoncer avant la bascule.roles.yamlà la main.eqs auth roles --initdonne le squelette.user.roledoit être en minuscules :ADMINrecopié ne donne aucune permission.forcePasswordChange,passwordSetBySeedet le verrou par compte restent dans l'application. Le socle limite par adresse, pas par compte. Une seconde application qui en a besoin en fera un candidat au socle.nuage) : non modélisée. Ta lecture est écrite telle quelle : le SSO survit, le rôle hérité se perd, le lien de données se garde.oidsans chemin depuissub#139