[SIEM][Detection Engine][Lists] Removes feature flag for lists

## Summary

* Removes the feature flag and turns on lists by default
* Applies to both exception lists and value lists
* Removes all scary messages about having it enabled
* Updates the unit tests to work with it on 

- [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
This commit is contained in:
Frank Hassanabad 2020-07-07 19:13:53 -06:00 committed by GitHub
parent 030daf84c9
commit 531cac058f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 59 additions and 475 deletions

View file

@ -32,13 +32,11 @@ source `$HOME/.zshrc` or `${HOME}.bashrc` to ensure variables are set:
source ~/.zshrc
```
Open your `kibana.dev.yml` file and add these lines:
Open your `kibana.dev.yml` file and add these lines with your name:
```sh
# Enable lists feature
xpack.lists.enabled: true
xpack.lists.listIndex: '.lists-frank'
xpack.lists.listItemIndex: '.items-frank'
xpack.lists.listIndex: '.lists-your-name'
xpack.lists.listItemIndex: '.items-your-name'
```
Restart Kibana and ensure that you are using `--no-base-path` as changing the base path is a feature but will

View file

@ -7,7 +7,7 @@
import { TypeOf, schema } from '@kbn/config-schema';
export const ConfigSchema = schema.object({
enabled: schema.boolean({ defaultValue: false }),
enabled: schema.boolean({ defaultValue: true }),
listIndex: schema.string({ defaultValue: '.lists' }),
listItemIndex: schema.string({ defaultValue: '.items' }),
});

View file

@ -40,10 +40,6 @@ export class ListPlugin
public async setup(core: CoreSetup, plugins: PluginsSetup): Promise<ListPluginSetup> {
const config = await createConfig$(this.initializerContext).pipe(first()).toPromise();
this.logger.error(
'You have activated the lists values feature flag which is NOT currently supported for Elastic Security! You should turn this feature flag off immediately by un-setting "xpack.lists.enabled: true" in kibana.yml and restarting Kibana'
);
this.spaces = plugins.spaces?.spacesService;
this.config = config;
this.security = plugins.security;

View file

@ -1,97 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import {
listsEnvFeatureFlagName,
hasListsFeature,
unSetFeatureFlagsForTestsOnly,
setFeatureFlagsForTestsOnly,
} from './feature_flags';
describe('feature_flags', () => {
beforeAll(() => {
delete process.env[listsEnvFeatureFlagName];
});
afterEach(() => {
delete process.env[listsEnvFeatureFlagName];
});
describe('hasListsFeature', () => {
test('hasListsFeature should return false if process.env is not set', () => {
expect(hasListsFeature()).toEqual(false);
});
test('hasListsFeature should return true if process.env is set to true', () => {
process.env[listsEnvFeatureFlagName] = 'true';
expect(hasListsFeature()).toEqual(true);
});
test('hasListsFeature should return false if process.env is set to false', () => {
process.env[listsEnvFeatureFlagName] = 'false';
expect(hasListsFeature()).toEqual(false);
});
test('hasListsFeature should return false if process.env is set to a non true value', () => {
process.env[listsEnvFeatureFlagName] = 'something else';
expect(hasListsFeature()).toEqual(false);
});
});
describe('setFeatureFlagsForTestsOnly', () => {
test('it can be called once and sets the environment variable for tests', () => {
setFeatureFlagsForTestsOnly();
expect(process.env[listsEnvFeatureFlagName]).toEqual('true');
unSetFeatureFlagsForTestsOnly(); // This is needed to not pollute other tests since this has to be paired
});
test('if it is called twice it throws an exception', () => {
setFeatureFlagsForTestsOnly();
expect(() => setFeatureFlagsForTestsOnly()).toThrow(
'In your tests you need to ensure in your afterEach/afterAll blocks you are calling unSetFeatureFlagsForTestsOnly'
);
unSetFeatureFlagsForTestsOnly(); // This is needed to not pollute other tests since this has to be paired
});
test('it can be called twice as long as unSetFeatureFlagsForTestsOnly is called in-between', () => {
setFeatureFlagsForTestsOnly();
unSetFeatureFlagsForTestsOnly();
setFeatureFlagsForTestsOnly();
expect(process.env[listsEnvFeatureFlagName]).toEqual('true');
unSetFeatureFlagsForTestsOnly(); // This is needed to not pollute other tests since this has to be paired
});
});
describe('unSetFeatureFlagsForTestsOnly', () => {
test('it can sets the value to undefined', () => {
setFeatureFlagsForTestsOnly();
unSetFeatureFlagsForTestsOnly();
expect(process.env[listsEnvFeatureFlagName]).toEqual(undefined);
});
test('it can not be be called before setFeatureFlagsForTestsOnly without throwing', () => {
expect(() => unSetFeatureFlagsForTestsOnly()).toThrow(
'In your tests you need to ensure in your beforeEach/beforeAll blocks you are calling setFeatureFlagsForTestsOnly'
);
});
test('if it is called twice it throws an exception', () => {
setFeatureFlagsForTestsOnly();
unSetFeatureFlagsForTestsOnly();
expect(() => unSetFeatureFlagsForTestsOnly()).toThrow(
'In your tests you need to ensure in your beforeEach/beforeAll blocks you are calling setFeatureFlagsForTestsOnly'
);
});
test('it can be called twice as long as setFeatureFlagsForTestsOnly is called in-between', () => {
setFeatureFlagsForTestsOnly();
unSetFeatureFlagsForTestsOnly();
setFeatureFlagsForTestsOnly();
unSetFeatureFlagsForTestsOnly();
expect(process.env[listsEnvFeatureFlagName]).toEqual(undefined);
});
});
});

View file

@ -1,49 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// TODO: (LIST-FEATURE) Delete this file once the lists features are within the product and in a particular version
// Very temporary file where we put our feature flags for detection lists.
// We need to use an environment variable and CANNOT use a kibana.dev.yml setting because some definitions
// of things are global in the modules are are initialized before the init of the server has a chance to start.
// Set this in your .bashrc/.zshrc to turn on lists feature, export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true
// NOTE: This feature is forwards and backwards compatible but forwards compatible is not guaranteed.
// Once you enable this and begin using it you might not be able to easily go back back.
// So it's best to not turn it on unless you are developing code.
export const listsEnvFeatureFlagName = 'ELASTIC_XPACK_SIEM_LISTS_FEATURE';
// This is for setFeatureFlagsForTestsOnly and unSetFeatureFlagsForTestsOnly only to use
let setFeatureFlagsForTestsOnlyCalled = false;
// Use this to detect if the lists feature is enabled or not
export const hasListsFeature = (): boolean => {
return process.env[listsEnvFeatureFlagName]?.trim().toLowerCase() === 'true';
};
// This is for tests only to use in your beforeAll() calls
export const setFeatureFlagsForTestsOnly = (): void => {
if (setFeatureFlagsForTestsOnlyCalled) {
throw new Error(
'In your tests you need to ensure in your afterEach/afterAll blocks you are calling unSetFeatureFlagsForTestsOnly'
);
} else {
setFeatureFlagsForTestsOnlyCalled = true;
process.env[listsEnvFeatureFlagName] = 'true';
}
};
// This is for tests only to use in your afterAll() calls
export const unSetFeatureFlagsForTestsOnly = (): void => {
if (!setFeatureFlagsForTestsOnlyCalled) {
throw new Error(
'In your tests you need to ensure in your beforeEach/beforeAll blocks you are calling setFeatureFlagsForTestsOnly'
);
} else {
delete process.env[listsEnvFeatureFlagName];
setFeatureFlagsForTestsOnlyCalled = false;
}
};

View file

@ -5,7 +5,6 @@
*/
import { getIndexExists } from './get_index_exists';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../feature_flags';
class StatusCode extends Error {
status: number = -1;
@ -16,14 +15,6 @@ class StatusCode extends Error {
}
describe('get_index_exists', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it should return a true if you have _shards', async () => {
const callWithRequest = jest.fn().mockResolvedValue({ _shards: { total: 1 } });
const indexExists = await getIndexExists(callWithRequest, 'some-index');

View file

@ -13,7 +13,6 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock } from '../__mocks__';
import { addPrepackedRulesRoute } from './add_prepackaged_rules_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { AddPrepackagedRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema';
jest.mock('../../rules/get_prepackaged_rules', () => {
@ -56,14 +55,6 @@ describe('add_prepackaged_rules_route', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -18,7 +18,6 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { createRulesBulkRoute } from './create_rules_bulk_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
@ -28,14 +27,6 @@ describe('create_rules_bulk', () => {
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.create>;
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -19,7 +19,6 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach
import { buildMlAuthz } from '../../../machine_learning/authz';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { createRulesRoute } from './create_rules_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { updateRulesNotifications } from '../../rules/update_rules_notifications';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
jest.mock('../../rules/update_rules_notifications');
@ -30,14 +29,6 @@ describe('create_rules', () => {
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.create>;
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -17,20 +17,11 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { deleteRulesBulkRoute } from './delete_rules_bulk_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('delete_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -15,20 +15,11 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { deleteRulesRoute } from './delete_rules_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('delete_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -13,20 +13,11 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { findRulesRoute } from './find_rules_route';
import { unSetFeatureFlagsForTestsOnly, setFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('find_rules', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -8,20 +8,11 @@ import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { getFindResultStatus, ruleStatusRequest } from '../__mocks__/request_responses';
import { serverMock, requestContextMock, requestMock } from '../__mocks__';
import { findRulesStatusesRoute } from './find_rules_status_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('find_statuses', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -13,7 +13,6 @@ import {
getNonEmptyIndex,
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock } from '../__mocks__';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
jest.mock('../../rules/get_prepackaged_rules', () => {
return {
@ -39,14 +38,6 @@ jest.mock('../../rules/get_prepackaged_rules', () => {
});
describe('get_prepackaged_rule_status_route', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();

View file

@ -19,7 +19,6 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach
import { buildMlAuthz } from '../../../machine_learning/authz';
import { importRulesRoute } from './import_rules_route';
import * as createRulesStreamFromNdJson from '../../rules/create_rules_stream_from_ndjson';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import {
getImportRulesWithIdSchemaMock,
ruleIdsToNdJsonString,
@ -29,14 +28,6 @@ import {
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
describe('import_rules_route', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
let config: ReturnType<typeof createMockConfig>;
let server: ReturnType<typeof serverMock.create>;
let request: ReturnType<typeof requestMock.create>;

View file

@ -16,7 +16,6 @@ import {
} from '../__mocks__/request_responses';
import { serverMock, requestContextMock, requestMock } from '../__mocks__';
import { patchRulesBulkRoute } from './patch_rules_bulk_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
@ -26,14 +25,6 @@ describe('patch_rules_bulk', () => {
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.create>;
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -18,7 +18,6 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { patchRulesRoute } from './patch_rules_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
@ -28,14 +27,6 @@ describe('patch_rules', () => {
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.create>;
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -14,20 +14,11 @@ import {
getFindResultStatusEmpty,
} from '../__mocks__/request_responses';
import { requestMock, requestContextMock, serverMock } from '../__mocks__';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('read_signals', () => {
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -18,7 +18,6 @@ import {
import { serverMock, requestContextMock, requestMock } from '../__mocks__';
import { updateRulesBulkRoute } from './update_rules_bulk_route';
import { BulkError } from '../utils';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create());
@ -28,14 +27,6 @@ describe('update_rules_bulk', () => {
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.create>;
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -17,7 +17,6 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { updateRulesNotifications } from '../../rules/update_rules_notifications';
import { updateRulesRoute } from './update_rules_route';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
@ -30,14 +29,6 @@ describe('update_rules', () => {
let { clients, context } = requestContextMock.createTools();
let ml: ReturnType<typeof mlServicesMock.create>;
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
server = serverMock.create();
({ clients, context } = requestContextMock.createTools());

View file

@ -27,7 +27,6 @@ import { PartialAlert } from '../../../../../../alerts/server';
import { SanitizedAlert } from '../../../../../../alerts/server/types';
import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson';
import { RuleAlertType } from '../../rules/types';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { CreateRulesBulkSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/create_rules_bulk_schema';
import { ImportRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/import_rules_schema';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/create_rules_schema.mock';
@ -35,14 +34,6 @@ import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine
type PromiseFromStreams = ImportRulesSchemaDecoded | Error;
describe('utils', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
describe('transformAlertToRule', () => {
test('should work with a full data set', () => {
const fullRule = getResult();

View file

@ -12,7 +12,6 @@ import {
import { getResult } from '../__mocks__/request_responses';
import { FindResult } from '../../../../../../alerts/server';
import { BulkError } from '../utils';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema';
import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock';
@ -84,14 +83,6 @@ export const ruleOutput: RulesSchema = {
};
describe('validate', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
describe('transformValidate', () => {
test('it should do a validation correctly of a partial alert', () => {
const ruleAlert = getResult();

View file

@ -15,17 +15,8 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { setSignalsStatusRoute } from './open_close_signals_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('set signal status', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();

View file

@ -15,17 +15,8 @@ import {
} from '../__mocks__/request_responses';
import { requestContextMock, serverMock, requestMock } from '../__mocks__';
import { querySignalsRoute } from './query_signals_route';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../feature_flags';
describe('query for signal', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
let server: ReturnType<typeof serverMock.create>;
let { clients, context } = requestContextMock.createTools();

View file

@ -21,17 +21,8 @@ import {
SiemResponseFactory,
} from './utils';
import { responseMock } from './__mocks__';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../feature_flags';
describe('utils', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
describe('transformError', () => {
test('returns transformed output error from boom object with a 500 and payload of internal server error', () => {
const boom = new Boom('some boom message');

View file

@ -9,7 +9,6 @@ import { Alert } from '../../../../../alerts/common';
import { APP_ID, SIGNALS_ID } from '../../../../common/constants';
import { CreateRulesOptions } from './types';
import { addTags } from './add_tags';
import { hasListsFeature } from '../feature_flags';
export const createRules = async ({
alertsClient,
@ -52,8 +51,6 @@ export const createRules = async ({
exceptionsList,
actions,
}: CreateRulesOptions): Promise<Alert> => {
// TODO: Remove this and use regular exceptions_list once the feature is stable for a release
const exceptionsListParam = hasListsFeature() ? { exceptionsList } : {};
return alertsClient.create({
data: {
name,
@ -93,7 +90,7 @@ export const createRules = async ({
references,
note,
version,
...exceptionsListParam,
exceptionsList,
},
schedule: { interval },
enabled,

View file

@ -11,18 +11,9 @@ import {
} from '../routes/__mocks__/request_responses';
import { alertsClientMock } from '../../../../../alerts/server/mocks';
import { getExportAll } from './get_export_all';
import { unSetFeatureFlagsForTestsOnly, setFeatureFlagsForTestsOnly } from '../feature_flags';
import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock';
describe('getExportAll', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
test('it exports everything from the alerts client', async () => {
const alertsClient = alertsClientMock.create();
alertsClient.get.mockResolvedValue(getResult());

View file

@ -12,18 +12,9 @@ import {
} from '../routes/__mocks__/request_responses';
import * as readRules from './read_rules';
import { alertsClientMock } from '../../../../../alerts/server/mocks';
import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../feature_flags';
import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock';
describe('get_export_by_object_ids', () => {
beforeAll(() => {
setFeatureFlagsForTestsOnly();
});
afterAll(() => {
unSetFeatureFlagsForTestsOnly();
});
beforeEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();

View file

@ -10,7 +10,6 @@ import { readRules } from './read_rules';
import { UpdateRulesOptions } from './types';
import { addTags } from './add_tags';
import { calculateVersion } from './utils';
import { hasListsFeature } from '../feature_flags';
import { ruleStatusSavedObjectsClientFactory } from '../signals/rule_status_saved_objects_client';
export const updateRules = async ({
@ -97,9 +96,6 @@ export const updateRules = async ({
exceptionsList,
});
// TODO: Remove this and use regular exceptions_list once the feature is stable for a release
const exceptionsListParam = hasListsFeature() ? { exceptionsList } : {};
const update = await alertsClient.update({
id: rule.id,
data: {
@ -141,7 +137,7 @@ export const updateRules = async ({
version: calculatedVersion,
anomalyThreshold,
machineLearningJobId,
...exceptionsListParam,
exceptionsList,
},
},
});

View file

@ -15,8 +15,6 @@ import { ExceptionListClient } from '../../../../../lists/server';
import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock';
import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
import * as featureFlags from '../feature_flags';
import {
generateId,
parseInterval,
@ -561,8 +559,6 @@ describe('utils', () => {
});
test('it successfully returns list and exceptions list client', async () => {
jest.spyOn(featureFlags, 'hasListsFeature').mockReturnValue(true);
const { listClient, exceptionsClient } = await getListsClient({
services: alertServices,
savedObjectClient: alertServices.savedObjectsClient,
@ -575,23 +571,7 @@ describe('utils', () => {
expect(exceptionsClient).toBeDefined();
});
test('it returns list and exceptions client of "undefined" if lists feature flag is off', async () => {
jest.spyOn(featureFlags, 'hasListsFeature').mockReturnValue(false);
const listsClient = await getListsClient({
services: alertServices,
savedObjectClient: alertServices.savedObjectsClient,
updatedByUser: 'some_user',
spaceId: '',
lists: listMock.createSetup(),
});
expect(listsClient).toEqual({ listClient: undefined, exceptionsClient: undefined });
});
test('it throws if "lists" is undefined', async () => {
jest.spyOn(featureFlags, 'hasListsFeature').mockReturnValue(true);
await expect(() =>
getListsClient({
services: alertServices,
@ -737,10 +717,6 @@ describe('utils', () => {
});
describe('#getExceptions', () => {
beforeEach(() => {
jest.spyOn(featureFlags, 'hasListsFeature').mockReturnValue(true);
});
test('it successfully returns array of exception list items', async () => {
const client = listMock.getExceptionListClient();
const exceptions = await getExceptions({
@ -764,17 +740,6 @@ describe('utils', () => {
]);
});
test('it returns empty array if lists feature flag not turned on', async () => {
jest.spyOn(featureFlags, 'hasListsFeature').mockReturnValue(false);
const exceptions = await getExceptions({
client: listMock.getExceptionListClient(),
lists: getListArrayMock(),
});
expect(exceptions).toEqual([]);
});
test('it throws if "client" is undefined', async () => {
await expect(() =>
getExceptions({

View file

@ -12,7 +12,6 @@ import { AlertServices, parseDuration } from '../../../../../alerts/server';
import { ExceptionListClient, ListClient, ListPluginSetup } from '../../../../../lists/server';
import { EntriesArray, ExceptionListItemSchema } from '../../../../../lists/common/schemas';
import { ListArrayOrUndefined } from '../../../../common/detection_engine/schemas/types/lists';
import { hasListsFeature } from '../feature_flags';
import { BulkResponse, BulkResponseErrorAggregation } from './types';
import { BuildRuleMessage } from './rule_messages';
@ -37,26 +36,21 @@ export const getListsClient = async ({
listClient: ListClient | undefined;
exceptionsClient: ExceptionListClient | undefined;
}> => {
// TODO Remove check once feature is no longer behind flag
if (hasListsFeature()) {
if (lists == null) {
throw new Error('lists plugin unavailable during rule execution');
}
const listClient = await lists.getListClient(
services.callCluster,
spaceId,
updatedByUser ?? 'elastic'
);
const exceptionsClient = await lists.getExceptionListClient(
savedObjectClient,
updatedByUser ?? 'elastic'
);
return { listClient, exceptionsClient };
} else {
return { listClient: undefined, exceptionsClient: undefined };
if (lists == null) {
throw new Error('lists plugin unavailable during rule execution');
}
const listClient = await lists.getListClient(
services.callCluster,
spaceId,
updatedByUser ?? 'elastic'
);
const exceptionsClient = await lists.getExceptionListClient(
savedObjectClient,
updatedByUser ?? 'elastic'
);
return { listClient, exceptionsClient };
};
export const hasLargeValueList = (entries: EntriesArray): boolean => {
@ -71,54 +65,49 @@ export const getExceptions = async ({
client: ExceptionListClient | undefined;
lists: ListArrayOrUndefined;
}): Promise<ExceptionListItemSchema[] | undefined> => {
// TODO Remove check once feature is no longer behind flag
if (hasListsFeature()) {
if (client == null) {
throw new Error('lists plugin unavailable during rule execution');
}
if (client == null) {
throw new Error('lists plugin unavailable during rule execution');
}
if (lists != null) {
try {
// Gather all exception items of all exception lists linked to rule
const exceptions = await Promise.all(
lists
.map(async (list) => {
const { id, namespace_type: namespaceType } = list;
try {
// TODO update once exceptions client `findExceptionListItem`
// accepts an array of list ids
const foundList = await client.getExceptionList({
id,
if (lists != null) {
try {
// Gather all exception items of all exception lists linked to rule
const exceptions = await Promise.all(
lists
.map(async (list) => {
const { id, namespace_type: namespaceType } = list;
try {
// TODO update once exceptions client `findExceptionListItem`
// accepts an array of list ids
const foundList = await client.getExceptionList({
id,
namespaceType,
listId: undefined,
});
if (foundList == null) {
return [];
} else {
const items = await client.findExceptionListItem({
listId: foundList.list_id,
namespaceType,
listId: undefined,
page: 1,
perPage: 5000,
filter: undefined,
sortOrder: undefined,
sortField: undefined,
});
if (foundList == null) {
return [];
} else {
const items = await client.findExceptionListItem({
listId: foundList.list_id,
namespaceType,
page: 1,
perPage: 5000,
filter: undefined,
sortOrder: undefined,
sortField: undefined,
});
return items != null ? items.data : [];
}
} catch {
throw new Error('unable to fetch exception list items');
return items != null ? items.data : [];
}
})
.flat()
);
return exceptions.flat();
} catch {
throw new Error('unable to fetch exception list items');
}
} else {
return [];
} catch {
throw new Error('unable to fetch exception list items');
}
})
.flat()
);
return exceptions.flat();
} catch {
throw new Error('unable to fetch exception list items');
}
} else {
return [];

View file

@ -33,7 +33,6 @@ import { isAlertExecutor } from './lib/detection_engine/signals/types';
import { signalRulesAlertType } from './lib/detection_engine/signals/signal_rule_alert_type';
import { rulesNotificationAlertType } from './lib/detection_engine/notifications/rules_notification_alert_type';
import { isNotificationAlertExecutor } from './lib/detection_engine/notifications/types';
import { hasListsFeature, listsEnvFeatureFlagName } from './lib/detection_engine/feature_flags';
import { ManifestTask, ExceptionsCache } from './endpoint/lib/artifacts';
import { initSavedObjects, savedObjectTypes } from './saved_objects';
import { AppClientFactory } from './client';
@ -106,13 +105,6 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
public async setup(core: CoreSetup<StartPlugins, PluginStart>, plugins: SetupPlugins) {
this.logger.debug('plugin setup');
if (hasListsFeature()) {
// TODO: Remove this once we have the lists feature supported
this.logger.error(
`You have activated the lists feature flag which is NOT currently supported for Security Solution! You should turn this feature flag off immediately by un-setting the environment variable: ${listsEnvFeatureFlagName} and restarting Kibana`
);
}
const config = await this.config$.pipe(first()).toPromise();
initSavedObjects(core.savedObjects);

View file

@ -8,7 +8,6 @@ import path from 'path';
import { CA_CERT_PATH } from '@kbn/dev-utils';
import { FtrConfigProviderContext } from '@kbn/test/types/ftr';
import { services } from './services';
import { listsEnvFeatureFlagName } from '../../../plugins/security_solution/server/lib/detection_engine/feature_flags';
interface CreateTestConfigOptions {
license: string;
@ -32,10 +31,6 @@ const enabledActionTypes = [
'test.rate-limit',
];
// Temporary feature flag for the lists feature
// TODO: Remove this once lists land in a Kibana version
process.env[listsEnvFeatureFlagName] = 'true';
// eslint-disable-next-line import/no-default-export
export function createTestConfig(name: string, options: CreateTestConfigOptions) {
const { license = 'trial', disabledPlugins = [], ssl = false } = options;