Skip to content

feat(server-nestjs): secure deployment API with project permission guards#2288

Open
KepoParis wants to merge 1 commit into
mainfrom
feat/secure-deployment-api
Open

feat(server-nestjs): secure deployment API with project permission guards#2288
KepoParis wants to merge 1 commit into
mainfrom
feat/secure-deployment-api

Conversation

@KepoParis

Copy link
Copy Markdown
Contributor

Issues liées

Issues numéro:


Quel est le comportement actuel ?

Les endpoints de déploiement sont exposés sous /api/v1/deployments avec le projectId passé en query/body, sans garde de permission (un TODO add auth and project perms guard était présent). N'importe quel utilisateur authentifié peut donc lister, créer, modifier ou supprimer des déploiements sans vérification des droits sur le projet.

Quel est le nouveau comportement ?

Sécurisation de l'API de déploiement via les permissions projet :

  • Déplacement des routes sous /api/v1/projects/:projectId/deployments et application du ProjectGuard.
  • Ajout des permissions requises par endpoint : ListDeployments / ManageDeployments (RequireProjectPermission) et RequireAdminPermission sur la liste.
  • Ajout des décorateurs de paramètres ProjectContext et ProjectId pour résoudre projet/utilisateur depuis la requête, et propagation d'un ProjectExecutionContext jusqu'à la couche service.
  • Ajout d'utilitaires de résultats de services plugin (ServiceResults, mergeServiceResults, getFailedServices).
  • Suppression en cascade des déploiements (migration Prisma + mise à jour du schéma).
  • Renommage de la limite de nom en longestDeploymentName et export de DeploymentSourceSchema.
  • Extension des services argocd/deployment et du datastore, ajout d'utilitaires de test et enrichissement des specs controller/service.

Cette PR introduit-elle un breaking change ?

Oui. Les URLs des endpoints de déploiement changent : le projectId passe de query/body à un segment de path (/api/v1/projects/:projectId/deployments). Les clients appelant l'ancienne route /api/v1/deployments doivent être mis à jour.

Autres informations

@KepoParis KepoParis self-assigned this Jul 3, 2026
@KepoParis KepoParis added the enhancement New feature or request label Jul 3, 2026
@KepoParis KepoParis requested a review from shikanime July 3, 2026 11:16
@github-actions github-actions Bot added the built label Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🤖 Hey !

The security scan report for the current pull request is available here.

@cloud-pi-native-sonarqube

Copy link
Copy Markdown


@OnEvent('project.argocd.update')
@StartActiveSpan()
async handleArgoCDProjectUpdate(project: ProjectWithDetails): Promise<RequiredServiceResult<'argocd'>> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better just using project.upsert, its designed to run on any changes in a GitOps style.

id: projectId,
name: 'Test Project',
}
const projectCtx: ProjectExecutionContext = { projectId, userId, requestId }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever, I'll steal the design.


await this.upsertProject(projectId)
// TODO handle result and add logs
await this.updateArgoCDProject({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emitAsync can be wait if it was the use case. The core design of the "reconciler" is take a database as a spec and reconcile the state with the target resource. Action shouldn't exists by itself from the outside of ArgoCD service.

})

if (failed.length > 0) {
this.logger.error(`project.argocd.update failed (projectId=${projectId})`)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning the result of the creation, I have been thinking about letting the reconciliation in async and use logService.addLog to return an error in a GitOps style

requestId: string
}

export const ProjectContext = createParamDecorator(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now have the ProjectContext and AuthUser decorators, it should have all we need

import type { FastifyRequest } from 'fastify'
import { createParamDecorator } from '@nestjs/common'

export const ProjectId = createParamDecorator(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Project should already have everything

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

built enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants