mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Unauthorized route migration for routes owned by obs-ux-management-team (#198374)
### Authz API migration for unauthorized routes This PR migrates unauthorized routes owned by your team to a new security configuration. Please refer to the documentation for more information: [Authorization API](https://docs.elastic.dev/kibana-dev-docs/key-concepts/security-api-authorization) ### **Before migration:** ```ts router.get({ path: '/api/path', ... }, handler); ``` ### **After migration:** ```ts router.get({ path: '/api/path', security: { authz: { enabled: false, reason: 'This route is opted out from authorization because ...', }, }, ... }, handler); ``` ### What to do next? 1. Review the changes in this PR. 2. Elaborate on the reasoning to opt-out of authorization. 3. Routes without a compelling reason to opt-out of authorization should plan to introduce them as soon as possible. 2. You might need to update your tests to reflect the new security configuration: - If you have snapshot tests that include the route definition. ## Any questions? If you have any questions or need help with API authorization, please reach out to the `@elastic/kibana-security` team. --------- Co-authored-by: Dominique Belcher <dominique.clarke@elastic.co> Co-authored-by: Shahzad <shahzad31comp@gmail.com>
This commit is contained in:
parent
8e1b0bd94a
commit
0b193ec81e
11 changed files with 276 additions and 65 deletions
|
@ -95,6 +95,12 @@ export function registerAnnotationAPIs({
|
|||
router.post(
|
||||
{
|
||||
path: '/api/observability/annotation',
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'This route delegates authorization to Elasticsearch',
|
||||
},
|
||||
},
|
||||
validate: {
|
||||
body: unknowns,
|
||||
},
|
||||
|
@ -110,6 +116,12 @@ export function registerAnnotationAPIs({
|
|||
router.put(
|
||||
{
|
||||
path: '/api/observability/annotation/{id}',
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'This route delegates authorization to Elasticsearch',
|
||||
},
|
||||
},
|
||||
validate: {
|
||||
body: unknowns,
|
||||
},
|
||||
|
@ -125,6 +137,12 @@ export function registerAnnotationAPIs({
|
|||
router.delete(
|
||||
{
|
||||
path: '/api/observability/annotation/{id}',
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'This route delegates authorization to Elasticsearch',
|
||||
},
|
||||
},
|
||||
validate: {
|
||||
params: unknowns,
|
||||
},
|
||||
|
@ -140,6 +158,12 @@ export function registerAnnotationAPIs({
|
|||
router.get(
|
||||
{
|
||||
path: '/api/observability/annotation/{id}',
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'This route delegates authorization to Elasticsearch',
|
||||
},
|
||||
},
|
||||
validate: {
|
||||
params: unknowns,
|
||||
},
|
||||
|
@ -155,6 +179,12 @@ export function registerAnnotationAPIs({
|
|||
router.get(
|
||||
{
|
||||
path: '/api/observability/annotation/find',
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'This route delegates authorization to Elasticsearch',
|
||||
},
|
||||
},
|
||||
validate: {
|
||||
query: unknowns,
|
||||
},
|
||||
|
@ -170,6 +200,12 @@ export function registerAnnotationAPIs({
|
|||
router.get(
|
||||
{
|
||||
path: '/api/observability/annotation/permissions',
|
||||
security: {
|
||||
authz: {
|
||||
enabled: false,
|
||||
reason: 'This route delegates authorization to Elasticsearch',
|
||||
},
|
||||
},
|
||||
validate: {
|
||||
query: unknowns,
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { PrivateLocationAttributes } from '../../runtime_types/private_locations';
|
||||
import { getPrivateLocationsForMonitor } from '../monitor_cruds/add_monitor/utils';
|
||||
import { SyntheticsRestApiRouteFactory } from '../types';
|
||||
|
@ -31,6 +32,9 @@ export const runOnceSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () =
|
|||
}): Promise<any> => {
|
||||
const monitor = request.body as MonitorFields;
|
||||
const { monitorId } = request.params;
|
||||
if (isEmpty(monitor)) {
|
||||
return response.badRequest({ body: { message: 'Monitor data is empty.' } });
|
||||
}
|
||||
|
||||
const validationResult = validateMonitor(monitor);
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server';
|
||||
import { IKibanaResponse } from '@kbn/core-http-server';
|
||||
import { getDecryptedMonitor } from '../../saved_objects/synthetics_monitor';
|
||||
import { PrivateLocationAttributes } from '../../runtime_types/private_locations';
|
||||
import { RouteContext, SyntheticsRestApiRouteFactory } from '../types';
|
||||
|
@ -14,6 +16,7 @@ import { ConfigKey, MonitorFields } from '../../../common/runtime_types';
|
|||
import { SYNTHETICS_API_URLS } from '../../../common/constants';
|
||||
import { normalizeSecrets } from '../../synthetics_service/utils/secrets';
|
||||
import { getPrivateLocationsForMonitor } from '../monitor_cruds/add_monitor/utils';
|
||||
import { getMonitorNotFoundResponse } from './service_errors';
|
||||
|
||||
export const testNowMonitorRoute: SyntheticsRestApiRouteFactory<TestNowResponse> = () => ({
|
||||
method: 'POST',
|
||||
|
@ -33,48 +36,56 @@ export const testNowMonitorRoute: SyntheticsRestApiRouteFactory<TestNowResponse>
|
|||
export const triggerTestNow = async (
|
||||
monitorId: string,
|
||||
routeContext: RouteContext
|
||||
): Promise<TestNowResponse> => {
|
||||
const { server, spaceId, syntheticsMonitorClient, savedObjectsClient } = routeContext;
|
||||
): Promise<TestNowResponse | IKibanaResponse<any>> => {
|
||||
const { server, spaceId, syntheticsMonitorClient, savedObjectsClient, response } = routeContext;
|
||||
|
||||
const monitorWithSecrets = await getDecryptedMonitor(server, monitorId, spaceId);
|
||||
const normalizedMonitor = normalizeSecrets(monitorWithSecrets);
|
||||
try {
|
||||
const monitorWithSecrets = await getDecryptedMonitor(server, monitorId, spaceId);
|
||||
const normalizedMonitor = normalizeSecrets(monitorWithSecrets);
|
||||
|
||||
const { [ConfigKey.SCHEDULE]: schedule, [ConfigKey.LOCATIONS]: locations } =
|
||||
monitorWithSecrets.attributes;
|
||||
const { [ConfigKey.SCHEDULE]: schedule, [ConfigKey.LOCATIONS]: locations } =
|
||||
monitorWithSecrets.attributes;
|
||||
|
||||
const privateLocations: PrivateLocationAttributes[] = await getPrivateLocationsForMonitor(
|
||||
savedObjectsClient,
|
||||
normalizedMonitor.attributes
|
||||
);
|
||||
const testRunId = uuidv4();
|
||||
const privateLocations: PrivateLocationAttributes[] = await getPrivateLocationsForMonitor(
|
||||
savedObjectsClient,
|
||||
normalizedMonitor.attributes
|
||||
);
|
||||
const testRunId = uuidv4();
|
||||
|
||||
const [, errors] = await syntheticsMonitorClient.testNowConfigs(
|
||||
{
|
||||
monitor: normalizedMonitor.attributes as MonitorFields,
|
||||
id: monitorId,
|
||||
testRunId,
|
||||
},
|
||||
savedObjectsClient,
|
||||
privateLocations,
|
||||
spaceId
|
||||
);
|
||||
const [, errors] = await syntheticsMonitorClient.testNowConfigs(
|
||||
{
|
||||
monitor: normalizedMonitor.attributes as MonitorFields,
|
||||
id: monitorId,
|
||||
testRunId,
|
||||
},
|
||||
savedObjectsClient,
|
||||
privateLocations,
|
||||
spaceId
|
||||
);
|
||||
|
||||
if (errors && errors?.length > 0) {
|
||||
return {
|
||||
errors,
|
||||
testRunId,
|
||||
schedule,
|
||||
locations,
|
||||
configId: monitorId,
|
||||
monitor: normalizedMonitor.attributes,
|
||||
};
|
||||
}
|
||||
|
||||
if (errors && errors?.length > 0) {
|
||||
return {
|
||||
errors,
|
||||
testRunId,
|
||||
schedule,
|
||||
locations,
|
||||
configId: monitorId,
|
||||
monitor: normalizedMonitor.attributes,
|
||||
};
|
||||
}
|
||||
} catch (getErr) {
|
||||
if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) {
|
||||
return getMonitorNotFoundResponse(response, monitorId);
|
||||
}
|
||||
|
||||
return {
|
||||
testRunId,
|
||||
schedule,
|
||||
locations,
|
||||
configId: monitorId,
|
||||
monitor: normalizedMonitor.attributes,
|
||||
};
|
||||
throw getErr;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ export const initSyntheticsServer = (
|
|||
) => {
|
||||
const { router } = server;
|
||||
syntheticsAppRestApiRoutes.forEach((route) => {
|
||||
const { method, options, handler, validate, path } = syntheticsRouteWrapper(
|
||||
const { method, options, handler, validate, path, security } = syntheticsRouteWrapper(
|
||||
createSyntheticsRouteWithAuth(route),
|
||||
server,
|
||||
syntheticsMonitorClient
|
||||
|
@ -30,6 +30,7 @@ export const initSyntheticsServer = (
|
|||
const routeDefinition = {
|
||||
path,
|
||||
validate,
|
||||
security,
|
||||
options,
|
||||
};
|
||||
|
||||
|
@ -52,11 +53,8 @@ export const initSyntheticsServer = (
|
|||
});
|
||||
|
||||
syntheticsAppPublicRestApiRoutes.forEach((route) => {
|
||||
const { method, options, handler, validate, path, validation } = syntheticsRouteWrapper(
|
||||
createSyntheticsRouteWithAuth(route),
|
||||
server,
|
||||
syntheticsMonitorClient
|
||||
);
|
||||
const { method, options, handler, validate, path, validation, security } =
|
||||
syntheticsRouteWrapper(createSyntheticsRouteWithAuth(route), server, syntheticsMonitorClient);
|
||||
|
||||
const routeDefinition = {
|
||||
path,
|
||||
|
@ -70,13 +68,11 @@ export const initSyntheticsServer = (
|
|||
.get({
|
||||
access: 'public',
|
||||
path: routeDefinition.path,
|
||||
options: {
|
||||
tags: options?.tags,
|
||||
},
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '2023-10-31',
|
||||
security,
|
||||
validate: validation ?? false,
|
||||
},
|
||||
handler
|
||||
|
@ -87,13 +83,11 @@ export const initSyntheticsServer = (
|
|||
.put({
|
||||
access: 'public',
|
||||
path: routeDefinition.path,
|
||||
options: {
|
||||
tags: options?.tags,
|
||||
},
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '2023-10-31',
|
||||
security,
|
||||
validate: validation ?? false,
|
||||
},
|
||||
handler
|
||||
|
@ -104,13 +98,11 @@ export const initSyntheticsServer = (
|
|||
.post({
|
||||
access: 'public',
|
||||
path: routeDefinition.path,
|
||||
options: {
|
||||
tags: options?.tags,
|
||||
},
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '2023-10-31',
|
||||
security,
|
||||
validate: validation ?? false,
|
||||
},
|
||||
handler
|
||||
|
@ -128,6 +120,7 @@ export const initSyntheticsServer = (
|
|||
.addVersion(
|
||||
{
|
||||
version: '2023-10-31',
|
||||
security,
|
||||
validate: validation ?? false,
|
||||
},
|
||||
handler
|
||||
|
|
|
@ -20,9 +20,13 @@ export const syntheticsRouteWrapper: SyntheticsRouteWrapper = (
|
|||
) => ({
|
||||
...uptimeRoute,
|
||||
options: {
|
||||
tags: ['access:uptime-read', ...(uptimeRoute?.writeAccess ? ['access:uptime-write'] : [])],
|
||||
...(uptimeRoute.options ?? {}),
|
||||
},
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['uptime-read', ...(uptimeRoute?.writeAccess ? ['uptime-write'] : [])],
|
||||
},
|
||||
},
|
||||
handler: async (context, request, response) => {
|
||||
const { elasticsearch, savedObjects, uiSettings } = await context.core;
|
||||
|
||||
|
|
|
@ -12,11 +12,12 @@ import { UptimeEsClient } from '../lib/lib';
|
|||
export const uptimeRouteWrapper: UMKibanaRouteWrapper = (uptimeRoute, server) => ({
|
||||
...uptimeRoute,
|
||||
options: {
|
||||
tags: [
|
||||
'oas-tag:uptime',
|
||||
'access:uptime-read',
|
||||
...(uptimeRoute?.writeAccess ? ['access:uptime-write'] : []),
|
||||
],
|
||||
tags: ['oas-tag:uptime'],
|
||||
},
|
||||
security: {
|
||||
authz: {
|
||||
requiredPrivileges: ['uptime-read', ...(uptimeRoute?.writeAccess ? ['uptime-write'] : [])],
|
||||
},
|
||||
},
|
||||
handler: async (context, request, response) => {
|
||||
const coreContext = await context.core;
|
||||
|
|
|
@ -41,7 +41,7 @@ export const initUptimeServer = (
|
|||
router: UptimeRouter
|
||||
) => {
|
||||
legacyUptimeRestApiRoutes.forEach((route) => {
|
||||
const { method, options, handler, validate, path } = uptimeRouteWrapper(
|
||||
const { method, options, handler, validate, path, security } = uptimeRouteWrapper(
|
||||
createRouteWithAuth(libs, route),
|
||||
server
|
||||
);
|
||||
|
@ -50,6 +50,7 @@ export const initUptimeServer = (
|
|||
path,
|
||||
validate,
|
||||
options,
|
||||
security,
|
||||
};
|
||||
|
||||
switch (method) {
|
||||
|
@ -71,26 +72,20 @@ export const initUptimeServer = (
|
|||
});
|
||||
|
||||
legacyUptimePublicRestApiRoutes.forEach((route) => {
|
||||
const { method, options, handler, path, ...rest } = uptimeRouteWrapper(
|
||||
const { method, options, handler, path, security, ...rest } = uptimeRouteWrapper(
|
||||
createRouteWithAuth(libs, route),
|
||||
server
|
||||
);
|
||||
|
||||
const validate = rest.validate ? getRequestValidation(rest.validate) : rest.validate;
|
||||
|
||||
const routeDefinition = {
|
||||
path,
|
||||
validate,
|
||||
options,
|
||||
};
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
router.versioned
|
||||
.get({
|
||||
access: 'public',
|
||||
description: `Get uptime settings`,
|
||||
path: routeDefinition.path,
|
||||
path,
|
||||
options: {
|
||||
tags: options?.tags,
|
||||
},
|
||||
|
@ -98,6 +93,7 @@ export const initUptimeServer = (
|
|||
.addVersion(
|
||||
{
|
||||
version: INITIAL_REST_VERSION,
|
||||
security,
|
||||
validate: {
|
||||
request: {
|
||||
body: validate ? validate?.body : undefined,
|
||||
|
@ -117,7 +113,7 @@ export const initUptimeServer = (
|
|||
.put({
|
||||
access: 'public',
|
||||
description: `Update uptime settings`,
|
||||
path: routeDefinition.path,
|
||||
path,
|
||||
options: {
|
||||
tags: options?.tags,
|
||||
},
|
||||
|
@ -125,6 +121,7 @@ export const initUptimeServer = (
|
|||
.addVersion(
|
||||
{
|
||||
version: INITIAL_REST_VERSION,
|
||||
security,
|
||||
validate: {
|
||||
request: {
|
||||
body: validate ? validate?.body : undefined,
|
||||
|
|
|
@ -304,7 +304,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
.send(httpMonitorJson);
|
||||
|
||||
expect(apiResponse.status).eql(403);
|
||||
expect(apiResponse.body.message).eql('Forbidden');
|
||||
expect(apiResponse.body.message).eql(
|
||||
'API [POST /api/synthetics/monitors] is unauthorized for user, this action is granted by the Kibana privileges [uptime-write]'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
|
|||
await esDeleteAllIndices('synthetics*');
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./synthetics_api_security'));
|
||||
loadTestFile(require.resolve('./edit_monitor_public_api'));
|
||||
loadTestFile(require.resolve('./add_monitor_public_api'));
|
||||
loadTestFile(require.resolve('./synthetics_enablement'));
|
||||
|
|
|
@ -175,7 +175,7 @@ export class SyntheticsMonitorTestService {
|
|||
}
|
||||
}
|
||||
|
||||
async addsNewSpace() {
|
||||
async addsNewSpace(uptimePermissions: string[] = ['all']) {
|
||||
const username = 'admin';
|
||||
const password = `${username}-password`;
|
||||
const roleName = 'uptime-role';
|
||||
|
@ -190,7 +190,8 @@ export class SyntheticsMonitorTestService {
|
|||
kibana: [
|
||||
{
|
||||
feature: {
|
||||
uptime: ['all'],
|
||||
uptime: uptimePermissions,
|
||||
slo: ['all'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
syntheticsAppPublicRestApiRoutes,
|
||||
syntheticsAppRestApiRoutes,
|
||||
} from '@kbn/synthetics-plugin/server/routes';
|
||||
import expect from '@kbn/expect';
|
||||
import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { SyntheticsMonitorTestService } from './services/synthetics_monitor_test_service';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('SyntheticsAPISecurity', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||
|
||||
const monitorTestService = new SyntheticsMonitorTestService(getService);
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
const assertPermissions = async (
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
path: string,
|
||||
options: {
|
||||
statusCodes: number[];
|
||||
SPACE_ID: string;
|
||||
username: string;
|
||||
password: string;
|
||||
writeAccess?: boolean;
|
||||
tags?: string;
|
||||
}
|
||||
) => {
|
||||
let resp;
|
||||
const { statusCodes, SPACE_ID, username, password, writeAccess } = options;
|
||||
const tags = !writeAccess ? '[uptime-read]' : options.tags ?? '[uptime-read,uptime-write]';
|
||||
const getStatusMessage = (respStatus: string) =>
|
||||
`Expected ${statusCodes?.join(
|
||||
','
|
||||
)}, got ${respStatus} status code doesn't match, for path: ${path} and method ${method}`;
|
||||
|
||||
const getBodyMessage = (tg?: string) =>
|
||||
`API [${method} ${path}] is unauthorized for user, this action is granted by the Kibana privileges ${
|
||||
tg ?? tags
|
||||
}`;
|
||||
|
||||
const verifyPermissionsBody = (res: any, msg: string) => {
|
||||
if (res.status === 403 && !res.body.message.includes('MissingIndicesPrivileges:')) {
|
||||
expect(decodeURIComponent(res.body.message)).to.eql(msg);
|
||||
}
|
||||
};
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
resp = await supertestWithoutAuth
|
||||
.get(`/s/${SPACE_ID}${path}`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({});
|
||||
expect(statusCodes.includes(resp.status)).to.eql(true, getStatusMessage(resp.status));
|
||||
verifyPermissionsBody(resp, getBodyMessage('[uptime-read]'));
|
||||
break;
|
||||
case 'PUT':
|
||||
resp = await supertestWithoutAuth
|
||||
.put(`/s/${SPACE_ID}${path}`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({});
|
||||
expect(statusCodes.includes(resp.status)).to.eql(true, getStatusMessage(resp.status));
|
||||
verifyPermissionsBody(resp, getBodyMessage());
|
||||
break;
|
||||
case 'POST':
|
||||
resp = await supertestWithoutAuth
|
||||
.post(`/s/${SPACE_ID}${path}`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({});
|
||||
expect(statusCodes.includes(resp.status)).to.eql(true, getStatusMessage(resp.status));
|
||||
verifyPermissionsBody(resp, getBodyMessage());
|
||||
break;
|
||||
case 'DELETE':
|
||||
resp = await supertestWithoutAuth
|
||||
.delete(`/s/${SPACE_ID}${path}`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({});
|
||||
expect(statusCodes.includes(resp.status)).to.eql(true, getStatusMessage(resp.status));
|
||||
verifyPermissionsBody(resp, getBodyMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
return resp;
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
});
|
||||
|
||||
const allRoutes = syntheticsAppRestApiRoutes.concat(syntheticsAppPublicRestApiRoutes);
|
||||
|
||||
it('throws permissions errors for un-auth user', async () => {
|
||||
const { SPACE_ID, username, password } = await monitorTestService.addsNewSpace([]);
|
||||
|
||||
for (const routeFn of allRoutes) {
|
||||
const route = routeFn();
|
||||
await assertPermissions(route.method, route.path, {
|
||||
statusCodes: [403],
|
||||
SPACE_ID,
|
||||
username,
|
||||
password,
|
||||
writeAccess: route.writeAccess ?? true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('throws permissions errors for read user', async () => {
|
||||
const { SPACE_ID, username, password } = await monitorTestService.addsNewSpace(['read']);
|
||||
|
||||
for (const routeFn of allRoutes) {
|
||||
const route = routeFn();
|
||||
if (route.writeAccess === false) {
|
||||
continue;
|
||||
}
|
||||
await assertPermissions(route.method, route.path, {
|
||||
statusCodes: [200, 403, 500, 400, 404],
|
||||
SPACE_ID,
|
||||
username,
|
||||
password,
|
||||
writeAccess: route.writeAccess ?? true,
|
||||
tags: '[uptime-write]',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('no permissions errors for all user', async () => {
|
||||
const { SPACE_ID, username, password } = await monitorTestService.addsNewSpace(['all']);
|
||||
|
||||
for (const routeFn of allRoutes) {
|
||||
const route = routeFn();
|
||||
if (
|
||||
(route.method === 'DELETE' && route.path === SYNTHETICS_API_URLS.SYNTHETICS_ENABLEMENT) ||
|
||||
SYNTHETICS_API_URLS.SYNTHETICS_PROJECT_APIKEY
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
await assertPermissions(route.method, route.path, {
|
||||
statusCodes: [400, 200, 404],
|
||||
SPACE_ID,
|
||||
username,
|
||||
password,
|
||||
writeAccess: route.writeAccess ?? true,
|
||||
tags: '[uptime-write]',
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue