Skip to content

Commit 3984bad

Browse files
committed
[Epic] Knowledge Base - API integration tests (#8737) (#197290)
## Summary This is a followup to the main Knowledge Base changes where we've: 1. Fixed the issue with access control to KB entries via bulk actions APIs 2. Added the RBAC validation for the bulk actions API 3. Added integration tests to cover the bulk actions API ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - Genai KB integration tests: [100 ESS + 100 Serverless](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7208) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> (cherry picked from commit fd53861) # Conflicts: # x-pack/test/security_solution_api_integration/tsconfig.json
1 parent 0fa7788 commit 3984bad

8 files changed

Lines changed: 666 additions & 38 deletions

File tree

x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,13 @@ export class DocumentsDataWriter implements DocumentsDataWriter {
117117
{
118118
bool: {
119119
must_not: {
120-
exists: {
121-
field: 'users',
120+
nested: {
121+
path: 'users',
122+
query: {
123+
exists: {
124+
field: 'users',
125+
},
126+
},
122127
},
123128
},
124129
},

x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ import {
2828
} from '../../../ai_assistant_data_clients/knowledge_base/types';
2929
import { ElasticAssistantPluginRouter } from '../../../types';
3030
import { buildResponse } from '../../utils';
31-
import { transformESSearchToKnowledgeBaseEntry } from '../../../ai_assistant_data_clients/knowledge_base/transforms';
31+
import {
32+
transformESSearchToKnowledgeBaseEntry,
33+
transformESToKnowledgeBase,
34+
} from '../../../ai_assistant_data_clients/knowledge_base/transforms';
3235
import {
3336
getUpdateScript,
3437
transformToCreateSchema,
3538
transformToUpdateSchema,
3639
} from '../../../ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry';
40+
import { getKBUserFilter } from './utils';
3741

3842
export interface BulkOperationError {
3943
message: string;
@@ -179,8 +183,19 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug
179183
const spaceId = ctx.elasticAssistant.getSpaceId();
180184
// Authenticated user null check completed in `performChecks()` above
181185
const authenticatedUser = ctx.elasticAssistant.getCurrentUser() as AuthenticatedUser;
186+
const userFilter = getKBUserFilter(authenticatedUser);
187+
const manageGlobalKnowledgeBaseAIAssistant =
188+
kbDataClient?.options.manageGlobalKnowledgeBaseAIAssistant;
182189

183190
if (body.create && body.create.length > 0) {
191+
// RBAC validation
192+
body.create.forEach((entry) => {
193+
const isGlobal = entry.users != null && entry.users.length === 0;
194+
if (isGlobal && !manageGlobalKnowledgeBaseAIAssistant) {
195+
throw new Error(`User lacks privileges to create global knowledge base entries`);
196+
}
197+
});
198+
184199
const result = await kbDataClient?.findDocuments<EsKnowledgeBaseEntrySchema>({
185200
perPage: 100,
186201
page: 1,
@@ -199,6 +214,44 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug
199214
}
200215
}
201216

217+
const validateDocumentsModification = async (
218+
documentIds: string[],
219+
operation: 'delete' | 'update'
220+
) => {
221+
if (!documentIds.length) {
222+
return;
223+
}
224+
const documentsFilter = documentIds.map((id) => `_id:${id}`).join(' OR ');
225+
const entries = await kbDataClient?.findDocuments<EsKnowledgeBaseEntrySchema>({
226+
page: 1,
227+
perPage: 100,
228+
filter: `${documentsFilter} AND ${userFilter}`,
229+
});
230+
const availableEntries = entries
231+
? transformESSearchToKnowledgeBaseEntry(entries.data)
232+
: [];
233+
availableEntries.forEach((entry) => {
234+
// RBAC validation
235+
const isGlobal = entry.users != null && entry.users.length === 0;
236+
if (isGlobal && !manageGlobalKnowledgeBaseAIAssistant) {
237+
throw new Error(
238+
`User lacks privileges to ${operation} global knowledge base entries`
239+
);
240+
}
241+
});
242+
const availableIds = availableEntries.map((doc) => doc.id);
243+
const nonAvailableIds = documentIds.filter((id) => !availableIds.includes(id));
244+
if (nonAvailableIds.length > 0) {
245+
throw new Error(`Could not find documents to ${operation}: ${nonAvailableIds}.`);
246+
}
247+
};
248+
249+
await validateDocumentsModification(body.delete?.ids ?? [], 'delete');
250+
await validateDocumentsModification(
251+
body.update?.map((entry) => entry.id) ?? [],
252+
'update'
253+
);
254+
202255
const writer = await kbDataClient?.getWriter();
203256
const changedAt = new Date().toISOString();
204257
const {
@@ -214,11 +267,11 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug
214267
spaceId,
215268
user: authenticatedUser,
216269
entry,
270+
global: entry.users != null && entry.users.length === 0,
217271
})
218272
),
219273
documentsToDelete: body.delete?.ids,
220274
documentsToUpdate: body.update?.map((entry) =>
221-
// TODO: KB-RBAC check, required when users != null as entry will either be created globally if empty
222275
transformToUpdateSchema({
223276
user: authenticatedUser,
224277
updatedAt: changedAt,
@@ -241,9 +294,10 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug
241294

242295
return buildBulkResponse(response, {
243296
// @ts-ignore-next-line TS2322
244-
updated: docsUpdated,
297+
updated: transformESToKnowledgeBase(docsUpdated),
245298
created: created?.data ? transformESSearchToKnowledgeBaseEntry(created?.data) : [],
246299
deleted: docsDeleted ?? [],
300+
skipped: [],
247301
errors,
248302
});
249303
} catch (err) {

0 commit comments

Comments
 (0)