Repository: directus/directus
File: api/src/controllers/deployment.ts (TypeScript)

Code before:
		});

		const record = await service.readByProvider(provider, req.sanitizedQuery);
		res.locals['payload'] = { data: record || null };
		return next();
	}),
	respond,
);

// List projects from provider (for config/selection)
router.get(
	'/:provider/projects',
	asyncHandler(async (req, res, next) => {
		const provider = req.params['provider'] as ProviderType;

		if (!validateProvider(provider)) {
			throw new InvalidPathParameterError({ reason: `${provider} is not a supported provider` });
		}

		const service = new DeploymentService({
			accountability: req.accountability,
			schema: req.schema,
		});

		const projectsService = new DeploymentProjectsService({
			accountability: null,
			schema: req.schema,
		});

		const deployment = await service.readByProvider(provider);
		const { data: providerProjects, remainingTTL } = await service.listProviderProjects(provider);
		const projects = await projectsService.listWithSync(deployment.id, providerProjects);

		res.locals['cache'] = false;
		res.locals['cacheTTL'] = remainingTTL;
		res.locals['payload'] = { data: projects };

		return next();
	}),
	respond,
);

// Get single project details
router.get(
	'/:provider/projects/:id',
	asyncHandler(async (req, res, next) => {
		const provider = req.params['provider'] as ProviderType;
		const projectId = req.params['id'] as string;

		if (!validateProvider(provider)) {
			throw new InvalidPathParameterError({ reason: `${provider} is not a supported provider` });

Review comment (bug):
This was `req.accountability` before — `null` here means the service runs as superuser, which skips RBAC for both the reads inside `listWithSync` _and_ the `updateBatch` write (name sync). Any authenticated user with read on `directus_deployments` can now indirectly trigger writes on `directus_deployment_projects` through a GET request.

Was this intentional to avoid the name-sync failing for non-admin users? If so, could we scope the null accountability to just the write side instead of the whole service?

Code after:
		});

		const record = await service.readByProvider(provider, req.sanitizedQuery);
		res.locals['payload'] = { data: record || null };
		return next();
	}),
	respond,
);

// List projects from provider (for config/selection)
router.get(
	'/:provider/projects',
	asyncHandler(async (req, res, next) => {
		const provider = req.params['provider'] as ProviderType;

		if (!validateProvider(provider)) {
			throw new InvalidPathParameterError({ reason: `${provider} is not a supported provider` });
		}

		const service = new DeploymentService({
			accountability: req.accountability,
			schema: req.schema,
		});

		const projectsService = new DeploymentProjectsService({
			accountability: req.accountability,
			schema: req.schema,
		});

		const deployment = await service.readByProvider(provider);
		const { data: providerProjects, remainingTTL } = await service.listProviderProjects(provider);
		const projects = await projectsService.listWithSync(deployment.id, providerProjects);

		res.locals['cache'] = false;
		res.locals['cacheTTL'] = remainingTTL;
		res.locals['payload'] = { data: projects };

		return next();
	}),
	respond,
);

// Get single project details
router.get(
	'/:provider/projects/:id',
	asyncHandler(async (req, res, next) => {
		const provider = req.params['provider'] as ProviderType;
		const projectId = req.params['id'] as string;

		if (!validateProvider(provider)) {
			throw new InvalidPathParameterError({ reason: `${provider} is not a supported provider` });