diff --git a/x-pack/solutions/observability/plugins/synthetics/server/routes/settings/private_locations/edit_private_location.ts b/x-pack/solutions/observability/plugins/synthetics/server/routes/settings/private_locations/edit_private_location.ts index 3ae484b33cbf7..594172420aadb 100644 --- a/x-pack/solutions/observability/plugins/synthetics/server/routes/settings/private_locations/edit_private_location.ts +++ b/x-pack/solutions/observability/plugins/synthetics/server/routes/settings/private_locations/edit_private_location.ts @@ -14,7 +14,7 @@ import { getPrivateLocations } from '../../../synthetics_service/get_private_loc import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; import { PrivateLocationRepository } from '../../../repositories/private_location_repository'; import { PRIVATE_LOCATION_WRITE_API } from '../../../feature'; -import { SyntheticsRestApiRouteFactory } from '../../types'; +import { RouteContext, SyntheticsRestApiRouteFactory } from '../../types'; import { SYNTHETICS_API_URLS } from '../../../../common/constants'; import { toClientContract, updatePrivateLocationMonitors } from './helpers'; import { PrivateLocation } from '../../../../common/runtime_types'; @@ -62,6 +62,35 @@ const isPrivateLocationChanged = ({ return isLabelChanged || areTagsChanged; }; +const checkPrivileges = async ({ + routeContext, + monitorsSpaces, +}: { + routeContext: RouteContext; + monitorsSpaces: string[]; +}) => { + const { request, response, server } = routeContext; + + const checkSavedObjectsPrivileges = + server.security.authz.checkSavedObjectsPrivilegesWithRequest(request); + + const { hasAllRequested } = await checkSavedObjectsPrivileges( + 'saved_object:synthetics-monitor/bulk_update', + monitorsSpaces + ); + + if (!hasAllRequested) { + return response.forbidden({ + body: { + message: i18n.translate('xpack.synthetics.editPrivateLocation.forbidden', { + defaultMessage: + 'You do not have sufficient permissions to update monitors in all required spaces. This private location is used by monitors in spaces where you lack update privileges.', + }), + }, + }); + } +}; + export const editPrivateLocationRoute: SyntheticsRestApiRouteFactory< PrivateLocation, TypeOf, @@ -79,7 +108,7 @@ export const editPrivateLocationRoute: SyntheticsRestApiRouteFactory< }, requiredPrivileges: [PRIVATE_LOCATION_WRITE_API], handler: async (routeContext) => { - const { response, request, savedObjectsClient, server } = routeContext; + const { response, request, savedObjectsClient } = routeContext; const { locationId } = request.params; const { label: newLocationLabel, tags: newTags } = request.body; @@ -103,27 +132,14 @@ export const editPrivateLocationRoute: SyntheticsRestApiRouteFactory< isPrivateLocationChanged({ privateLocation: existingLocation, newParams: request.body }) ) { // This privileges check is done only when changing the label, because changing the label will update also the monitors in that location - if (isPrivateLocationLabelChanged(existingLocation.attributes.label, newLocationLabel)) { - const monitorsSpaces = monitorsInLocation.map(({ namespaces }) => namespaces![0]); - - const checkSavedObjectsPrivileges = - server.security.authz.checkSavedObjectsPrivilegesWithRequest(request); - - const { hasAllRequested } = await checkSavedObjectsPrivileges( - 'saved_object:synthetics-monitor/bulk_update', - monitorsSpaces - ); - - if (!hasAllRequested) { - return response.forbidden({ - body: { - message: i18n.translate('xpack.synthetics.editPrivateLocation.forbidden', { - defaultMessage: - 'You do not have sufficient permissions to update monitors in all required spaces. This private location is used by monitors in spaces where you lack update privileges.', - }), - }, - }); - } + if ( + isPrivateLocationLabelChanged(existingLocation.attributes.label, newLocationLabel) && + monitorsInLocation.length + ) { + await checkPrivileges({ + routeContext, + monitorsSpaces: monitorsInLocation.map(({ namespaces }) => namespaces![0]), + }); } newLocation = await repo.editPrivateLocation(locationId, { diff --git a/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/synthetics/edit_private_location.ts b/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/synthetics/edit_private_location.ts index 8fe8d0a43efac..f168d857d260c 100644 --- a/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/synthetics/edit_private_location.ts +++ b/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/synthetics/edit_private_location.ts @@ -86,6 +86,21 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { rawExpect(apiResponse.body.locations).toEqual(rawExpect.arrayContaining(testResponse)); }); + it('successfully edits a private location label with no monitors assigned', async () => { + const privateLocation = privateLocations[0]; + + await supertestEditorWithApiKey + .put(`${SYNTHETICS_API_URLS.PRIVATE_LOCATIONS}/${privateLocation.id}`) + .send({ label: 'No monitors assigned' }) + .expect(200); + + // Set the label back, needed for the other tests + await supertestEditorWithApiKey + .put(`${SYNTHETICS_API_URLS.PRIVATE_LOCATIONS}/${privateLocation.id}`) + .send({ label: privateLocations[0].label }) + .expect(200); + }); + it('adds a monitor in private location', async () => { newMonitor = { ...getFixtureJson('http_monitor'),