refactor(admin-roles): migrate from server - #2371
Conversation
e25c2f2 to
3218292
Compare
|
🤖 Hey ! The security scan report for the current pull request is available here. |
3218292 to
3044f04
Compare
|
🤖 Hey ! The security scan report for the current pull request is available here. |
3044f04 to
b2642e0
Compare
|
🤖 Hey ! The security scan report for the current pull request is available here. |
| }) | ||
| } | ||
|
|
||
| if (positionsAvailable.length && positionsAvailable.length !== dbRoles.length) { |
There was a problem hiding this comment.
Dead position-integrity guard (parity note): positionsAvailable is only populated for roles found in dbRoles, so its length always equals the number of matched DB roles. The !== dbRoles.length branch is effectively unreachable on the normal partial-patch path. Reproduces legacy behavior (business.ts:39) — harmless, but worth a comment or removal so it is not mistaken for an active invariant.
There was a problem hiding this comment.
Ben, surtout, il est où le test unitaire qui valide/invalide ce if ?
| select: { id: true, adminRoleIds: true }, | ||
| }) | ||
|
|
||
| await this.eventEmitter.emitAsync('adminRole.delete', { |
There was a problem hiding this comment.
adminRole.delete is emitted inside the transaction (before the row is deleted at :185). Legacy does the same (business.ts:94), so this is parity-preserving — but if a future @OnEvent(adminRole.delete) consumer reads the role row, ordering matters. Confirm intended.
There was a problem hiding this comment.
D'ailleurs faudrait clarifier si on veut adminRole.delete (action de supprimer) ou adminRole.deleted (résultat de la suppression).
En termes d'intention et de conséquences, ça peut effectivement être problématique.
On a fait une carto des flux d'évènement d'ailleurs ? On se fait plutôt ça dans le ticket de carto des plugins ( #2181 )
| import type { AdminRoleService } from './admin-role.service' | ||
| import type { CreateAdminRoleBody, PatchAdminRolesBody } from './admin-role.utils' | ||
|
|
||
| export type AdminRoleContract = Parameters<AdminRoleService['patch']>[0][number] |
There was a problem hiding this comment.
Unused testing-utils exports: AdminRoleContract, AdminRoleResponse, and makeAdminRoleMember (lines 5, 6, 27) have no importers — the spec only uses makeAdminRole / makeCreateAdminRoleBody. Drop them or wire them into the spec to avoid dead surface.
| @UseGuards(UserGuard) | ||
| // TODO: ListRoles is intentionally not protected by admin permission because of | ||
| // certain behaviours of the legacy client | ||
| // @RequireAdminPermission('ListRoles') |
There was a problem hiding this comment.
ListRoles intentionally unguarded (legacy-client behavior) — matches the legacy router. Low priority: note which legacy client path depends on this so the TODO can be closed later.
There was a problem hiding this comment.
Ça demande un ticket, à mon avis, car c'est suffisament atomique, comme considération 🙂
shikanime
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Migration of admin-roles from the legacy Fastify server into server-nestjs is well-structured (typecheck clean, admin-role.service.spec.ts passes, eslint clean). One blocker must be resolved before the legacy router is cut over.
Blocker — emitted adminRole.* events are never consumed (silent Keycloak/GitLab sync regression).
The service emits adminRole.upsert / adminRole.delete (service.ts:45, :124, :169) via EventEmitter2, but no @OnEvent('adminRole.upsert'|'adminRole.delete') handler exists in server-nestjs and @cpn-console/hooks is not imported by the module. In the legacy server, those same flows call hook.adminRole.upsert / hook.adminRole.delete (business.ts:42,66,94), which drive the Keycloak OIDC-group sync and GitLab admin/auditor group sync. Every other migrated entity bridges its event into the plugin hook system via an @OnEvent handler (e.g. keycloak.service.ts:28, gitlab.service.ts:63). Without that bridge, once the legacy route is removed, admin-role CRUD will silently stop syncing member groups. Add the @OnEvent bridge handlers (mirroring the project bridge) or explicitly defer with a tracked follow-up before cutover.
Warnings (parity-preserving, confirm): dead patch position-integrity guard (service.ts:92) — only reachable in the legacy-incompatible all-roles path; adminRole.delete emitted before the row delete inside the transaction (service.ts:169 vs :185) — legacy does the same.
Minor: unused testing-utils exports (AdminRoleContract, AdminRoleResponse, makeAdminRoleMember in admin-role-testing.utils.ts:5,6,27).
Full detail in the inline comments.
b2642e0 to
b5725e4
Compare
|
🤖 Hey ! The security scan report for the current pull request is available here. |
b5725e4 to
de5e877
Compare
|
🤖 Hey ! The security scan report for the current pull request is available here. |
StephaneTrebel
left a comment
There was a problem hiding this comment.
Rien qui me choque, mais les questions évoquées me semblent pertinentes
| @UseGuards(UserGuard) | ||
| // TODO: ListRoles is intentionally not protected by admin permission because of | ||
| // certain behaviours of the legacy client | ||
| // @RequireAdminPermission('ListRoles') |
There was a problem hiding this comment.
Ça demande un ticket, à mon avis, car c'est suffisament atomique, comme considération 🙂
| }) | ||
| } | ||
|
|
||
| if (positionsAvailable.length && positionsAvailable.length !== dbRoles.length) { |
There was a problem hiding this comment.
Ben, surtout, il est où le test unitaire qui valide/invalide ce if ?
| select: { id: true, adminRoleIds: true }, | ||
| }) | ||
|
|
||
| await this.eventEmitter.emitAsync('adminRole.delete', { |
There was a problem hiding this comment.
D'ailleurs faudrait clarifier si on veut adminRole.delete (action de supprimer) ou adminRole.deleted (résultat de la suppression).
En termes d'intention et de conséquences, ça peut effectivement être problématique.
On a fait une carto des flux d'évènement d'ailleurs ? On se fait plutôt ça dans le ticket de carto des plugins ( #2181 )
de5e877 to
046ee74
Compare
Review: PR #2371 — verdict REQUEST CHANGESI reviewed the actual diff (34 commits / 206 files). CI is green (unit-tests, lint, build, SonarQube, Trivy, CodeQL all pass) and the branch is mergeable with no conflicts. The quality of the code is high: the deployment Blockers
Warnings (follow-up)
Nits
|
ca7cef4 to
273f574
Compare
Review: #2371 — refactor(admin-roles): migrate from serverVerdict: REQUEST CHANGES (reviewer agent) — blocker still open since [blocker] Emitted Warnings (parity-preserving): dead Cannot approve until the blocker is resolved. |
273f574 to
986437f
Compare
Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I00a18a853330301a735cdfcf3fb6955a6a6a6964
Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I6e2bf93ddac464c88a82683dc6e6b0846a6a6964
986437f to
c491b64
Compare
|

2 New Issues
0 Fixed Issues
0 Accepted Issues
Change-Id: I6e2bf93ddac464c88a82683dc6e6b0846a6a6964
Issues liées
Issues numéro: #2204
Reopened Pull Request: #2205
Quel est le comportement actuel ?
Quel est le nouveau comportement ?
Cette PR introduit-elle un breaking change ?
Autres informations