Description
Dans l'API v2 des dĂ©pĂŽts, la mise Ă jour des identifiants de miroir Vault est devinĂ©e Ă
partir du corps de la requĂȘte au lieu d'ĂȘtre exprimĂ©e par le client.
parseRepositoryCredentialUpdate (apps/server-nestjs/src/modules/repository/repository.utils.ts)
infÚre l'intention (set / clear / keep) de la présence ou de l'absence de champs :
if (updateRepositoryInfos.isPrivate === false) return { kind: 'clear' }
if (updateRepositoryInfos.externalToken) return { kind: 'set', externalToken: ... }
return { kind: 'keep' }
C'est la reprise du comportement legacy (qui signalait « inchangé » avec un jeton factice
fakeToken), conservée telle quelle pour ne pas élargir la migration. Mais on ne devrait
jamais deviner quoi que ce soit à partir des données d'entrée : soit le client sait ce
qu'il veut, soit il doit y rĂ©flĂ©chir avant d'envoyer sa requĂȘte. Le kind devrait ĂȘtre
dans la requĂȘte.
MĂȘme racine pour buildRepositoryUpdateData, dans le mĂȘme fichier : les deux if
(isPrivate !== undefined, isPrivate !== false && externalUserName !== undefined)
sont fragiles parce que isPrivate y est un tri-Ă©tat true | false | undefined lĂ oĂč
ce devrait ĂȘtre un boolĂ©en. La sĂ©mantique de « rendre public » (qui conserve
l'externalUserName stocké mais supprime le secret Vault) est aujourd'hui implicite et
répartie entre deux fonctions.
PRs liées
#2416 â introduit parseRepositoryCredentialUpdate et le type
RepositoryMirrorCredentialUpdate avec le comportement legacy conservé.
Issues liées
Aucune.
Exemples simples
Aujourd'hui, trois requĂȘtes diffĂ©rentes produisent trois effets Vault diffĂ©rents sans
que le client ait exprimé la moindre intention :
Cible : l'intention est portée explicitement par le corps, par exemple
Spécifications techniques
Zone concernée : apps/server-nestjs/src/modules/repository/ (+ packages/shared/src/schemas/v2/repository.ts).
- Porter le
kind dans le contrat. Faire de UpdateRepositorySchema une union
discriminĂ©e sur l'intention de credentials, comme CreateRepositorySchema l'est dĂ©jĂ
sur isPrivate. parseRepositoryCredentialUpdate disparaĂźt alors : le boundary zod
produit directement le RepositoryMirrorCredentialUpdate, et le service se contente
d'exécuter (« parse, don't validate »).
- Rendre les combinaisons impossibles inexprimables.
isPrivate: false avec
kind: 'set' ne doit pas ĂȘtre reprĂ©sentable dans le type, plutĂŽt que d'ĂȘtre arbitrĂ© Ă
l'exécution par un ordre de if.
- Sortir
isPrivate du tri-état dans buildRepositoryUpdateData : décider
explicitement de la sĂ©mantique du passage public â l'externalUserName stockĂ©
est-il conservé (legacy) ou effacé ? Cf. la question ouverte ci-dessous.
- Impact client : la webapp (
apps/client) et les consommateurs de l'API v2 devront
envoyer l'intention. Prévoir la période de transition (l'API v1 legacy reste sur
apps/server et n'est pas concernée).
Questions ouvertes (à trancher avant implémentation)
- Rendre un dépÎt public doit-il effacer l'
externalUserName en base, ou conserver le
comportement legacy qui le laisse intact ?
- Le
kind est-il un champ Ă part (credentials: { kind: ... }) ou portĂ© par la mĂȘme
union que isPrivate ?
Définition du fini
Description
Dans l'API v2 des dĂ©pĂŽts, la mise Ă jour des identifiants de miroir Vault est devinĂ©e Ă
partir du corps de la requĂȘte au lieu d'ĂȘtre exprimĂ©e par le client.
parseRepositoryCredentialUpdate(apps/server-nestjs/src/modules/repository/repository.utils.ts)infĂšre l'intention (
set/clear/keep) de la présence ou de l'absence de champs :C'est la reprise du comportement legacy (qui signalait « inchangé » avec un jeton factice
fakeToken), conservée telle quelle pour ne pas élargir la migration. Mais on ne devraitjamais deviner quoi que ce soit à partir des données d'entrée : soit le client sait ce
qu'il veut, soit il doit y rĂ©flĂ©chir avant d'envoyer sa requĂȘte. Le
kinddevrait ĂȘtredans la requĂȘte.
MĂȘme racine pour
buildRepositoryUpdateData, dans le mĂȘme fichier : les deuxif(
isPrivate !== undefined,isPrivate !== false && externalUserName !== undefined)sont fragiles parce que
isPrivatey est un tri-Ă©tattrue | false | undefinedlĂ oĂčce devrait ĂȘtre un boolĂ©en. La sĂ©mantique de « rendre public » (qui conserve
l'
externalUserNamestocké mais supprime le secret Vault) est aujourd'hui implicite etrépartie entre deux fonctions.
PRs liées
#2416 â introduit
parseRepositoryCredentialUpdateet le typeRepositoryMirrorCredentialUpdateavec le comportement legacy conservé.Issues liées
Aucune.
Exemples simples
Aujourd'hui, trois requĂȘtes diffĂ©rentes produisent trois effets Vault diffĂ©rents sans
que le client ait exprimé la moindre intention :
Cible : l'intention est portée explicitement par le corps, par exemple
{ "deployRevision": "main", "credentials": { "kind": "keep" } } { "isPrivate": false, "credentials": { "kind": "clear" } } { "isPrivate": true, "credentials": { "kind": "set", "externalUserName": "bot", "externalToken": "glpat-xxx" } }Spécifications techniques
Zone concernée :
apps/server-nestjs/src/modules/repository/(+packages/shared/src/schemas/v2/repository.ts).kinddans le contrat. Faire deUpdateRepositorySchemaune uniondiscriminée sur l'intention de credentials, comme
CreateRepositorySchemal'est dĂ©jĂsur
isPrivate.parseRepositoryCredentialUpdatedisparaĂźt alors : le boundary zodproduit directement le
RepositoryMirrorCredentialUpdate, et le service se contented'exécuter (« parse, don't validate »).
isPrivate: falseaveckind: 'set'ne doit pas ĂȘtre reprĂ©sentable dans le type, plutĂŽt que d'ĂȘtre arbitrĂ© Ăl'exĂ©cution par un ordre de
if.isPrivatedu tri-Ă©tat dansbuildRepositoryUpdateData: dĂ©ciderexplicitement de la sĂ©mantique du passage public â l'
externalUserNamestockéest-il conservé (legacy) ou effacé ? Cf. la question ouverte ci-dessous.
apps/client) et les consommateurs de l'API v2 devrontenvoyer l'intention. Prévoir la période de transition (l'API v1 legacy reste sur
apps/serveret n'est pas concernée).Questions ouvertes (à trancher avant implémentation)
externalUserNameen base, ou conserver lecomportement legacy qui le laisse intact ?
kindest-il un champ Ă part (credentials: { kind: ... }) ou portĂ© par la mĂȘmeunion que
isPrivate?Définition du fini
kindest portĂ© explicitement par la requĂȘte, plus aucune infĂ©rence cĂŽtĂ© serveurisPrivaten'est plus un tri-Ă©tat dans la construction de la mise Ă jour