Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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<typeof EditPrivateLocationQuery>,
Expand All @@ -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;

Expand All @@ -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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down