From 55070cf6dc71c53ae433dd9da5a30573fdcae8d2 Mon Sep 17 00:00:00 2001 From: Viduni Wickramarachchi Date: Fri, 27 Dec 2024 10:07:42 -0500 Subject: [PATCH 1/4] [Obs AI Assistant] Add route privilege tests for serverless (#204884) --- .../common/forbidden_api_error.ts | 16 +++ .../observability_ai_assistant_api_client.ts | 19 ++- .../ai_assistant/tests/chat/chat.spec.ts | 71 +++------- .../tests/complete/complete.spec.ts | 23 ++++ .../tests/connectors/connectors.spec.ts | 22 +++- .../tests/conversations/conversations.spec.ts | 124 ++++++++++++++++++ .../knowledge_base/knowledge_base.spec.ts | 57 ++++++++ .../knowledge_base_setup.spec.ts | 25 +++- .../knowledge_base_status.spec.ts | 23 +++- .../knowledge_base_user_instructions.spec.ts | 38 ++++++ 10 files changed, 359 insertions(+), 59 deletions(-) create mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts new file mode 100644 index 0000000000000..c404920bc55e9 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +export class ForbiddenApiError extends Error { + status: number; + + constructor(message: string = 'Forbidden') { + super(message); + this.name = 'ForbiddenApiError'; + this.status = 403; + } +} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts index 3ac941501ae7c..d8ca8661b90b4 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts @@ -40,7 +40,11 @@ export function getObservabilityAIAssistantApiClient({ } } -type ObservabilityAIAssistantApiClientKey = 'slsAdmin' | 'slsEditor' | 'slsUser'; +type ObservabilityAIAssistantApiClientKey = + | 'slsAdmin' + | 'slsEditor' + | 'slsUser' + | 'slsUnauthorized'; export type ObservabilityAIAssistantApiClient = Record< ObservabilityAIAssistantApiClientKey, @@ -195,18 +199,27 @@ export async function getObservabilityAIAssistantApiClientService({ const svlSharedConfig = getService('config'); const roleScopedSupertest = getService('roleScopedSupertest'); + // admin user const supertestAdminWithCookieCredentials: SupertestWithRoleScope = await roleScopedSupertest.getSupertestWithRoleScope('admin', { useCookieHeader: true, withInternalHeaders: true, }); + // editor user const supertestEditorWithCookieCredentials: SupertestWithRoleScope = await roleScopedSupertest.getSupertestWithRoleScope('editor', { useCookieHeader: true, withInternalHeaders: true, }); + // unauthorized user + const supertestUnauthorizedWithCookieCredentials: SupertestWithRoleScope = + await roleScopedSupertest.getSupertestWithRoleScope('viewer', { + useCookieHeader: true, + withInternalHeaders: false, // No internal headers for unauthorized users + }); + return { // defaults to elastic_admin user when used without auth slsUser: await getObservabilityAIAssistantApiClient({ @@ -222,5 +235,9 @@ export async function getObservabilityAIAssistantApiClientService({ svlSharedConfig, supertestUserWithCookieCredentials: supertestEditorWithCookieCredentials, }), + slsUnauthorized: await getObservabilityAIAssistantApiClient({ + svlSharedConfig, + supertestUserWithCookieCredentials: supertestUnauthorizedWithCookieCredentials, + }), }; } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts index 2a25a309e8174..0ad911f792a7d 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts @@ -16,6 +16,7 @@ import { SupertestWithRoleScope } from '@kbn/test-suites-xpack/api_integration/d import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors'; import type { InternalRequestHeader, RoleCredentials } from '../../../../../../shared/services'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -23,6 +24,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const svlCommonApi = getService('svlCommonApi'); const log = getService('log'); const roleScopedSupertest = getService('roleScopedSupertest'); + const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); let supertestEditorWithCookieCredentials: SupertestWithRoleScope; @@ -170,57 +172,26 @@ export default function ApiTest({ getService }: FtrProviderContext) { ]); }); - it.skip('returns a useful error if the request fails', async () => { - const interceptor = proxy.intercept('conversation', () => true); - - const passThrough = new PassThrough(); - - supertestWithoutAuth - .post(CHAT_API_URL) - .set(roleAuthc.apiKeyHeader) - .set(internalReqHeader) - .set('kbn-xsrf', 'foo') - .send({ - name: 'my_api_call', - messages, - connectorId, - functions: [], - scopes: ['all'], - }) - .expect(200) - .pipe(passThrough); - - let data: string = ''; - - passThrough.on('data', (chunk) => { - data += chunk.toString('utf-8'); + describe('security roles and access privileges', () => { + it('should deny access for users without the ai_assistant privilege', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: `POST ${CHAT_API_URL}`, + params: { + body: { + name: 'my_api_call', + messages, + connectorId, + functions: [], + scopes: ['all'], + }, + }, + }); + throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); + } catch (e) { + expect(e.status).to.be(403); + } }); - - const simulator = await interceptor.waitForIntercept(); - - await simulator.status(400); - - await simulator.rawWrite( - JSON.stringify({ - error: { - code: 'context_length_exceeded', - message: - "This model's maximum context length is 8192 tokens. However, your messages resulted in 11036 tokens. Please reduce the length of the messages.", - param: 'messages', - type: 'invalid_request_error', - }, - }) - ); - - await simulator.rawEnd(); - - await new Promise((resolve) => passThrough.on('end', () => resolve())); - - const response = JSON.parse(data.trim()); - - expect(response.error.message).to.be( - `Token limit reached. Token limit is 8192, but the current conversation has 11036 tokens.` - ); }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts index 4d3e1baed3f9b..3455387e7624d 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts @@ -34,6 +34,7 @@ import { } from '../conversations/helpers'; import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors'; import type { InternalRequestHeader, RoleCredentials } from '../../../../../../shared/services'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -547,5 +548,27 @@ export default function ApiTest({ getService }: FtrProviderContext) { // todo it.skip('executes a function', async () => {}); + + describe('security roles and access privileges', () => { + it('should deny access for users without the ai_assistant privilege', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'POST /internal/observability_ai_assistant/chat/complete', + params: { + body: { + messages, + connectorId, + persist: false, + screenContexts: [], + scopes: ['all'], + }, + }, + }); + throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts index 2096abe74e2e8..b133b2d56aa1e 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts @@ -13,6 +13,9 @@ import type { RoleCredentials, SupertestWithoutAuthProviderType, } from '../../../../../../shared/services'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; + +const CONNECTOR_API_URL = '/internal/observability_ai_assistant/connectors'; export default function ApiTest({ getService }: FtrProviderContext) { const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); @@ -47,14 +50,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('Returns a 2xx for enterprise license', async () => { await observabilityAIAssistantAPIClient .slsEditor({ - endpoint: 'GET /internal/observability_ai_assistant/connectors', + endpoint: `GET ${CONNECTOR_API_URL}`, }) .expect(200); }); it('returns an empty list of connectors', async () => { const res = await observabilityAIAssistantAPIClient.slsEditor({ - endpoint: 'GET /internal/observability_ai_assistant/connectors', + endpoint: `GET ${CONNECTOR_API_URL}`, }); expect(res.body.length).to.be(0); @@ -70,7 +73,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); const res = await observabilityAIAssistantAPIClient.slsEditor({ - endpoint: 'GET /internal/observability_ai_assistant/connectors', + endpoint: `GET ${CONNECTOR_API_URL}`, }); expect(res.body.length).to.be(1); @@ -83,6 +86,19 @@ export default function ApiTest({ getService }: FtrProviderContext) { roleAuthc, }); }); + + describe('security roles and access privileges', () => { + it('should deny access for users without the ai_assistant privilege', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: `GET ${CONNECTOR_API_URL}`, + }); + throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts index 7033e0660f5c6..e4aa90993bd3b 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts @@ -14,6 +14,7 @@ import { } from '@kbn/observability-ai-assistant-plugin/common/types'; import type { FtrProviderContext } from '../../common/ftr_provider_context'; import type { SupertestReturnType } from '../../common/observability_ai_assistant_api_client'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); @@ -253,5 +254,128 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); }); + + describe('security roles and access privileges', () => { + describe('should deny access for users without the ai_assistant privilege', () => { + let createResponse: Awaited< + SupertestReturnType<'POST /internal/observability_ai_assistant/conversation'> + >; + before(async () => { + createResponse = await observabilityAIAssistantAPIClient + .slsEditor({ + endpoint: 'POST /internal/observability_ai_assistant/conversation', + params: { + body: { + conversation: conversationCreate, + }, + }, + }) + .expect(200); + }); + + after(async () => { + await observabilityAIAssistantAPIClient + .slsEditor({ + endpoint: 'DELETE /internal/observability_ai_assistant/conversation/{conversationId}', + params: { + path: { + conversationId: createResponse.body.conversation.id, + }, + }, + }) + .expect(200); + }); + + it('POST /internal/observability_ai_assistant/conversation', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'POST /internal/observability_ai_assistant/conversation', + params: { + body: { + conversation: conversationCreate, + }, + }, + }); + // throw new ForbiddenApiError( + // 'Expected slsUnauthorized() to throw a 403 Forbidden error' + // ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('POST /internal/observability_ai_assistant/conversations', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'POST /internal/observability_ai_assistant/conversations', + }); + // throw new ForbiddenApiError( + // 'Expected slsUnauthorized() to throw a 403 Forbidden error' + // ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('PUT /internal/observability_ai_assistant/conversation/{conversationId}', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', + params: { + path: { + conversationId: createResponse.body.conversation.id, + }, + body: { + conversation: merge(omit(conversationUpdate, 'conversation.id'), { + conversation: { id: createResponse.body.conversation.id }, + }), + }, + }, + }); + // throw new ForbiddenApiError( + // 'Expected slsUnauthorized() to throw a 403 Forbidden error' + // ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('GET /internal/observability_ai_assistant/conversation/{conversationId}', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', + params: { + path: { + conversationId: createResponse.body.conversation.id, + }, + }, + }); + // throw new ForbiddenApiError( + // 'Expected slsUnauthorized() to throw a 403 Forbidden error' + // ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('DELETE /internal/observability_ai_assistant/conversation/{conversationId}', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'DELETE /internal/observability_ai_assistant/conversation/{conversationId}', + params: { + path: { + conversationId: createResponse.body.conversation.id, + }, + }, + }); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts index f156ba7e583b5..8f29716ae3eda 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts @@ -15,6 +15,7 @@ import { } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers'; import { type KnowledgeBaseEntry } from '@kbn/observability-ai-assistant-plugin/common'; import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const ml = getService('ml'); @@ -212,6 +213,62 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(entries[0].title).to.eql('My title b'); }); }); + + describe('security roles and access privileges', () => { + describe('should deny access for users without the ai_assistant privilege', () => { + it('POST /internal/observability_ai_assistant/kb/entries/save', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'POST /internal/observability_ai_assistant/kb/entries/save', + params: { + body: { + id: 'my-doc-id-1', + title: 'My title', + text: 'My content', + }, + }, + }); + throw new ForbiddenApiError( + 'Expected unauthorizedUser() to throw a 403 Forbidden error' + ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('GET /internal/observability_ai_assistant/kb/entries', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'GET /internal/observability_ai_assistant/kb/entries', + params: { + query: { query: '', sortBy: 'title', sortDirection: 'asc' }, + }, + }); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('DELETE /internal/observability_ai_assistant/kb/entries/{entryId}', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'DELETE /internal/observability_ai_assistant/kb/entries/{entryId}', + params: { + path: { entryId: 'my-doc-id-1' }, + }, + }); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts index 87ceec18f1985..1899dbbb5daf1 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts @@ -14,6 +14,9 @@ import { } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers'; import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; + +export const KNOWLEDGE_BASE_SETUP_API_URL = '/internal/observability_ai_assistant/kb/setup'; export default function ApiTest({ getService }: FtrProviderContext) { const ml = getService('ml'); @@ -33,7 +36,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { await createKnowledgeBaseModel(ml); const res = await observabilityAIAssistantAPIClient .slsAdmin({ - endpoint: 'POST /internal/observability_ai_assistant/kb/setup', + endpoint: `POST ${KNOWLEDGE_BASE_SETUP_API_URL}`, params: { query: { model_id: TINY_ELSER.id, @@ -52,7 +55,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns bad request if model cannot be installed', async () => { const res = await observabilityAIAssistantAPIClient .slsAdmin({ - endpoint: 'POST /internal/observability_ai_assistant/kb/setup', + endpoint: `POST ${KNOWLEDGE_BASE_SETUP_API_URL}`, params: { query: { model_id: TINY_ELSER.id, @@ -66,5 +69,23 @@ export default function ApiTest({ getService }: FtrProviderContext) { 'No known trained model with model_id [pt_tiny_elser]' ); }); + + describe('security roles and access privileges', () => { + it('should deny access for users without the ai_assistant privilege', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: `POST ${KNOWLEDGE_BASE_SETUP_API_URL}`, + params: { + query: { + model_id: TINY_ELSER.id, + }, + }, + }); + throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts index 207badc1b855a..3058f90823546 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts @@ -14,6 +14,10 @@ import { } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers'; import { AI_ASSISTANT_KB_INFERENCE_ID } from '@kbn/observability-ai-assistant-plugin/server/service/inference_endpoint'; import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; +import { KNOWLEDGE_BASE_SETUP_API_URL } from './knowledge_base_setup.spec'; + +const KNOWLEDGE_BASE_STATUS_API_URL = '/internal/observability_ai_assistant/kb/status'; export default function ApiTest({ getService }: FtrProviderContext) { const ml = getService('ml'); @@ -27,7 +31,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { await createKnowledgeBaseModel(ml); await observabilityAIAssistantAPIClient .slsAdmin({ - endpoint: 'POST /internal/observability_ai_assistant/kb/setup', + endpoint: `POST ${KNOWLEDGE_BASE_SETUP_API_URL}`, params: { query: { model_id: TINY_ELSER.id, @@ -45,7 +49,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns correct status after knowledge base is setup', async () => { const res = await observabilityAIAssistantAPIClient .slsEditor({ - endpoint: 'GET /internal/observability_ai_assistant/kb/status', + endpoint: `GET ${KNOWLEDGE_BASE_STATUS_API_URL}`, }) .expect(200); @@ -59,12 +63,25 @@ export default function ApiTest({ getService }: FtrProviderContext) { const res = await observabilityAIAssistantAPIClient .slsEditor({ - endpoint: 'GET /internal/observability_ai_assistant/kb/status', + endpoint: `GET ${KNOWLEDGE_BASE_STATUS_API_URL}`, }) .expect(200); expect(res.body.enabled).to.be(true); expect(res.body.ready).to.be(false); }); + + describe('security roles and access privileges', () => { + it('should deny access for users without the ai_assistant privilege', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: `GET ${KNOWLEDGE_BASE_STATUS_API_URL}`, + }); + throw new ForbiddenApiError('Expected unauthorizedUser() to throw a 403 Forbidden error'); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts index 0557d43830bc0..00f53e356a345 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts @@ -24,6 +24,7 @@ import { import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import type { InternalRequestHeader, RoleCredentials } from '../../../../../../shared/services'; +import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); @@ -329,5 +330,42 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(conversation.messages.length).to.be(5); }); }); + + describe('security roles and access privileges', () => { + describe('should deny access for users without the ai_assistant privilege', () => { + it('PUT /internal/observability_ai_assistant/kb/user_instructions', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'PUT /internal/observability_ai_assistant/kb/user_instructions', + params: { + body: { + id: 'test-instruction', + text: 'Test user instruction', + public: true, + }, + }, + }); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + + it('GET /internal/observability_ai_assistant/kb/user_instructions', async () => { + try { + await observabilityAIAssistantAPIClient.slsUnauthorized({ + endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions', + }); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); + } catch (e) { + expect(e.status).to.be(403); + } + }); + }); + }); }); } From d53e1e23e347597cdaa50c33eda7d9b1ad9f2643 Mon Sep 17 00:00:00 2001 From: Viduni Wickramarachchi Date: Fri, 27 Dec 2024 10:10:34 -0500 Subject: [PATCH 2/4] [Obs AI Assistant] Add route privilege tests for serverless (#204884) --- .../tests/conversations/conversations.spec.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts index e4aa90993bd3b..88c386cbbdb27 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts @@ -296,9 +296,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }, }); - // throw new ForbiddenApiError( - // 'Expected slsUnauthorized() to throw a 403 Forbidden error' - // ); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); } catch (e) { expect(e.status).to.be(403); } @@ -309,9 +309,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { await observabilityAIAssistantAPIClient.slsUnauthorized({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }); - // throw new ForbiddenApiError( - // 'Expected slsUnauthorized() to throw a 403 Forbidden error' - // ); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); } catch (e) { expect(e.status).to.be(403); } @@ -332,9 +332,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }, }); - // throw new ForbiddenApiError( - // 'Expected slsUnauthorized() to throw a 403 Forbidden error' - // ); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); } catch (e) { expect(e.status).to.be(403); } @@ -350,9 +350,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }, }); - // throw new ForbiddenApiError( - // 'Expected slsUnauthorized() to throw a 403 Forbidden error' - // ); + throw new ForbiddenApiError( + 'Expected slsUnauthorized() to throw a 403 Forbidden error' + ); } catch (e) { expect(e.status).to.be(403); } From 9470903a9f85cce6cb435348348f042b16ac3dd3 Mon Sep 17 00:00:00 2001 From: Viduni Wickramarachchi Date: Mon, 30 Dec 2024 09:17:41 -0500 Subject: [PATCH 3/4] [Obs AI Assistant] Address PR comments (#204884) --- .../common/forbidden_api_error.ts | 16 ----- .../observability_ai_assistant_api_client.ts | 4 +- .../ai_assistant/tests/chat/chat.spec.ts | 12 ++-- .../tests/complete/complete.spec.ts | 12 ++-- .../tests/connectors/connectors.spec.ts | 12 ++-- .../tests/conversations/conversations.spec.ts | 66 ++++++------------- .../knowledge_base/knowledge_base.spec.ts | 40 ++++------- .../knowledge_base_setup.spec.ts | 12 ++-- .../knowledge_base_status.spec.ts | 12 ++-- .../knowledge_base_user_instructions.spec.ts | 27 +++----- 10 files changed, 62 insertions(+), 151 deletions(-) delete mode 100644 x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts deleted file mode 100644 index c404920bc55e9..0000000000000 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/forbidden_api_error.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ - -export class ForbiddenApiError extends Error { - status: number; - - constructor(message: string = 'Forbidden') { - super(message); - this.name = 'ForbiddenApiError'; - this.status = 403; - } -} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts index d8ca8661b90b4..566d06702872f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/common/observability_ai_assistant_api_client.ts @@ -216,8 +216,8 @@ export async function getObservabilityAIAssistantApiClientService({ // unauthorized user const supertestUnauthorizedWithCookieCredentials: SupertestWithRoleScope = await roleScopedSupertest.getSupertestWithRoleScope('viewer', { - useCookieHeader: true, - withInternalHeaders: false, // No internal headers for unauthorized users + useCookieHeader: false, + withInternalHeaders: true, }); return { diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts index 0ad911f792a7d..40f3db279135e 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/chat/chat.spec.ts @@ -16,7 +16,6 @@ import { SupertestWithRoleScope } from '@kbn/test-suites-xpack/api_integration/d import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors'; import type { InternalRequestHeader, RoleCredentials } from '../../../../../../shared/services'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -174,8 +173,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { it('should deny access for users without the ai_assistant privilege', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: `POST ${CHAT_API_URL}`, params: { body: { @@ -186,11 +185,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { scopes: ['all'], }, }, - }); - throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts index 3455387e7624d..47aa5018f810a 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/complete/complete.spec.ts @@ -34,7 +34,6 @@ import { } from '../conversations/helpers'; import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors'; import type { InternalRequestHeader, RoleCredentials } from '../../../../../../shared/services'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -551,8 +550,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { it('should deny access for users without the ai_assistant privilege', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'POST /internal/observability_ai_assistant/chat/complete', params: { body: { @@ -563,11 +562,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { scopes: ['all'], }, }, - }); - throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts index b133b2d56aa1e..5ea2ad9e873bb 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts @@ -13,7 +13,6 @@ import type { RoleCredentials, SupertestWithoutAuthProviderType, } from '../../../../../../shared/services'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; const CONNECTOR_API_URL = '/internal/observability_ai_assistant/connectors'; @@ -89,14 +88,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { it('should deny access for users without the ai_assistant privilege', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: `GET ${CONNECTOR_API_URL}`, - }); - throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts index 88c386cbbdb27..6656ea0407817 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/conversations/conversations.spec.ts @@ -14,7 +14,6 @@ import { } from '@kbn/observability-ai-assistant-plugin/common/types'; import type { FtrProviderContext } from '../../common/ftr_provider_context'; import type { SupertestReturnType } from '../../common/observability_ai_assistant_api_client'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); @@ -287,39 +286,29 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); it('POST /internal/observability_ai_assistant/conversation', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'POST /internal/observability_ai_assistant/conversation', params: { body: { conversation: conversationCreate, }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('POST /internal/observability_ai_assistant/conversations', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'POST /internal/observability_ai_assistant/conversations', - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('PUT /internal/observability_ai_assistant/conversation/{conversationId}', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -331,49 +320,34 @@ export default function ApiTest({ getService }: FtrProviderContext) { }), }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('GET /internal/observability_ai_assistant/conversation/{conversationId}', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { conversationId: createResponse.body.conversation.id, }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('DELETE /internal/observability_ai_assistant/conversation/{conversationId}', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'DELETE /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { conversationId: createResponse.body.conversation.id, }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts index 8f29716ae3eda..f5413de3f3ff5 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base.spec.ts @@ -15,7 +15,6 @@ import { } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers'; import { type KnowledgeBaseEntry } from '@kbn/observability-ai-assistant-plugin/common'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const ml = getService('ml'); @@ -217,8 +216,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { describe('should deny access for users without the ai_assistant privilege', () => { it('POST /internal/observability_ai_assistant/kb/entries/save', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'POST /internal/observability_ai_assistant/kb/entries/save', params: { body: { @@ -227,45 +226,30 @@ export default function ApiTest({ getService }: FtrProviderContext) { text: 'My content', }, }, - }); - throw new ForbiddenApiError( - 'Expected unauthorizedUser() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('GET /internal/observability_ai_assistant/kb/entries', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'GET /internal/observability_ai_assistant/kb/entries', params: { query: { query: '', sortBy: 'title', sortDirection: 'asc' }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('DELETE /internal/observability_ai_assistant/kb/entries/{entryId}', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'DELETE /internal/observability_ai_assistant/kb/entries/{entryId}', params: { path: { entryId: 'my-doc-id-1' }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts index 1899dbbb5daf1..6f99a841f4d9f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_setup.spec.ts @@ -14,7 +14,6 @@ import { } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; export const KNOWLEDGE_BASE_SETUP_API_URL = '/internal/observability_ai_assistant/kb/setup'; @@ -72,19 +71,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { it('should deny access for users without the ai_assistant privilege', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: `POST ${KNOWLEDGE_BASE_SETUP_API_URL}`, params: { query: { model_id: TINY_ELSER.id, }, }, - }); - throw new ForbiddenApiError('Expected slsUnauthorized() to throw a 403 Forbidden error'); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts index 3058f90823546..458cff655d404 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_status.spec.ts @@ -14,7 +14,6 @@ import { } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers'; import { AI_ASSISTANT_KB_INFERENCE_ID } from '@kbn/observability-ai-assistant-plugin/server/service/inference_endpoint'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; import { KNOWLEDGE_BASE_SETUP_API_URL } from './knowledge_base_setup.spec'; const KNOWLEDGE_BASE_STATUS_API_URL = '/internal/observability_ai_assistant/kb/status'; @@ -73,14 +72,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { it('should deny access for users without the ai_assistant privilege', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: `GET ${KNOWLEDGE_BASE_STATUS_API_URL}`, - }); - throw new ForbiddenApiError('Expected unauthorizedUser() to throw a 403 Forbidden error'); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts index 00f53e356a345..e6d954529d759 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/knowledge_base/knowledge_base_user_instructions.spec.ts @@ -24,7 +24,6 @@ import { import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import type { InternalRequestHeader, RoleCredentials } from '../../../../../../shared/services'; -import { ForbiddenApiError } from '../../common/forbidden_api_error'; export default function ApiTest({ getService }: FtrProviderContext) { const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); @@ -334,8 +333,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('security roles and access privileges', () => { describe('should deny access for users without the ai_assistant privilege', () => { it('PUT /internal/observability_ai_assistant/kb/user_instructions', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'PUT /internal/observability_ai_assistant/kb/user_instructions', params: { body: { @@ -344,26 +343,16 @@ export default function ApiTest({ getService }: FtrProviderContext) { public: true, }, }, - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); it('GET /internal/observability_ai_assistant/kb/user_instructions', async () => { - try { - await observabilityAIAssistantAPIClient.slsUnauthorized({ + await observabilityAIAssistantAPIClient + .slsUnauthorized({ endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions', - }); - throw new ForbiddenApiError( - 'Expected slsUnauthorized() to throw a 403 Forbidden error' - ); - } catch (e) { - expect(e.status).to.be(403); - } + }) + .expect(403); }); }); }); From 6beb135311501cd743043a11f4e0bb39340a5fe8 Mon Sep 17 00:00:00 2001 From: Viduni Wickramarachchi Date: Fri, 3 Jan 2025 08:32:15 -0500 Subject: [PATCH 4/4] [Obs AI Assistant] Remove URL constant (#204884) --- .../ai_assistant/tests/connectors/connectors.spec.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts index 5ea2ad9e873bb..2c112f85fc219 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/ai_assistant/tests/connectors/connectors.spec.ts @@ -14,8 +14,6 @@ import type { SupertestWithoutAuthProviderType, } from '../../../../../../shared/services'; -const CONNECTOR_API_URL = '/internal/observability_ai_assistant/connectors'; - export default function ApiTest({ getService }: FtrProviderContext) { const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient'); const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -49,14 +47,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('Returns a 2xx for enterprise license', async () => { await observabilityAIAssistantAPIClient .slsEditor({ - endpoint: `GET ${CONNECTOR_API_URL}`, + endpoint: `GET /internal/observability_ai_assistant/connectors`, }) .expect(200); }); it('returns an empty list of connectors', async () => { const res = await observabilityAIAssistantAPIClient.slsEditor({ - endpoint: `GET ${CONNECTOR_API_URL}`, + endpoint: `GET /internal/observability_ai_assistant/connectors`, }); expect(res.body.length).to.be(0); @@ -72,7 +70,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); const res = await observabilityAIAssistantAPIClient.slsEditor({ - endpoint: `GET ${CONNECTOR_API_URL}`, + endpoint: `GET /internal/observability_ai_assistant/connectors`, }); expect(res.body.length).to.be(1); @@ -90,7 +88,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('should deny access for users without the ai_assistant privilege', async () => { await observabilityAIAssistantAPIClient .slsUnauthorized({ - endpoint: `GET ${CONNECTOR_API_URL}`, + endpoint: `GET /internal/observability_ai_assistant/connectors`, }) .expect(403); });