Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Observability AI Assistant Tests Deployment Agnostic (#205194) #206516

Merged
merged 2 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -1164,13 +1164,15 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql

### Observability Plugins


# Observability AI Assistant
x-pack/test/observability_ai_assistant_api_integration @elastic/obs-ai-assistant
x-pack/test/observability_ai_assistant_functional @elastic/obs-ai-assistant
x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai-assistant

# Infra Monitoring
/x-pack/test_serverless/api_integration/test_suites/common/data_usage @elastic/obs-ai-assistant @elastic/security-solution
/x-pack/test_serverless/functional/test_suites/common/data_usage @elastic/obs-ai-assistant @elastic/security-solution
/x-pack/test/observability_ai_assistant_api_integration @elastic/obs-ai-assistant
/x-pack/test/observability_ai_assistant_functional @elastic/obs-ai-assistant
/x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai-assistant
/x-pack/test/functional/es_archives/observability/ai_assistant @elastic/obs-ai-assistant
/x-pack/test/api_integration/deployment_agnostic/apis/observability/ai_assistant @elastic/obs-ai-assistant
# Infra Obs
## This plugin mostly contains the codebase for the infra services, but also includes some code for the Logs UI app.
## To keep @elastic/obs-ux-logs-team as codeowner of the plugin manifest without requiring a review for all the other code changes
## the priority on codeownership will be as follow:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@
import expect from '@kbn/expect';
import { MessageRole, type Message } from '@kbn/observability-ai-assistant-plugin/common';
import { PassThrough } from 'stream';
import { createLlmProxy, LlmProxy } from '../../common/create_llm_proxy';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { createProxyActionConnector, deleteActionConnector } from '../../common/action_connectors';
import { ForbiddenApiError } from '../../common/config';

export default function ApiTest({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
import {
LlmProxy,
createLlmProxy,
} from '../../../../../../observability_ai_assistant_api_integration/common/create_llm_proxy';
import { SupertestWithRoleScope } from '../../../../services/role_scoped_supertest';
import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context';

export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) {
const log = getService('log');
const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient');

const CHAT_API_URL = `/internal/observability_ai_assistant/chat`;
const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantApi');

const messages: Message[] = [
{
Expand All @@ -37,37 +36,50 @@ export default function ApiTest({ getService }: FtrProviderContext) {
},
];

describe('/internal/observability_ai_assistant/chat', () => {
describe('/internal/observability_ai_assistant/chat', function () {
// Fails on MKI: https://github.com/elastic/kibana/issues/205581
this.tags(['failsOnMKI']);
let proxy: LlmProxy;

let connectorId: string;

before(async () => {
proxy = await createLlmProxy(log);
connectorId = await createProxyActionConnector({ supertest, log, port: proxy.getPort() });
connectorId = await observabilityAIAssistantAPIClient.createProxyActionConnector({
port: proxy.getPort(),
});
});

after(async () => {
proxy.close();
await deleteActionConnector({ supertest, connectorId, log });
await observabilityAIAssistantAPIClient.deleteActionConnector({
actionId: connectorId,
});
});

it("returns a 4xx if the connector doesn't exist", async () => {
await supertest
.post(CHAT_API_URL)
.set('kbn-xsrf', 'foo')
.send({
name: 'my_api_call',
messages,
connectorId: 'does not exist',
functions: [],
scopes: ['all'],
})
.expect(404);
const { status } = await observabilityAIAssistantAPIClient.editor({
endpoint: 'POST /internal/observability_ai_assistant/chat',
params: {
body: {
name: 'my_api_call',
messages,
connectorId: 'does not exist',
functions: [],
scopes: ['all'],
},
},
});
expect(status).to.be(404);
});

it('returns a streaming response from the server', async () => {
const NUM_RESPONSES = 5;
const roleScopedSupertest = getService('roleScopedSupertest');
const supertestEditorWithCookieCredentials: SupertestWithRoleScope =
await roleScopedSupertest.getSupertestWithRoleScope('editor', {
useCookieHeader: true,
withInternalHeaders: true,
});

await Promise.race([
new Promise((resolve, reject) => {
Expand All @@ -81,9 +93,8 @@ export default function ApiTest({ getService }: FtrProviderContext) {
const receivedChunks: Array<Record<string, any>> = [];

const passThrough = new PassThrough();
supertest
.post(CHAT_API_URL)
.set('kbn-xsrf', 'foo')
supertestEditorWithCookieCredentials
.post('/internal/observability_ai_assistant/chat')
.on('error', reject)
.send({
name: 'my_api_call',
Expand Down Expand Up @@ -136,26 +147,21 @@ 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.unauthorizedUser({
endpoint: `POST ${CHAT_API_URL}`,
params: {
body: {
name: 'my_api_call',
messages,
connectorId,
functions: [],
scopes: ['all'],
},
const { status } = await observabilityAIAssistantAPIClient.viewer({
endpoint: 'POST /internal/observability_ai_assistant/chat',
params: {
body: {
name: 'my_api_call',
messages,
connectorId,
functions: [],
scopes: ['all'],
},
});
throw new ForbiddenApiError('Expected unauthorizedUser() to throw a 403 Forbidden error');
} catch (e) {
expect(e.status).to.be(403);
}
},
});
expect(status).to.be(403);
});
});
});
Expand Down
Loading
Loading