Skip to content

Commit

Permalink
[8.x] [Security GenAI] When indices referenced in KB index entries ar…
Browse files Browse the repository at this point in the history
…e deleted from OUTSIDE the AI Assistant KB UI, there is not indication to the user (#197156) (#197722) (#197895)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security GenAI] When indices referenced in KB index entries are
deleted from OUTSIDE the AI Assistant KB UI, there is not indication to
the user (#197156)
(#197722)](#197722)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Ievgen
Sorokopud","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-25T19:17:57Z","message":"[Security
GenAI] When indices referenced in KB index entries are deleted from
OUTSIDE the AI Assistant KB UI, there is not indication to the user
(#197156) (#197722)\n\n## Summary\r\n\r\nBug
https://github.com/elastic/kibana/issues/197156\r\n\r\nThis is a UI part
of the bug that warns a user about missing indices\r\nused in knowledge
base entries.\r\n\r\n### To test\r\n\r\n1. Add an index entry that uses
existing index\r\n2. Remove that index\r\n3. Go back to knowledge base
entries page\r\n4. You should see warning icon next to the name of the
index entry which\r\nuses removed index. Also, when you edit that entry
you will see `Index\r\ndoesn't exist` error next to the `Index` field in
the flyout\r\n\r\n<img width=\"1458\" alt=\"Screenshot 2024-10-24 at 19
54
36\"\r\nsrc=\"https://github.com/user-attachments/assets/7d4468f9-fada-4416-9480-99bfca3de220\">\r\n\r\n<img
width=\"615\" alt=\"Screenshot 2024-10-24 at 19 54
52\"\r\nsrc=\"https://github.com/user-attachments/assets/fd9bbe80-0a3c-40b8-909a-93f8082e69eb\">\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"a1d755a675b05269f167d160f4c0c28a83d5e4d5","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:
SecuritySolution","backport:prev-minor","Team:Security Generative
AI","v8.16.0"],"title":"[Security GenAI] When indices referenced in KB
index entries are deleted from OUTSIDE the AI Assistant KB UI, there is
not indication to the user
(#197156)","number":197722,"url":"https://github.com/elastic/kibana/pull/197722","mergeCommit":{"message":"[Security
GenAI] When indices referenced in KB index entries are deleted from
OUTSIDE the AI Assistant KB UI, there is not indication to the user
(#197156) (#197722)\n\n## Summary\r\n\r\nBug
https://github.com/elastic/kibana/issues/197156\r\n\r\nThis is a UI part
of the bug that warns a user about missing indices\r\nused in knowledge
base entries.\r\n\r\n### To test\r\n\r\n1. Add an index entry that uses
existing index\r\n2. Remove that index\r\n3. Go back to knowledge base
entries page\r\n4. You should see warning icon next to the name of the
index entry which\r\nuses removed index. Also, when you edit that entry
you will see `Index\r\ndoesn't exist` error next to the `Index` field in
the flyout\r\n\r\n<img width=\"1458\" alt=\"Screenshot 2024-10-24 at 19
54
36\"\r\nsrc=\"https://github.com/user-attachments/assets/7d4468f9-fada-4416-9480-99bfca3de220\">\r\n\r\n<img
width=\"615\" alt=\"Screenshot 2024-10-24 at 19 54
52\"\r\nsrc=\"https://github.com/user-attachments/assets/fd9bbe80-0a3c-40b8-909a-93f8082e69eb\">\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"a1d755a675b05269f167d160f4c0c28a83d5e4d5"}},"sourceBranch":"main","suggestedTargetBranches":["8.16"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/197722","number":197722,"mergeCommit":{"message":"[Security
GenAI] When indices referenced in KB index entries are deleted from
OUTSIDE the AI Assistant KB UI, there is not indication to the user
(#197156) (#197722)\n\n## Summary\r\n\r\nBug
https://github.com/elastic/kibana/issues/197156\r\n\r\nThis is a UI part
of the bug that warns a user about missing indices\r\nused in knowledge
base entries.\r\n\r\n### To test\r\n\r\n1. Add an index entry that uses
existing index\r\n2. Remove that index\r\n3. Go back to knowledge base
entries page\r\n4. You should see warning icon next to the name of the
index entry which\r\nuses removed index. Also, when you edit that entry
you will see `Index\r\ndoesn't exist` error next to the `Index` field in
the flyout\r\n\r\n<img width=\"1458\" alt=\"Screenshot 2024-10-24 at 19
54
36\"\r\nsrc=\"https://github.com/user-attachments/assets/7d4468f9-fada-4416-9480-99bfca3de220\">\r\n\r\n<img
width=\"615\" alt=\"Screenshot 2024-10-24 at 19 54
52\"\r\nsrc=\"https://github.com/user-attachments/assets/fd9bbe80-0a3c-40b8-909a-93f8082e69eb\">\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"a1d755a675b05269f167d160f4c0c28a83d5e4d5"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Ievgen Sorokopud <[email protected]>
  • Loading branch information
kibanamachine and e40pud authored Oct 25, 2024
1 parent 837bfe9 commit da5e2cd
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const useInlineActions = <T extends { isDefault?: boolean | undefined }>(
actions: [
{
name: i18n.EDIT_BUTTON,
'data-test-subj': 'edit-button',
description: i18n.EDIT_BUTTON,
icon: 'pencil',
type: 'icon',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const mockDataViews = {
{ name: 'field-2', esTypes: ['text'] },
{ name: 'field-3', esTypes: ['semantic_text'] },
]),
getExistingIndices: jest.fn().mockResolvedValue(['index-2']),
} as unknown as DataViewsContract;
const queryClient = new QueryClient();
const wrapper = (props: { children: React.ReactNode }) => (
Expand All @@ -65,7 +66,22 @@ const wrapper = (props: { children: React.ReactNode }) => (
describe('KnowledgeBaseSettingsManagement', () => {
const mockData = [
{ id: '1', name: 'Test Entry 1', type: 'document', kbResource: 'user', users: [{ id: 'hi' }] },
{ id: '2', name: 'Test Entry 2', type: 'index', kbResource: 'global', users: [] },
{
id: '2',
name: 'Test Entry 2',
type: 'index',
kbResource: 'global',
users: [],
index: 'missing-index',
},
{
id: '3',
name: 'Test Entry 3',
type: 'index',
kbResource: 'private',
users: [{ id: 'fake-user' }],
index: 'index-2',
},
];

beforeEach(() => {
Expand Down Expand Up @@ -241,4 +257,24 @@ describe('KnowledgeBaseSettingsManagement', () => {
});
expect(screen.queryByTestId('delete-entry-confirmation')).not.toBeInTheDocument();
});

it('shows warning icon for index entries with missing indices', async () => {
render(<KnowledgeBaseSettingsManagement dataViews={mockDataViews} />, {
wrapper,
});

await waitFor(() => expect(screen.getByTestId('missing-index-icon')).toBeInTheDocument());

expect(screen.getAllByTestId('missing-index-icon').length).toEqual(1);

fireEvent.mouseOver(screen.getByTestId('missing-index-icon'));

await waitFor(() => screen.getByTestId('missing-index-tooltip'));

expect(
screen.getByText(
'The index assigned to this knowledge base entry is unavailable. Check the permissions on the configured index, or that the index has not been deleted. You can update the index to be used for this knowledge entry, or delete the entry entirely.'
)
).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from '@kbn/elastic-assistant-common';
import { css } from '@emotion/react';
import { DataViewsContract } from '@kbn/data-views-plugin/public';
import useAsync from 'react-use/lib/useAsync';
import { KnowledgeBaseTour } from '../../tour/knowledge_base';
import { AlertsSettingsManagement } from '../../assistant/settings/alerts_settings/alerts_settings_management';
import { useKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_knowledge_base_entries';
Expand Down Expand Up @@ -173,10 +174,22 @@ export const KnowledgeBaseSettingsManagement: React.FC<Params> = React.memo(({ d
toasts,
enabled: enableKnowledgeBaseByDefault,
});

const { value: existingIndices } = useAsync(() => {
const indices: string[] = [];
entries.data.forEach((entry) => {
if (entry.type === 'index') {
indices.push(entry.index);
}
});
return dataViews.getExistingIndices(indices);
}, [entries.data]);

const { getColumns } = useKnowledgeBaseTable();
const columns = useMemo(
() =>
getColumns({
existingIndices,
isDeleteEnabled: (entry: KnowledgeBaseEntryResponse) => {
return (
!isSystemEntry(entry) && (isGlobalEntry(entry) ? hasManageGlobalKnowledgeBase : true)
Expand All @@ -197,7 +210,7 @@ export const KnowledgeBaseSettingsManagement: React.FC<Params> = React.memo(({ d
openFlyout();
},
}),
[entries.data, getColumns, hasManageGlobalKnowledgeBase, openFlyout]
[entries.data, existingIndices, getColumns, hasManageGlobalKnowledgeBase, openFlyout]
);

// Refresh button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('IndexEntryEditor', () => {
{ name: 'field-2', esTypes: ['text'] },
{ name: 'field-3', esTypes: ['semantic_text'] },
]),
getExistingIndices: jest.fn().mockResolvedValue(['index-1']),
} as unknown as DataViewsContract;

const defaultProps = {
Expand Down Expand Up @@ -147,4 +148,20 @@ describe('IndexEntryEditor', () => {
expect(getByRole('combobox', { name: i18n.ENTRY_FIELD_PLACEHOLDER })).toBeDisabled();
});
});

it('fetches index options and updates on selection 2', async () => {
(mockDataViews.getExistingIndices as jest.Mock).mockResolvedValue([]);
const { getByText } = render(
<IndexEntryEditor
{...defaultProps}
entry={{ ...defaultProps.entry, index: 'missing-index' }}
/>
);

await waitFor(() => {
expect(mockDataViews.getExistingIndices).toHaveBeenCalled();
});

expect(getByText("Index doesn't exist")).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ export const IndexEntryEditor: React.FC<Props> = React.memo(
}));
}, [dataViews]);

const { value: isMissingIndex } = useAsync(async () => {
if (!entry?.index?.length) return false;

return !(await dataViews.getExistingIndices([entry.index])).length;
}, [entry?.index]);

const indexFields = useAsync(
async () =>
dataViews.getFieldsForWildcard({
Expand Down Expand Up @@ -251,11 +257,17 @@ export const IndexEntryEditor: React.FC<Props> = React.memo(
fullWidth
/>
</EuiFormRow>
<EuiFormRow label={i18n.ENTRY_INDEX_NAME_INPUT_LABEL} fullWidth>
<EuiFormRow
label={i18n.ENTRY_INDEX_NAME_INPUT_LABEL}
fullWidth
isInvalid={isMissingIndex}
error={isMissingIndex && <>{i18n.MISSING_INDEX_ERROR}</>}
>
<EuiComboBox
data-test-subj="index-combobox"
aria-label={i18n.ENTRY_INDEX_NAME_INPUT_LABEL}
isClearable={true}
isInvalid={isMissingIndex}
singleSelection={{ asPlainText: true }}
onCreateOption={onCreateIndexOption}
fullWidth
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,3 +335,18 @@ export const PRIVATE = i18n.translate(
defaultMessage: 'Private',
}
);

export const MISSING_INDEX_ERROR = i18n.translate(
'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.missingIndexError',
{
defaultMessage: `Index doesn't exist`,
}
);

export const MISSING_INDEX_TOOLTIP_CONTENT = i18n.translate(
'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.missingIndexTootipContent',
{
defaultMessage:
'The index assigned to this knowledge base entry is unavailable. Check the permissions on the configured index, or that the index has not been deleted. You can update the index to be used for this knowledge entry, or delete the entry entirely.',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
* 2.0.
*/

import { EuiAvatar, EuiBadge, EuiBasicTableColumn, EuiIcon, EuiText } from '@elastic/eui';
import {
EuiAvatar,
EuiBadge,
EuiBasicTableColumn,
EuiIcon,
EuiText,
EuiToolTip,
} from '@elastic/eui';
import { css } from '@emotion/react';
import React, { useCallback, useMemo } from 'react';
import { FormattedDate } from '@kbn/i18n-react';
Expand Down Expand Up @@ -77,6 +84,39 @@ const AuthorColumn = ({ entry }: { entry: KnowledgeBaseEntryResponse }) => {
);
};

const NameColumn = ({
entry,
existingIndices,
}: {
entry: KnowledgeBaseEntryResponse;
existingIndices?: string[];
}) => {
let showMissingIndexWarning = false;
if (existingIndices && entry.type === 'index') {
showMissingIndexWarning = !existingIndices.includes(entry.index);
}
return (
<>
<EuiText size={'s'}>{entry.name}</EuiText>
{showMissingIndexWarning && (
<EuiToolTip
data-test-subj="missing-index-tooltip"
content={i18n.MISSING_INDEX_TOOLTIP_CONTENT}
>
<EuiIcon
data-test-subj="missing-index-icon"
type="warning"
color="danger"
css={css`
margin-left: 10px;
`}
/>
</EuiToolTip>
)}
</>
);
};

export const useKnowledgeBaseTable = () => {
const getActions = useInlineActions<KnowledgeBaseEntryResponse & { isDefault?: undefined }>();

Expand All @@ -97,11 +137,13 @@ export const useKnowledgeBaseTable = () => {

const getColumns = useCallback(
({
existingIndices,
isDeleteEnabled,
isEditEnabled,
onDeleteActionClicked,
onEditActionClicked,
}: {
existingIndices?: string[];
isDeleteEnabled: (entry: KnowledgeBaseEntryResponse) => boolean;
isEditEnabled: (entry: KnowledgeBaseEntryResponse) => boolean;
onDeleteActionClicked: (entry: KnowledgeBaseEntryResponse) => void;
Expand All @@ -115,7 +157,9 @@ export const useKnowledgeBaseTable = () => {
},
{
name: i18n.COLUMN_NAME,
render: ({ name }: KnowledgeBaseEntryResponse) => name,
render: (entry: KnowledgeBaseEntryResponse) => (
<NameColumn entry={entry} existingIndices={existingIndices} />
),
sortable: ({ name }: KnowledgeBaseEntryResponse) => name,
width: '30%',
},
Expand Down

0 comments on commit da5e2cd

Please sign in to comment.