Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ import {
EuiFlyoutFooter,
EuiTextColor,
EuiFlyout,
EuiToolTip,
} from '@elastic/eui';
import type {
BulkErrorSchema,
ImportExceptionsResponseSchema,
} from '@kbn/securitysolution-io-ts-list-types';
import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants';
import type { HttpSetup } from '@kbn/core-http-browser';
import type { ToastInput, Toast, ErrorToastOptions } from '@kbn/core-notifications-browser';

Expand Down Expand Up @@ -58,6 +60,7 @@ export const ImportExceptionListFlyout = React.memo(
const [overwrite, setOverwrite] = useState(false);
const [asNewList, setAsNewList] = useState(false);
const [alreadyExistingItem, setAlreadyExistingItem] = useState(false);
const [endpointListImporting, setEndpointListImporting] = useState(false);

const resetForm = useCallback(() => {
if (filePickerRef.current?.fileInput) {
Expand All @@ -66,6 +69,7 @@ export const ImportExceptionListFlyout = React.memo(
}
setFiles(null);
setAlreadyExistingItem(false);
setEndpointListImporting(false);
setAsNewList(false);
setOverwrite(false);
}, []);
Expand Down Expand Up @@ -128,6 +132,13 @@ export const ImportExceptionListFlyout = React.memo(
importExceptionListState?.result?.errors.forEach((err) => {
if (err.error.message.includes('already exists')) {
setAlreadyExistingItem(true);
if (
err.error.message.includes(
`Found that list_id: "${ENDPOINT_LIST_ID}" already exists`
)
) {
setEndpointListImporting(true);
}
}
errorsToDisplay.push(err);
});
Expand Down Expand Up @@ -190,16 +201,22 @@ export const ImportExceptionListFlyout = React.memo(
setAsNewList(false);
}}
/>
<EuiCheckbox
id={'createNewListCheckbox'}
label={i18n.IMPORT_EXCEPTION_LIST_AS_NEW_LIST}
data-test-subj="importExceptionListCreateNewCheckbox"
checked={asNewList}
onChange={(e) => {
setAsNewList(!asNewList);
setOverwrite(false);
}}
/>
<EuiToolTip
position="bottom"
content={endpointListImporting ? i18n.IMPORT_EXCEPTION_ENDPOINT_LIST_WARNING : ''}
>
<EuiCheckbox
id={'createNewListCheckbox'}
label={i18n.IMPORT_EXCEPTION_LIST_AS_NEW_LIST}
data-test-subj="importExceptionListCreateNewCheckbox"
checked={asNewList}
disabled={endpointListImporting}
onChange={(e) => {
setAsNewList(!asNewList);
setOverwrite(false);
}}
/>
</EuiToolTip>
</>
)}
</EuiFlyoutBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const importExceptionList = async ({
formData.append('file', file as Blob);

const res = await http.post<ImportExceptionsResponseSchema>(`${EXCEPTION_LIST_URL}/_import`, {
version: '2023-10-31',
body: formData,
query: { overwrite, overwrite_exceptions: overwriteExceptions, as_new_list: asNewList },
headers: { 'Content-Type': undefined },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,13 @@ export const IMPORT_EXCEPTION_LIST_AS_NEW_LIST = i18n.translate(
}
);

export const IMPORT_EXCEPTION_ENDPOINT_LIST_WARNING = i18n.translate(
'xpack.securitySolution.exceptionsTable.importExceptionEndpointListWarning',
{
defaultMessage: 'Multiple exception lists for Endpoint Security are not allowed.',
}
);

export const READ_ONLY_BADGE_TOOLTIP = i18n.translate(
'xpack.securitySolution.exceptions.badge.readOnly.tooltip',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,68 +16,92 @@ import {
importExceptionListWithSelectingCreateNewOption,
validateImportExceptionListWentSuccessfully,
validateImportExceptionListFailedBecauseExistingListFound,
validateImportExceptionListCreateNewOptionDisabled,
} from '../../../../../../tasks/exceptions_table';
import { login } from '../../../../../../tasks/login';
import { visit } from '../../../../../../tasks/navigation';
import { EXCEPTIONS_URL } from '../../../../../../urls/navigation';

describe('Import Lists', { tags: ['@ess', '@serverless', '@skipInServerless'] }, () => {
const LIST_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_exception_list.ndjson';
const ENDPOINT_LIST_TO_IMPORT_FILENAME = 'cypress/fixtures/endpoint_exception_list.ndjson';
beforeEach(() => {
login();
visit(EXCEPTIONS_URL);
waitForExceptionsTableToBeLoaded();
cy.intercept(/(\/api\/exception_lists\/_import)/).as('import');
});

it('Should import exception list successfully if the list does not exist', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);
describe('Exception Lists', () => {
it('Should import exception list successfully if the list does not exist', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);

validateImportExceptionListWentSuccessfully();
validateImportExceptionListWentSuccessfully();

cy.get(IMPORT_SHARED_EXCEPTION_LISTS_CLOSE_BTN).click();
cy.get(IMPORT_SHARED_EXCEPTION_LISTS_CLOSE_BTN).click();

// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
});
// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
});

it('Should not import exception list if it exists', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);
it('Should not import exception list if it exists', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);

validateImportExceptionListFailedBecauseExistingListFound();
validateImportExceptionListFailedBecauseExistingListFound();

// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
});
// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
});

it('Should import exception list if it exists but the user selected overwrite checkbox', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);

validateImportExceptionListFailedBecauseExistingListFound();

// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');

importExceptionListWithSelectingOverwriteExistingOption();

validateImportExceptionListWentSuccessfully();

it('Should import exception list if it exists but the user selected overwrite checkbox', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);
// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
});

validateImportExceptionListFailedBecauseExistingListFound();
it('Should import exception list if it exists but the user selected create new checkbox', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);

// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
validateImportExceptionListFailedBecauseExistingListFound();

importExceptionListWithSelectingOverwriteExistingOption();
// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');

validateImportExceptionListWentSuccessfully();
importExceptionListWithSelectingCreateNewOption();

// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
validateImportExceptionListWentSuccessfully();
// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2');
});
});

it('Should import exception list if it exists but the user selected create new checkbox', () => {
importExceptionLists(LIST_TO_IMPORT_FILENAME);
describe('Endpoint Security Exception List', () => {
before(() => {
login();
visit(EXCEPTIONS_URL);

validateImportExceptionListFailedBecauseExistingListFound();
// Make sure we have Endpoint Security Exception List
importExceptionLists(ENDPOINT_LIST_TO_IMPORT_FILENAME);
});

// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '1');
it('Should not allow to import or create a second Endpoint Security Exception List', () => {
// Try to import another Endpoint Security Exception List
importExceptionLists(ENDPOINT_LIST_TO_IMPORT_FILENAME);

importExceptionListWithSelectingCreateNewOption();
validateImportExceptionListFailedBecauseExistingListFound();

validateImportExceptionListWentSuccessfully();
// Validate table items count
cy.contains(EXCEPTIONS_TABLE_SHOWING_LISTS, '2');
// Validate that "Create new list" option is disabled
validateImportExceptionListCreateNewOptionDisabled();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"_version":"WzUxOTM4LDE1XQ==","created_at":"2024-03-18T14:11:18.125Z","created_by":"kibana","description":"Endpoint Security Exception List","id":"endpoint_list","immutable":false,"list_id":"endpoint_list","name":"Endpoint Security Exception List","namespace_type":"agnostic","os_types":[],"tags":[],"tie_breaker_id":"04deda68-7162-4349-8e34-c315bb9f896f","type":"endpoint","updated_at":"2024-03-19T12:57:31.911Z","updated_by":"elastic","version":1}
{"exported_exception_list_count":1,"exported_exception_list_item_count":0,"missing_exception_list_item_count":0,"missing_exception_list_items":[],"missing_exception_lists":[],"missing_exception_lists_count":0}
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,7 @@ export const validateImportExceptionListFailedBecauseExistingListFound = () => {
cy.get(TOASTER_BODY).should('contain', 'Found that list_id');
});
};

export const validateImportExceptionListCreateNewOptionDisabled = () => {
cy.get(IMPORT_SHARED_EXCEPTION_LISTS_OVERWRITE_CREATE_NEW_CHECKBOX).should('be.disabled');
};