[HTTP/OAS] Make SO CRUD and resolve APIs internal on serverless (#184408)

This commit is contained in:
Jean-Louis Leysens 2024-06-11 17:40:03 +02:00 committed by GitHub
parent 8faa5946c3
commit dc78221e2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 245 additions and 46 deletions

View file

@ -105,6 +105,7 @@ export type {
RouteValidatorFullConfigRequest,
RouteValidatorFullConfigResponse,
LazyValidator,
RouteAccess,
} from './src/router';
export {
validBodyOutput,

View file

@ -51,6 +51,7 @@ export type {
RouteConfigOptionsBody,
RouteContentType,
SafeRouteMethod,
RouteAccess,
} from './route';
export { validBodyOutput } from './route';
export type {

View file

@ -100,6 +100,16 @@ export interface RouteConfigOptionsBody {
parse?: boolean | 'gunzip';
}
/**
* Route access level.
*
* Public routes are stable and intended for external access and are subject to
* stricter change management and have long term maintenance windows.
*
* @remark On serverless access to internal routes is restricted.
*/
export type RouteAccess = 'public' | 'internal';
/**
* Additional route options.
* @public
@ -133,7 +143,7 @@ export interface RouteConfigOptions<Method extends RouteMethod> {
*
* Defaults to 'internal' If not declared,
*/
access?: 'public' | 'internal';
access?: RouteAccess;
/**
* Additional metadata tag strings to attach to the route.

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerBulkCreateRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.post(
{
path: '/_bulk_create',
options: {
access,
description: `Create saved objects`,
},
validate: {
query: schema.object({
overwrite: schema.boolean({ defaultValue: false }),

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerBulkDeleteRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.post(
{
path: '/_bulk_delete',
options: {
access,
description: `Remove saved objects`,
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerBulkGetRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.post(
{
path: '/_bulk_get',
options: {
access,
description: `Get saved objects`,
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerBulkResolveRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.post(
{
path: '/_bulk_resolve',
options: {
access,
description: `Resolve saved objects`,
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerBulkUpdateRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.put(
{
path: '/_bulk_update',
options: {
access,
description: `Update saved objects`,
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerCreateRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.post(
{
path: '/{type}/{id?}',
options: {
access,
description: `Create a saved object`,
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerDeleteRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.delete(
{
path: '/{type}/{id}',
options: {
access,
description: `Delete a saved object`,
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -143,6 +143,10 @@ export const registerExportRoute = (
router.post(
{
path: '/_export',
options: {
access: 'public',
description: `Export saved objects`,
},
validate: {
body: schema.object({
type: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),

View file

@ -7,21 +7,24 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
import type { InternalSavedObjectRouter } from '../internal_types';
import { catchAndReturnBoomErrors, throwOnHttpHiddenTypes } from './utils';
import { logWarnOnExternalRequest } from './utils';
interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerFindRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const referenceSchema = schema.object({
type: schema.string(),
@ -34,6 +37,10 @@ export const registerFindRoute = (
router.get(
{
path: '/_find',
options: {
access,
description: `Search for saved objects`,
},
validate: {
query: schema.object({
per_page: schema.number({ min: 0, defaultValue: 20 }),

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -21,16 +22,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerGetRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.get(
{
path: '/{type}/{id}',
options: {
access,
description: `Get a saved object`,
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -36,6 +36,8 @@ export const registerImportRoute = (
{
path: '/_import',
options: {
access: 'public',
description: `Import saved objects`,
body: {
maxBytes: maxImportPayloadBytes,
output: 'stream',

View file

@ -41,6 +41,7 @@ export function registerRoutes({
migratorPromise,
kibanaVersion,
kibanaIndex,
isServerless,
}: {
http: InternalHttpServiceSetup;
coreUsageData: InternalCoreUsageDataSetup;
@ -49,20 +50,30 @@ export function registerRoutes({
migratorPromise: Promise<IKibanaMigrator>;
kibanaVersion: string;
kibanaIndex: string;
isServerless: boolean;
}) {
const router =
http.createRouter<InternalSavedObjectsRequestHandlerContext>('/api/saved_objects/');
registerGetRoute(router, { config, coreUsageData, logger });
registerResolveRoute(router, { config, coreUsageData, logger });
registerCreateRoute(router, { config, coreUsageData, logger });
registerDeleteRoute(router, { config, coreUsageData, logger });
registerFindRoute(router, { config, coreUsageData, logger });
registerUpdateRoute(router, { config, coreUsageData, logger });
registerBulkGetRoute(router, { config, coreUsageData, logger });
registerBulkCreateRoute(router, { config, coreUsageData, logger });
registerBulkResolveRoute(router, { config, coreUsageData, logger });
registerBulkUpdateRoute(router, { config, coreUsageData, logger });
registerBulkDeleteRoute(router, { config, coreUsageData, logger });
const internalOnServerless = isServerless ? 'internal' : 'public';
registerGetRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerResolveRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerCreateRoute(router, {
config,
coreUsageData,
logger,
access: internalOnServerless,
});
registerDeleteRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerFindRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerUpdateRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerBulkGetRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerBulkCreateRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerBulkResolveRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerBulkUpdateRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerBulkDeleteRoute(router, { config, coreUsageData, logger, access: internalOnServerless });
registerExportRoute(router, { config, coreUsageData });
registerImportRoute(router, { config, coreUsageData });
registerResolveImportErrorsRoute(router, { config, coreUsageData });

View file

@ -7,6 +7,7 @@
*/
import { schema } from '@kbn/config-schema';
import type { RouteAccess } from '@kbn/core-http-server';
import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { Logger } from '@kbn/logging';
@ -17,16 +18,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerResolveRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.get(
{
path: '/resolve/{type}/{id}',
options: {
access,
description: `Resolve a saved object`,
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -37,6 +37,8 @@ export const registerResolveImportErrorsRoute = (
{
path: '/_resolve_import_errors',
options: {
access: 'public',
description: `Resolve import errors`,
body: {
maxBytes: maxImportPayloadBytes,
output: 'stream',

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
import type { RouteAccess } from '@kbn/core-http-server';
import { schema } from '@kbn/config-schema';
import type { SavedObjectsUpdateOptions } from '@kbn/core-saved-objects-api-server';
import type { Logger } from '@kbn/logging';
@ -22,16 +23,21 @@ interface RouteDependencies {
config: SavedObjectConfig;
coreUsageData: InternalCoreUsageDataSetup;
logger: Logger;
access: RouteAccess;
}
export const registerUpdateRoute = (
router: InternalSavedObjectRouter,
{ config, coreUsageData, logger }: RouteDependencies
{ config, coreUsageData, logger, access }: RouteDependencies
) => {
const { allowHttpApiAccess } = config;
router.put(
{
path: '/{type}/{id}',
options: {
access,
description: `Update a saved object`,
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -162,6 +162,7 @@ export class SavedObjectsService
migratorPromise: firstValueFrom(this.migrator$),
kibanaIndex: MAIN_SAVED_OBJECT_INDEX,
kibanaVersion: this.kibanaVersion,
isServerless: this.coreContext.env.packageInfo.buildFlavor === 'serverless',
});
registerCoreObjectTypes(this.typeRegistry);

View file

@ -54,7 +54,8 @@ describe('POST /api/saved_objects/_bulk_create with allowApiAccess true', () =>
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);
const logger = loggerMock.create();
const config = setupConfig(true);
registerBulkCreateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkCreateRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -58,8 +58,9 @@ describe('POST /api/saved_objects/_bulk_delete with allowApiAccess as true', ()
const logger = loggerMock.create();
const config = setupConfig(true);
const access = 'public';
registerBulkDeleteRoute(router, { config, coreUsageData, logger });
registerBulkDeleteRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -56,7 +56,8 @@ describe('POST /api/saved_objects/_bulk_get with allowApiAccess true', () => {
const logger = loggerMock.create();
const config = setupConfig(true);
registerBulkGetRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkGetRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -57,7 +57,8 @@ describe('POST /api/saved_objects/_bulk_resolve with allowApiAccess true', () =>
const logger = loggerMock.create();
const config = setupConfig(true);
registerBulkResolveRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkResolveRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -50,7 +50,8 @@ describe('PUT /api/saved_objects/_bulk_update with allowApiAccess true', () => {
const logger = loggerMock.create();
const config = setupConfig(true);
registerBulkUpdateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkUpdateRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -56,8 +56,8 @@ describe('POST /api/saved_objects/{type} with allowApiAccess true', () => {
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);
const logger = loggerMock.create();
const config = setupConfig(true);
registerCreateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerCreateRoute(router, { config, coreUsageData, logger, access });
handlerContext.savedObjects.typeRegistry.getType.mockImplementation((typename: string) => {
return testTypes

View file

@ -53,7 +53,8 @@ describe('DELETE /api/saved_objects/{type}/{id} with allowApiAccess true', () =>
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);
const logger = loggerMock.create();
const config = setupConfig(true);
registerDeleteRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerDeleteRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -69,8 +69,9 @@ describe('GET /api/saved_objects/_find with allowApiAccess true', () => {
const logger = loggerMock.create();
const config = setupConfig(true);
const access = 'public';
registerFindRoute(router, { config, coreUsageData, logger });
registerFindRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -78,7 +78,8 @@ describe('GET /api/saved_objects/{type}/{id} with allowApiAccess true', () => {
const logger = loggerMock.create();
const config = setupConfig(true);
registerGetRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerGetRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -78,8 +78,9 @@ describe('GET /api/saved_objects/resolve/{type}/{id} with allowApiAccess true',
const logger = loggerMock.create();
const config = setupConfig(true);
const access = 'public';
registerResolveRoute(router, { config, coreUsageData, logger });
registerResolveRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -54,7 +54,8 @@ describe('PUT /api/saved_objects/{type}/{id?} with allowApiAccess true', () => {
const logger = loggerMock.create();
const config = setupConfig(true);
registerUpdateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerUpdateRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -58,8 +58,9 @@ describe('POST /api/saved_objects/_bulk_create', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
const access = 'public';
registerBulkCreateRoute(router, { config, coreUsageData, logger });
registerBulkCreateRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -60,8 +60,9 @@ describe('POST /api/saved_objects/_bulk_delete', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
const access = 'public';
registerBulkDeleteRoute(router, { config, coreUsageData, logger });
registerBulkDeleteRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -58,7 +58,9 @@ describe('POST /api/saved_objects/_bulk_get', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerBulkGetRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkGetRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -59,7 +59,9 @@ describe('POST /api/saved_objects/_bulk_resolve', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerBulkResolveRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkResolveRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -57,7 +57,9 @@ describe('PUT /api/saved_objects/_bulk_update', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerBulkUpdateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerBulkUpdateRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -58,7 +58,9 @@ describe('POST /api/saved_objects/{type}', () => {
const logger = loggerMock.create();
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerCreateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerCreateRoute(router, { config, coreUsageData, logger, access });
handlerContext.savedObjects.typeRegistry.getType.mockImplementation((typename: string) => {
return testTypes

View file

@ -55,7 +55,8 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
const logger = loggerMock.create();
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerDeleteRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerDeleteRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -72,8 +72,9 @@ describe('GET /api/saved_objects/_find', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
const access = 'public';
registerFindRoute(router, { config, coreUsageData, logger });
registerFindRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -80,7 +80,9 @@ describe('GET /api/saved_objects/{type}/{id}', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerGetRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerGetRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -79,8 +79,9 @@ describe('GET /api/saved_objects/resolve/{type}/{id}', () => {
const logger = loggerMock.create();
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
const access = 'public';
registerResolveRoute(router, { config, coreUsageData, logger });
registerResolveRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -67,7 +67,8 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => {
loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation();
const config = setupConfig();
registerUpdateRoute(router, { config, coreUsageData, logger });
const access = 'public';
registerUpdateRoute(router, { config, coreUsageData, logger, access });
await server.start();
});

View file

@ -15,5 +15,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./translations'));
loadTestFile(require.resolve('./capabilities'));
loadTestFile(require.resolve('./ui_settings'));
loadTestFile(require.resolve('./saved_objects'));
});
}

View file

@ -0,0 +1,73 @@
/*
* 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const svlCommonApi = getService('svlCommonApi');
describe('Blocked internal SO API', () => {
const apis = [
{
path: '/api/saved_objects/_bulk_create',
method: 'post' as const,
},
{
path: '/api/saved_objects/_bulk_delete',
method: 'post' as const,
},
{
path: '/api/saved_objects/_bulk_get',
method: 'post' as const,
},
{
path: '/api/saved_objects/_bulk_resolve',
method: 'post' as const,
},
{
path: '/api/saved_objects/_bulk_update',
method: 'post' as const,
},
{
path: '/api/saved_objects/test/id',
method: 'get' as const,
},
{
path: '/api/saved_objects/test/id',
method: 'post' as const,
},
{
path: '/api/saved_objects/test/id',
method: 'delete' as const,
},
{
path: '/api/saved_objects/_find',
method: 'get' as const,
},
{
path: '/api/saved_objects/test/id',
method: 'put' as const,
},
];
for (const { path, method } of apis) {
it(`${method} ${path}`, async () => {
const { body } = await supertest[method](path)
.set(svlCommonApi.getCommonRequestHeader())
.expect(400);
expect(body).to.eql({
statusCode: 400,
error: 'Bad Request',
message: `uri [${path}] with method [${method}] exists but is not available with the current configuration`,
});
});
}
});
}