Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into task/olm-7053-serve…
Browse files Browse the repository at this point in the history
…rless-pli-authz

# Conflicts:
#	x-pack/plugins/security_solution_serverless/server/plugin.ts
  • Loading branch information
paul-tavares committed Jul 26, 2023
2 parents dfb1736 + 7c16dd9 commit 54e7184
Show file tree
Hide file tree
Showing 529 changed files with 6,240 additions and 5,061 deletions.
Expand Up @@ -28,7 +28,7 @@ cat <<EOF >src/dev/code_coverage/www/index_partial_2.html
</main>
<footer class="mastfoot mt-auto">
<div class="inner">
<p>Please slack us at <a href="https://app.slack.com/client/T0CUZ52US/C0TR0FAET">#kibana-qa</a> if youve questions</p>
<p>Please slack us at <a href="https://app.slack.com/client/T0CUZ52US/C0TR0FAET">#appex-qa</a> if youve questions</p>
</div>
</footer>
</div>
Expand Down
Expand Up @@ -42,6 +42,7 @@ describe('registerRouteForBundle', () => {
{
path: '/route-path/{path*}',
options: {
access: 'public',
authRequired: false,
},
validate: expect.any(Object),
Expand Down
Expand Up @@ -32,6 +32,7 @@ export function registerRouteForBundle(
path: `${routePath}{path*}`,
options: {
authRequired: false,
access: 'public',
},
validate: {
params: schema.object({
Expand Down
27 changes: 15 additions & 12 deletions packages/core/apps/core-apps-server-internal/src/core_app.ts
Expand Up @@ -93,18 +93,21 @@ export class CoreAppsService {
const router = httpSetup.createRouter<InternalCoreAppsServiceRequestHandlerContext>('');
const resources = coreSetup.httpResources.createRegistrar(router);

router.get({ path: '/', validate: false }, async (context, req, res) => {
const { uiSettings } = await context.core;
const defaultRoute = await uiSettings.client.get<string>('defaultRoute');
const basePath = httpSetup.basePath.get(req);
const url = `${basePath}${defaultRoute}`;

return res.redirected({
headers: {
location: url,
},
});
});
router.get(
{ path: '/', validate: false, options: { access: 'public' } },
async (context, req, res) => {
const { uiSettings } = await context.core;
const defaultRoute = await uiSettings.client.get<string>('defaultRoute');
const basePath = httpSetup.basePath.get(req);
const url = `${basePath}${defaultRoute}`;

return res.redirected({
headers: {
location: url,
},
});
}
);

this.registerCommonDefaultRoutes({
basePath: coreSetup.http.basePath,
Expand Down
Expand Up @@ -62,6 +62,20 @@ describe('HttpResources service', () => {
register = await initializer();
});

it('registration defaults to "public" access', () => {
register(routeConfig, async (ctx, req, res) => res.ok());
const [[registeredRouteConfig]] = router.get.mock.calls;
expect(registeredRouteConfig.options?.access).toBe('public');
});

it('registration can set access to "internal"', () => {
register({ ...routeConfig, options: { access: 'internal' } }, async (ctx, req, res) =>
res.ok()
);
const [[registeredRouteConfig]] = router.get.mock.calls;
expect(registeredRouteConfig.options?.access).toBe('internal');
});

describe('renderCoreApp', () => {
it('formats successful response', async () => {
register(routeConfig, async (ctx, req, res) => {
Expand Down
Expand Up @@ -85,12 +85,21 @@ export class HttpResourcesService implements CoreService<InternalHttpResourcesSe
route: RouteConfig<P, Q, B, 'get'>,
handler: HttpResourcesRequestHandler<P, Q, B, Context>
) => {
return router.get<P, Q, B>(route, (context, request, response) => {
return handler(context as Context, request, {
...response,
...this.createResponseToolkit(deps, context, request, response),
});
});
return router.get<P, Q, B>(
{
...route,
options: {
access: 'public',
...route.options,
},
},
(context, request, response) => {
return handler(context as Context, request, {
...response,
...this.createResponseToolkit(deps, context, request, response),
});
}
);
},
};
}
Expand Down
Expand Up @@ -6,6 +6,14 @@
* Side Public License, v 1.
*/

jest.mock('@kbn/server-http-tools', () => {
const module = jest.requireActual('@kbn/server-http-tools');
return {
...module,
createServer: jest.fn(module.createServer),
};
});

import { Server } from 'http';
import { rm, mkdtemp, readFile, writeFile } from 'fs/promises';
import supertest from 'supertest';
Expand All @@ -23,6 +31,7 @@ import type {
RequestHandlerContextBase,
} from '@kbn/core-http-server';
import { Router, type RouterOptions } from '@kbn/core-http-router-server-internal';
import { createServer } from '@kbn/server-http-tools';
import { HttpConfig } from './http_config';
import { HttpServer } from './http_server';
import { Readable } from 'stream';
Expand Down Expand Up @@ -1506,6 +1515,29 @@ describe('setup contract', () => {
}
});

test('registers routes with expected options', async () => {
const { registerStaticDir } = await server.setup(config);
expect(createServer).toHaveBeenCalledTimes(1);
const [{ value: myServer }] = (createServer as jest.Mock).mock.results;
jest.spyOn(myServer, 'route');
expect(myServer.route).toHaveBeenCalledTimes(0);
registerStaticDir('/static/{path*}', assetFolder);
expect(myServer.route).toHaveBeenCalledTimes(1);
expect(myServer.route).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
options: {
app: { access: 'public' },
auth: false,
cache: {
privacy: 'public',
otherwise: 'must-revalidate',
},
},
})
);
});

test('does not throw if called after stop', async () => {
const { registerStaticDir } = await server.setup(config);
await server.stop();
Expand Down
Expand Up @@ -587,6 +587,7 @@ export class HttpServer {
},
},
options: {
app: { access: 'public' },
auth: false,
cache: {
privacy: 'public',
Expand Down
@@ -0,0 +1,23 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { mockRouter } from '@kbn/core-http-router-server-mocks';
import { registerTranslationsRoute } from './translations';

describe('registerTranslationsRoute', () => {
test('registers route with expected options', () => {
const router = mockRouter.create();
registerTranslationsRoute(router, 'en');
expect(router.get).toHaveBeenCalledTimes(1);
expect(router.get).toHaveBeenNthCalledWith(
1,
expect.objectContaining({ options: { access: 'public', authRequired: false } }),
expect.any(Function)
);
});
});
Expand Up @@ -28,6 +28,7 @@ export const registerTranslationsRoute = (router: IRouter, locale: string) => {
}),
},
options: {
access: 'public',
authRequired: false,
},
},
Expand Down
1 change: 1 addition & 0 deletions packages/core/i18n/core-i18n-server-internal/tsconfig.json
Expand Up @@ -25,6 +25,7 @@
"@kbn/i18n",
"@kbn/std",
"@kbn/repo-packages",
"@kbn/core-http-router-server-mocks",
],
"exclude": [
"target/**/*",
Expand Down
@@ -0,0 +1,31 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { registerBootstrapRoute } from './register_bootstrap_route';
import { mockRouter } from '@kbn/core-http-router-server-mocks';

describe('registerBootstrapRoute', () => {
test('register with expected options', () => {
const router = mockRouter.create();
const renderer = jest.fn();
registerBootstrapRoute({ router, renderer });
expect(router.get).toHaveBeenCalledTimes(2);
expect(router.get).toHaveBeenNthCalledWith(
1,
expect.objectContaining({ options: { access: 'public', tags: ['api'] } }),
expect.any(Function)
);
expect(router.get).toHaveBeenNthCalledWith(
2,
expect.objectContaining({
options: { access: 'public', tags: ['api'], authRequired: 'optional' },
}),
expect.any(Function)
);
});
});
Expand Up @@ -21,6 +21,7 @@ export const registerBootstrapRoute = ({
path: '/bootstrap.js',
options: {
tags: ['api'],
access: 'public',
},
validate: false,
},
Expand All @@ -44,6 +45,7 @@ export const registerBootstrapRoute = ({
options: {
authRequired: 'optional',
tags: ['api'],
access: 'public',
},
validate: false,
},
Expand Down
Expand Up @@ -83,6 +83,7 @@ export const registerStatusRoute = ({
options: {
authRequired: 'optional',
tags: ['api'], // ensures that unauthenticated calls receive a 401 rather than a 302 redirect to login page
access: 'public', // needs to be public to allow access from "system" users like k8s readiness probes.
},
validate: {
query: schema.object(
Expand Down
Expand Up @@ -17,6 +17,7 @@ export const registerPrebootStatusRoute = ({ router }: { router: IRouter }) => {
options: {
authRequired: false,
tags: ['api'],
access: 'public', // needs to be public to allow access from "system" users like k8s readiness probes.
},
validate: false,
},
Expand Down
Expand Up @@ -82,7 +82,7 @@ describe('StatusService', () => {
expect(prebootRouterMock.get).toHaveBeenCalledWith(
{
path: '/api/status',
options: { authRequired: false, tags: ['api'] },
options: { authRequired: false, tags: ['api'], access: 'public' },
validate: false,
},
expect.any(Function)
Expand Down
8 changes: 8 additions & 0 deletions packages/kbn-cases-components/src/status/types.ts
Expand Up @@ -6,6 +6,14 @@
* Side Public License, v 1.
*/

/**
* This is being used by Cases in
* x-pack/plugins/cases/common/types/domain/case/v1.ts.
* Introducing a breaking change in this enum will
* force cases to create a version of the domain object
* which in turn will force cases to create a new version
* to most of the Cases APIs.
*/
export enum CaseStatuses {
open = 'open',
'in-progress' = 'in-progress',
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-content-management-utils/index.ts
Expand Up @@ -10,3 +10,4 @@ export * from './src/types';
export * from './src/schema';
export * from './src/saved_object_content_storage';
export * from './src/utils';
export * from './src/msearch';
96 changes: 96 additions & 0 deletions packages/kbn-content-management-utils/src/msearch.ts
@@ -0,0 +1,96 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import Boom from '@hapi/boom';
import { pick } from 'lodash';

import type { StorageContext } from '@kbn/content-management-plugin/server';

import type {
SavedObjectsFindResult,
SavedObject,
SavedObjectReference,
} from '@kbn/core-saved-objects-api-server';

import type { ServicesDefinitionSet, SOWithMetadata, SOWithMetadataPartial } from './types';

type PartialSavedObject<T> = Omit<SavedObject<Partial<T>>, 'references'> & {
references: SavedObjectReference[] | undefined;
};

interface GetMSearchParams {
savedObjectType: string;
cmServicesDefinition: ServicesDefinitionSet;
allowedSavedObjectAttributes: string[];
}

function savedObjectToItem<Attributes extends object>(
savedObject: SavedObject<Attributes> | PartialSavedObject<Attributes>,
allowedSavedObjectAttributes: string[]
): SOWithMetadata | SOWithMetadataPartial {
const {
id,
type,
updated_at: updatedAt,
created_at: createdAt,
attributes,
references,
error,
namespaces,
version,
} = savedObject;

return {
id,
type,
updatedAt,
createdAt,
attributes: pick(attributes, allowedSavedObjectAttributes),
references,
error,
namespaces,
version,
};
}

export interface GetMSearchType<ReturnItem> {
savedObjectType: string;
toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult) => ReturnItem;
}

export const getMSearch = <ReturnItem, SOAttributes extends object>({
savedObjectType,
cmServicesDefinition,
allowedSavedObjectAttributes,
}: GetMSearchParams) => {
return {
savedObjectType,
toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult): ReturnItem => {
const transforms = ctx.utils.getTransforms(cmServicesDefinition);

// Validate DB response and DOWN transform to the request version
const { value, error: resultError } = transforms.mSearch.out.result.down<
ReturnItem,
ReturnItem
>(
// Ran into a case where a schema was broken by a SO attribute that wasn't part of the definition
// so we specify which attributes are allowed
savedObjectToItem<SOAttributes>(
savedObject as SavedObjectsFindResult<SOAttributes>,
allowedSavedObjectAttributes
)
);

if (resultError) {
throw Boom.badRequest(`Invalid response. ${resultError.message}`);
}

return value;
},
};
};

0 comments on commit 54e7184

Please sign in to comment.