Skip to content

Commit

Permalink
Merge branch '8.16' into backport/8.16/pr-196615
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Oct 23, 2024
2 parents 684fdc5 + 871137b commit ab4c095
Show file tree
Hide file tree
Showing 12 changed files with 675 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ const getESQLDocumentCountStats = async (
` | EVAL _timestamp_= TO_DOUBLE(DATE_TRUNC(${intervalMs} millisecond, ${getSafeESQLName(
timeFieldName
)}))
| stats rows = count(*) by _timestamp_`
| stats rows = count(*) by _timestamp_
| LIMIT 1000`
);

const request = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,13 @@ export class DocumentsDataWriter implements DocumentsDataWriter {
{
bool: {
must_not: {
exists: {
field: 'users',
nested: {
path: 'users',
query: {
exists: {
field: 'users',
},
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ import {
} from '../../../ai_assistant_data_clients/knowledge_base/types';
import { ElasticAssistantPluginRouter } from '../../../types';
import { buildResponse } from '../../utils';
import { transformESSearchToKnowledgeBaseEntry } from '../../../ai_assistant_data_clients/knowledge_base/transforms';
import {
transformESSearchToKnowledgeBaseEntry,
transformESToKnowledgeBase,
} from '../../../ai_assistant_data_clients/knowledge_base/transforms';
import {
getUpdateScript,
transformToCreateSchema,
transformToUpdateSchema,
} from '../../../ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry';
import { getKBUserFilter } from './utils';

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

if (body.create && body.create.length > 0) {
// RBAC validation
body.create.forEach((entry) => {
const isGlobal = entry.users != null && entry.users.length === 0;
if (isGlobal && !manageGlobalKnowledgeBaseAIAssistant) {
throw new Error(`User lacks privileges to create global knowledge base entries`);
}
});

const result = await kbDataClient?.findDocuments<EsKnowledgeBaseEntrySchema>({
perPage: 100,
page: 1,
Expand All @@ -199,6 +214,44 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug
}
}

const validateDocumentsModification = async (
documentIds: string[],
operation: 'delete' | 'update'
) => {
if (!documentIds.length) {
return;
}
const documentsFilter = documentIds.map((id) => `_id:${id}`).join(' OR ');
const entries = await kbDataClient?.findDocuments<EsKnowledgeBaseEntrySchema>({
page: 1,
perPage: 100,
filter: `${documentsFilter} AND ${userFilter}`,
});
const availableEntries = entries
? transformESSearchToKnowledgeBaseEntry(entries.data)
: [];
availableEntries.forEach((entry) => {
// RBAC validation
const isGlobal = entry.users != null && entry.users.length === 0;
if (isGlobal && !manageGlobalKnowledgeBaseAIAssistant) {
throw new Error(
`User lacks privileges to ${operation} global knowledge base entries`
);
}
});
const availableIds = availableEntries.map((doc) => doc.id);
const nonAvailableIds = documentIds.filter((id) => !availableIds.includes(id));
if (nonAvailableIds.length > 0) {
throw new Error(`Could not find documents to ${operation}: ${nonAvailableIds}.`);
}
};

await validateDocumentsModification(body.delete?.ids ?? [], 'delete');
await validateDocumentsModification(
body.update?.map((entry) => entry.id) ?? [],
'update'
);

const writer = await kbDataClient?.getWriter();
const changedAt = new Date().toISOString();
const {
Expand All @@ -214,11 +267,11 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug
spaceId,
user: authenticatedUser,
entry,
global: entry.users != null && entry.users.length === 0,
})
),
documentsToDelete: body.delete?.ids,
documentsToUpdate: body.update?.map((entry) =>
// TODO: KB-RBAC check, required when users != null as entry will either be created globally if empty
transformToUpdateSchema({
user: authenticatedUser,
updatedAt: changedAt,
Expand All @@ -241,9 +294,10 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug

return buildBulkResponse(response, {
// @ts-ignore-next-line TS2322
updated: docsUpdated,
updated: transformESToKnowledgeBase(docsUpdated),
created: created?.data ? transformESSearchToKnowledgeBaseEntry(created?.data) : [],
deleted: docsDeleted ?? [],
skipped: [],
errors,
});
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ export const DEFAULT_INFERENCE_ENDPOINTS_TABLE_STATE: AllInferenceEndpointsTable
export const PIPELINE_URL = 'ingest/ingest_pipelines';

export const PRECONFIGURED_ENDPOINTS = {
ELSER: '.elser-2',
E5: '.multi-e5-small',
ELSER: '.elser-2-elasticsearch',
E5: '.multilingual-e5-small-elasticsearch',
};
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('Delete Action', () => {
});

it('disable the delete action for preconfigured endpoint', () => {
const preconfiguredMockItem = { ...mockItem, endpoint: '.elser-2' };
const preconfiguredMockItem = { ...mockItem, endpoint: '.multilingual-e5-small-elasticsearch' };
render(<Wrapper item={preconfiguredMockItem} />);

expect(screen.getByTestId('inferenceUIDeleteAction')).toBeDisabled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const inferenceEndpoints = [
task_settings: {},
},
{
inference_id: '.elser-2',
inference_id: '.elser-2-elasticsearch',
task_type: 'sparse_embedding',
service: 'elasticsearch',
service_settings: {
Expand All @@ -57,7 +57,7 @@ const inferenceEndpoints = [
task_settings: {},
},
{
inference_id: '.multi-e5-small',
inference_id: '.multilingual-e5-small-elasticsearch',
task_type: 'text_embedding',
service: 'elasticsearch',
service_settings: {
Expand All @@ -80,8 +80,8 @@ describe('When the tabular page is loaded', () => {
render(<TabularPage inferenceEndpoints={inferenceEndpoints} />);

const rows = screen.getAllByRole('row');
expect(rows[1]).toHaveTextContent('.elser-2');
expect(rows[2]).toHaveTextContent('.multi-e5-small');
expect(rows[1]).toHaveTextContent('.elser-2-elasticsearch');
expect(rows[2]).toHaveTextContent('.multilingual-e5-small-elasticsearch');
expect(rows[3]).toHaveTextContent('local-model');
expect(rows[4]).toHaveTextContent('my-elser-model-05');
expect(rows[5]).toHaveTextContent('third-party-model');
Expand Down
Loading

0 comments on commit ab4c095

Please sign in to comment.