mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Setup E2E against Serverless ES, Kibana, Fleet server standalone and Elastic endpoint agent in VM (#167720)
## Summary Run Defend Workflows Cypress E2E against Serverless stack, similar to https://github.com/elastic/kibana/pull/165415 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Gloria Hornero <gloria.hornero@elastic.co>
This commit is contained in:
parent
7e24f2512d
commit
5fb9a3889e
30 changed files with 281 additions and 281 deletions
|
@ -27,8 +27,7 @@ disabled:
|
|||
- x-pack/test/functional_enterprise_search/cypress.config.ts
|
||||
- x-pack/test/defend_workflows_cypress/cli_config.ts
|
||||
- x-pack/test/defend_workflows_cypress/config.ts
|
||||
- x-pack/test/defend_workflows_cypress/endpoint_config.ts
|
||||
- x-pack/test/defend_workflows_cypress/endpoint_serverless_config.ts
|
||||
- x-pack/test/defend_workflows_cypress/serverless_config.ts
|
||||
- x-pack/plugins/observability_onboarding/e2e/ftr_config_open.ts
|
||||
- x-pack/plugins/observability_onboarding/e2e/ftr_config_runner.ts
|
||||
- x-pack/plugins/observability_onboarding/e2e/ftr_config.ts
|
||||
|
|
|
@ -35,6 +35,7 @@ export const serverless: Command = {
|
|||
--basePath Path to the directory where the ES cluster will store data
|
||||
--clean Remove existing file system object store before running
|
||||
--kill Kill running ES serverless nodes if detected on startup
|
||||
--host Publish ES docker container on additional host IP
|
||||
--port The port to bind to on 127.0.0.1 [default: ${DEFAULT_PORT}]
|
||||
--ssl Enable HTTP SSL on the ES cluster
|
||||
--skipTeardown If this process exits, leave the ES cluster running in the background
|
||||
|
@ -72,7 +73,7 @@ export const serverless: Command = {
|
|||
files: 'F',
|
||||
},
|
||||
|
||||
string: ['tag', 'image', 'basePath', 'resources'],
|
||||
string: ['tag', 'image', 'basePath', 'resources', 'host'],
|
||||
boolean: ['clean', 'ssl', 'kill', 'background', 'skipTeardown', 'waitForReady'],
|
||||
|
||||
default: defaults,
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
teardownServerlessClusterSync,
|
||||
verifyDockerInstalled,
|
||||
getESp12Volume,
|
||||
ServerlessOptions,
|
||||
} from './docker';
|
||||
import { ToolingLog, ToolingLogCollectingWriter } from '@kbn/tooling-log';
|
||||
import { ES_P12_PATH } from '@kbn/dev-utils';
|
||||
|
@ -155,6 +156,19 @@ describe('resolvePort()', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
test('should return default port when custom host passed in options', () => {
|
||||
const port = resolvePort({ host: '192.168.25.1' } as ServerlessOptions);
|
||||
|
||||
expect(port).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"-p",
|
||||
"127.0.0.1:9200:9200",
|
||||
"-p",
|
||||
"192.168.25.1:9200:9200",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('should return custom port when passed in options', () => {
|
||||
const port = resolvePort({ port: 9220 });
|
||||
|
||||
|
@ -167,6 +181,21 @@ describe('resolvePort()', () => {
|
|||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('should return custom port and host when passed in options', () => {
|
||||
const port = resolvePort({ port: 9220, host: '192.168.25.1' });
|
||||
|
||||
expect(port).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"-p",
|
||||
"127.0.0.1:9220:9220",
|
||||
"-p",
|
||||
"192.168.25.1:9220:9220",
|
||||
"--env",
|
||||
"http.port=9220",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('verifyDockerInstalled()', () => {
|
||||
|
|
|
@ -56,6 +56,8 @@ export interface DockerOptions extends EsClusterExecOptions, BaseOptions {
|
|||
}
|
||||
|
||||
export interface ServerlessOptions extends EsClusterExecOptions, BaseOptions {
|
||||
/** Publish ES docker container on additional host IP */
|
||||
host?: string;
|
||||
/** Clean (or delete) all data created by the ES cluster after it is stopped */
|
||||
clean?: boolean;
|
||||
/** Path to the directory where the ES cluster will store data */
|
||||
|
@ -306,19 +308,21 @@ export function resolveDockerImage({
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine the port to bind the Serverless index node or Docker node to
|
||||
* Determine the port and optionally an additional host to bind the Serverless index node or Docker node to
|
||||
*/
|
||||
export function resolvePort(options: ServerlessOptions | DockerOptions) {
|
||||
if (options.port) {
|
||||
return [
|
||||
'-p',
|
||||
`127.0.0.1:${options.port}:${options.port}`,
|
||||
'--env',
|
||||
`http.port=${options.port}`,
|
||||
];
|
||||
const port = options.port || DEFAULT_PORT;
|
||||
const value = ['-p', `127.0.0.1:${port}:${port}`];
|
||||
|
||||
if ((options as ServerlessOptions).host) {
|
||||
value.push('-p', `${(options as ServerlessOptions).host}:${port}:${port}`);
|
||||
}
|
||||
|
||||
return ['-p', `127.0.0.1:${DEFAULT_PORT}:${DEFAULT_PORT}`];
|
||||
if (options.port) {
|
||||
value.push('--env', `http.port=${options.port}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,7 @@ import { Client, HttpConnection } from '@elastic/elasticsearch';
|
|||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { REPO_ROOT } from '@kbn/repo-info';
|
||||
import type { ArtifactLicense } from '@kbn/es';
|
||||
import type { ServerlessOptions } from '@kbn/es/src/utils';
|
||||
import { CI_PARALLEL_PROCESS_PREFIX } from '../ci_parallel_process_prefix';
|
||||
import { esTestConfig } from './es_test_config';
|
||||
|
||||
|
@ -70,10 +71,7 @@ export interface CreateTestEsClusterOptions {
|
|||
*/
|
||||
esArgs?: string[];
|
||||
esFrom?: string;
|
||||
esServerlessOptions?: {
|
||||
image?: string;
|
||||
tag?: string;
|
||||
};
|
||||
esServerlessOptions?: Pick<ServerlessOptions, 'image' | 'tag' | 'host'>;
|
||||
esJavaOpts?: string;
|
||||
/**
|
||||
* License to run your cluster under. Keep in mind that a `trial` license
|
||||
|
@ -246,6 +244,7 @@ export function createTestEsCluster<
|
|||
esArgs: customEsArgs,
|
||||
image: esServerlessOptions?.image,
|
||||
tag: esServerlessOptions?.tag,
|
||||
host: esServerlessOptions?.host,
|
||||
port,
|
||||
clean: true,
|
||||
background: true,
|
||||
|
|
|
@ -214,6 +214,12 @@ export const schema = Joi.object()
|
|||
})
|
||||
.default(),
|
||||
|
||||
esServerlessOptions: Joi.object()
|
||||
.keys({
|
||||
host: Joi.string().ip(),
|
||||
})
|
||||
.default(),
|
||||
|
||||
kbnTestServer: Joi.object()
|
||||
.keys({
|
||||
buildArgs: Joi.array(),
|
||||
|
|
|
@ -166,16 +166,24 @@ function getESServerlessOptions(esServerlessImageFromArg: string | undefined, co
|
|||
esTestConfig.getESServerlessImage() ||
|
||||
(config.has('esTestCluster.esServerlessImage') &&
|
||||
config.get('esTestCluster.esServerlessImage'));
|
||||
const serverlessHost: string | undefined =
|
||||
config.has('esServerlessOptions.host') && config.get('esServerlessOptions.host');
|
||||
|
||||
if (esServerlessImageUrlOrTag) {
|
||||
if (esServerlessImageUrlOrTag.includes(':')) {
|
||||
return {
|
||||
image: esServerlessImageUrlOrTag,
|
||||
host: serverlessHost,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
tag: esServerlessImageUrlOrTag,
|
||||
host: serverlessHost,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
host: serverlessHost,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"cypress:dw": "NODE_OPTIONS=--openssl-legacy-provider node ./scripts/start_cypress_parallel --config-file ./public/management/cypress/cypress.config.ts --ftr-config-file ../../test/defend_workflows_cypress/cli_config",
|
||||
"cypress:dw:open": "yarn cypress:dw open",
|
||||
"cypress:dw:run": "yarn cypress:dw run",
|
||||
"cypress:dw:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ./scripts/start_cypress_parallel --config-file ./public/management/cypress/cypress_serverless.config.ts --ftr-config-file ../../../x-pack/test_serverless/functional/test_suites/security/cypress/security_config",
|
||||
"cypress:dw:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ./scripts/start_cypress_parallel --config-file ./public/management/cypress/cypress_serverless.config.ts --ftr-config-file ../../test/defend_workflows_cypress/serverless_config",
|
||||
"cypress:dw:serverless:open": "yarn cypress:dw:serverless open",
|
||||
"cypress:dw:serverless:run": "yarn cypress:dw:serverless run",
|
||||
"cypress:dw:endpoint": "echo '\n** WARNING **: Run script `cypress:dw:endpoint` no longer valid! Use `cypress:dw` instead\n'",
|
||||
|
|
|
@ -63,16 +63,8 @@ export const getCypressBaseConfig = (
|
|||
experimentalInteractiveRunEvents: true,
|
||||
setupNodeEvents: (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => {
|
||||
dataLoaders(on, config);
|
||||
|
||||
// skip dataLoadersForRealEndpoints() if running in serverless
|
||||
// https://github.com/elastic/security-team/issues/7467
|
||||
// Once we are able to run Fleet server in serverless mode (see: https://github.com/elastic/kibana/pull/166183)
|
||||
// this `if()` statement needs to be removed and `dataLoadersForRealEndpoints()` should
|
||||
// just be called without having any checks around it.
|
||||
if (!config.env.IS_SERVERLESS) {
|
||||
// Data loaders specific to "real" Endpoint testing
|
||||
dataLoadersForRealEndpoints(on, config);
|
||||
}
|
||||
// Data loaders specific to "real" Endpoint testing
|
||||
dataLoadersForRealEndpoints(on, config);
|
||||
|
||||
responseActionTasks(on, config);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ const loginWithoutAccess = (url: string) => {
|
|||
loadPage(url);
|
||||
};
|
||||
|
||||
describe('Artifacts pages', { tags: '@ess' }, () => {
|
||||
describe('Artifacts pages', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
before(() => {
|
||||
login();
|
||||
loadEndpointDataForEventFiltersIfNeeded();
|
||||
|
|
|
@ -18,7 +18,7 @@ import { cleanupRule, generateRandomStringName, loadRule } from '../../tasks/api
|
|||
import { RESPONSE_ACTION_TYPES } from '../../../../../common/api/detection_engine';
|
||||
import { login, ROLE } from '../../tasks/login';
|
||||
|
||||
describe('Form', { tags: '@ess' }, () => {
|
||||
describe('Form', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
describe('User with no access can not create an endpoint response action', () => {
|
||||
before(() => {
|
||||
login(ROLE.endpoint_response_actions_no_access);
|
||||
|
|
|
@ -12,79 +12,83 @@ import { indexEndpointRuleAlerts } from '../../tasks/index_endpoint_rule_alerts'
|
|||
|
||||
import { login, ROLE } from '../../tasks/login';
|
||||
|
||||
describe('Response actions history page', { tags: '@ess' }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let endpointDataWithAutomated: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let alertData: ReturnTypeFromChainable<typeof indexEndpointRuleAlerts> | undefined;
|
||||
const [endpointAgentId, endpointHostname] = generateRandomStringName(2);
|
||||
describe(
|
||||
'Response actions history page',
|
||||
{ tags: ['@ess', '@serverless', '@brokenInServerless'] },
|
||||
() => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let endpointDataWithAutomated: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let alertData: ReturnTypeFromChainable<typeof indexEndpointRuleAlerts> | undefined;
|
||||
const [endpointAgentId, endpointHostname] = generateRandomStringName(2);
|
||||
|
||||
before(() => {
|
||||
login(ROLE.endpoint_response_actions_access);
|
||||
before(() => {
|
||||
login(ROLE.endpoint_response_actions_access);
|
||||
|
||||
indexEndpointHosts({ numResponseActions: 2 }).then((indexEndpoints) => {
|
||||
endpointData = indexEndpoints;
|
||||
});
|
||||
indexEndpointRuleAlerts({
|
||||
endpointAgentId,
|
||||
endpointHostname,
|
||||
endpointIsolated: false,
|
||||
}).then((indexedAlert) => {
|
||||
alertData = indexedAlert;
|
||||
const alertId = alertData.alerts[0]._id;
|
||||
return indexEndpointHosts({
|
||||
numResponseActions: 1,
|
||||
alertIds: [alertId],
|
||||
}).then((indexEndpoints) => {
|
||||
endpointDataWithAutomated = indexEndpoints;
|
||||
indexEndpointHosts({ numResponseActions: 2 }).then((indexEndpoints) => {
|
||||
endpointData = indexEndpoints;
|
||||
});
|
||||
indexEndpointRuleAlerts({
|
||||
endpointAgentId,
|
||||
endpointHostname,
|
||||
endpointIsolated: false,
|
||||
}).then((indexedAlert) => {
|
||||
alertData = indexedAlert;
|
||||
const alertId = alertData.alerts[0]._id;
|
||||
return indexEndpointHosts({
|
||||
numResponseActions: 1,
|
||||
alertIds: [alertId],
|
||||
}).then((indexEndpoints) => {
|
||||
endpointDataWithAutomated = indexEndpoints;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(() => {
|
||||
if (endpointDataWithAutomated) {
|
||||
endpointDataWithAutomated.cleanup();
|
||||
endpointDataWithAutomated = undefined;
|
||||
}
|
||||
if (endpointData) {
|
||||
endpointData.cleanup();
|
||||
endpointData = undefined;
|
||||
}
|
||||
after(() => {
|
||||
if (endpointDataWithAutomated) {
|
||||
endpointDataWithAutomated.cleanup();
|
||||
endpointDataWithAutomated = undefined;
|
||||
}
|
||||
if (endpointData) {
|
||||
endpointData.cleanup();
|
||||
endpointData = undefined;
|
||||
}
|
||||
|
||||
if (alertData) {
|
||||
alertData.cleanup();
|
||||
alertData = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it('enable filtering by type', () => {
|
||||
cy.visit(`/app/security/administration/response_actions_history`);
|
||||
|
||||
let maxLength: number;
|
||||
cy.getByTestSubj('response-actions-list').then(($table) => {
|
||||
maxLength = $table.find('tbody .euiTableRow').length;
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength);
|
||||
if (alertData) {
|
||||
alertData.cleanup();
|
||||
alertData = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
cy.getByTestSubj('response-actions-list-type-filter-popoverButton').click();
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered by rule').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', 1);
|
||||
cy.get('tbody .euiTableRow').eq(0).contains('Triggered by rule');
|
||||
it('enable filtering by type', () => {
|
||||
cy.visit(`/app/security/administration/response_actions_history`);
|
||||
|
||||
let maxLength: number;
|
||||
cy.getByTestSubj('response-actions-list').then(($table) => {
|
||||
maxLength = $table.find('tbody .euiTableRow').length;
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength);
|
||||
});
|
||||
|
||||
cy.getByTestSubj('response-actions-list-type-filter-popoverButton').click();
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered by rule').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', 1);
|
||||
cy.get('tbody .euiTableRow').eq(0).contains('Triggered by rule');
|
||||
});
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered by rule').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength);
|
||||
});
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered manually').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength - 1);
|
||||
});
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered by rule').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength);
|
||||
cy.get('tbody .euiTableRow').eq(0).contains('Triggered by rule').click();
|
||||
});
|
||||
// check if we were moved to Rules app after clicking Triggered by rule
|
||||
cy.getByTestSubj('breadcrumb last').contains('Detection rules (SIEM)');
|
||||
});
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered by rule').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength);
|
||||
});
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered manually').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength - 1);
|
||||
});
|
||||
cy.getByTestSubj('type-filter-option').contains('Triggered by rule').click();
|
||||
cy.getByTestSubj('response-actions-list').within(() => {
|
||||
cy.get('tbody .euiTableRow').should('have.lengthOf', maxLength);
|
||||
cy.get('tbody .euiTableRow').eq(0).contains('Triggered by rule').click();
|
||||
});
|
||||
// check if we were moved to Rules app after clicking Triggered by rule
|
||||
cy.getByTestSubj('breadcrumb last').contains('Detection rules (SIEM)');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ import { indexEndpointRuleAlerts } from '../../tasks/index_endpoint_rule_alerts'
|
|||
|
||||
import { login, ROLE } from '../../tasks/login';
|
||||
|
||||
describe('Results', { tags: '@ess' }, () => {
|
||||
describe('Results', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let alertData: ReturnTypeFromChainable<typeof indexEndpointRuleAlerts> | undefined;
|
||||
const [endpointAgentId, endpointHostname] = generateRandomStringName(2);
|
||||
|
|
|
@ -32,7 +32,7 @@ import { createEndpointHost } from '../../tasks/create_endpoint_host';
|
|||
import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data';
|
||||
import { enableAllPolicyProtections } from '../../tasks/endpoint_policy';
|
||||
|
||||
describe('Endpoints page', { tags: '@ess' }, () => {
|
||||
describe('Endpoints page', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
let indexedPolicy: IndexedFleetEndpointPolicyResponse;
|
||||
let policy: PolicyData;
|
||||
let createdHost: CreateAndEnrollEndpointHostResponse;
|
||||
|
|
|
@ -13,7 +13,7 @@ import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts';
|
|||
import { login } from '../../tasks/login';
|
||||
import { loadPage } from '../../tasks/common';
|
||||
|
||||
describe('Endpoints page', { tags: '@ess' }, () => {
|
||||
describe('Endpoints page', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts>;
|
||||
|
||||
before(() => {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { navigateToFleetAgentDetails } from '../../screens/fleet/agent_details';
|
|||
import { EndpointPolicyResponseGenerator } from '../../../../../common/endpoint/data_generators/endpoint_policy_response_generator';
|
||||
import { descriptions } from '../../../components/policy_response/policy_response_friendly_names';
|
||||
|
||||
describe.skip('Endpoint Policy Response', { tags: '@ess' }, () => {
|
||||
describe.skip('Endpoint Policy Response', { tags: ['@ess', '@serverless'] }, () => {
|
||||
let loadedEndpoint: CyIndexEndpointHosts;
|
||||
let endpointMetadata: HostMetadata;
|
||||
let loadedPolicyResponse: IndexedEndpointPolicyResponse;
|
||||
|
|
|
@ -19,7 +19,8 @@ import { disableExpandableFlyoutAdvancedSettings, loadPage } from '../../tasks/c
|
|||
describe(
|
||||
'Policy Details',
|
||||
{
|
||||
tags: '@ess',
|
||||
tags: ['@ess', '@serverless', '@brokenInServerless'],
|
||||
env: { ftrConfig: { enableExperimental: ['protectionUpdatesEnabled'] } },
|
||||
},
|
||||
() => {
|
||||
describe('Protection updates', () => {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { login } from '../../tasks/login';
|
|||
import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../tasks/fleet';
|
||||
|
||||
// We need a way to disable experimental features in the Cypress tests
|
||||
describe.skip('Disabled experimental features on: ', { tags: '@ess' }, () => {
|
||||
describe.skip('Disabled experimental features on: ', { tags: ['@ess', '@serverless'] }, () => {
|
||||
describe('Policy list', () => {
|
||||
describe('Renders policy list without protection updates feature flag', () => {
|
||||
let indexedPolicy: IndexedFleetEndpointPolicyResponse;
|
||||
|
|
|
@ -16,7 +16,7 @@ import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../task
|
|||
describe(
|
||||
'Policy List',
|
||||
{
|
||||
tags: '@ess',
|
||||
tags: ['@ess', '@serverless', '@brokenInServerless'],
|
||||
env: { ftrConfig: { enableExperimental: ['protectionUpdatesEnabled'] } },
|
||||
},
|
||||
() => {
|
||||
|
|
|
@ -29,7 +29,7 @@ import { indexNewCase } from '../../tasks/index_new_case';
|
|||
import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts';
|
||||
import { indexEndpointRuleAlerts } from '../../tasks/index_endpoint_rule_alerts';
|
||||
|
||||
describe('Isolate command', { tags: '@ess' }, () => {
|
||||
describe('Isolate command', { tags: ['@ess', '@serverless'] }, () => {
|
||||
describe('from Manage', () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let isolatedEndpointData: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
|
@ -192,7 +192,7 @@ describe('Isolate command', { tags: '@ess' }, () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('from Cases', () => {
|
||||
describe('from Cases', { tags: ['@brokenInServerless'] }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts> | undefined;
|
||||
let caseData: ReturnTypeFromChainable<typeof indexNewCase> | undefined;
|
||||
let alertData: ReturnTypeFromChainable<typeof indexEndpointRuleAlerts> | undefined;
|
||||
|
|
|
@ -10,65 +10,69 @@ import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts';
|
|||
import { login } from '../../tasks/login';
|
||||
import { loadPage } from '../../tasks/common';
|
||||
|
||||
describe('Response actions history page', { tags: '@ess' }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts>;
|
||||
// let actionData: ReturnTypeFromChainable<typeof indexActionResponses>;
|
||||
describe(
|
||||
'Response actions history page',
|
||||
{ tags: ['@ess', '@serverless', '@brokenInServerless'] },
|
||||
() => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts>;
|
||||
// let actionData: ReturnTypeFromChainable<typeof indexActionResponses>;
|
||||
|
||||
before(() => {
|
||||
indexEndpointHosts({ numResponseActions: 11 }).then((indexEndpoints) => {
|
||||
endpointData = indexEndpoints;
|
||||
before(() => {
|
||||
indexEndpointHosts({ numResponseActions: 11 }).then((indexEndpoints) => {
|
||||
endpointData = indexEndpoints;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
if (endpointData) {
|
||||
endpointData.cleanup();
|
||||
// @ts-expect-error ignore setting to undefined
|
||||
endpointData = undefined;
|
||||
}
|
||||
});
|
||||
after(() => {
|
||||
if (endpointData) {
|
||||
endpointData.cleanup();
|
||||
// @ts-expect-error ignore setting to undefined
|
||||
endpointData = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it('retains expanded action details on page reload', () => {
|
||||
loadPage(`/app/security/administration/response_actions_history`);
|
||||
cy.getByTestSubj('response-actions-list-expand-button').eq(3).click(); // 4th row on 1st page
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||
cy.url().should('include', 'withOutputs');
|
||||
it('retains expanded action details on page reload', () => {
|
||||
loadPage(`/app/security/administration/response_actions_history`);
|
||||
cy.getByTestSubj('response-actions-list-expand-button').eq(3).click(); // 4th row on 1st page
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||
cy.url().should('include', 'withOutputs');
|
||||
|
||||
// navigate to page 2
|
||||
cy.getByTestSubj('pagination-button-1').click();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('not.exist');
|
||||
|
||||
// reload with URL params on page 2 with existing URL
|
||||
cy.reload();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('not.exist');
|
||||
|
||||
// navigate to page 1
|
||||
cy.getByTestSubj('pagination-button-0').click();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||
});
|
||||
|
||||
it('collapses expanded tray with a single click', () => {
|
||||
loadPage(`/app/security/administration/response_actions_history`);
|
||||
// 2nd row on 1st page
|
||||
cy.getByTestSubj('response-actions-list-expand-button').eq(1).as('2nd-row');
|
||||
|
||||
// expand the row
|
||||
cy.get('@2nd-row').click();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||
cy.url().should('include', 'withOutputs');
|
||||
|
||||
// collapse the row
|
||||
cy.intercept('GET', '/api/endpoint/action*').as('getResponses');
|
||||
cy.get('@2nd-row').click();
|
||||
// wait for the API response to come back
|
||||
// and then see if the tray is actually closed
|
||||
cy.wait('@getResponses', { timeout: 500 }).then(() => {
|
||||
// navigate to page 2
|
||||
cy.getByTestSubj('pagination-button-1').click();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('not.exist');
|
||||
cy.url().should('not.include', 'withOutputs');
|
||||
|
||||
// reload with URL params on page 2 with existing URL
|
||||
cy.reload();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('not.exist');
|
||||
|
||||
// navigate to page 1
|
||||
cy.getByTestSubj('pagination-button-0').click();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('collapses expanded tray with a single click', () => {
|
||||
loadPage(`/app/security/administration/response_actions_history`);
|
||||
// 2nd row on 1st page
|
||||
cy.getByTestSubj('response-actions-list-expand-button').eq(1).as('2nd-row');
|
||||
|
||||
// expand the row
|
||||
cy.get('@2nd-row').click();
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||
cy.url().should('include', 'withOutputs');
|
||||
|
||||
// collapse the row
|
||||
cy.intercept('GET', '/api/endpoint/action*').as('getResponses');
|
||||
cy.get('@2nd-row').click();
|
||||
// wait for the API response to come back
|
||||
// and then see if the tray is actually closed
|
||||
cy.wait('@getResponses', { timeout: 500 }).then(() => {
|
||||
cy.getByTestSubj('response-actions-list-details-tray').should('not.exist');
|
||||
cy.url().should('not.include', 'withOutputs');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -21,7 +21,7 @@ import { indexNewCase } from '../../tasks/index_new_case';
|
|||
import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts';
|
||||
import { indexEndpointRuleAlerts } from '../../tasks/index_endpoint_rule_alerts';
|
||||
|
||||
describe('When accessing Endpoint Response Console', { tags: '@ess' }, () => {
|
||||
describe('When accessing Endpoint Response Console', { tags: ['@ess', '@serverless'] }, () => {
|
||||
const performResponderSanityChecks = () => {
|
||||
openResponderActionLogFlyout();
|
||||
// Ensure the popover in the action log date quick select picker is accessible
|
||||
|
@ -109,12 +109,16 @@ describe('When accessing Endpoint Response Console', { tags: '@ess' }, () => {
|
|||
cy.getByTestSubj('endpointResponseActions-action-item').should('be.enabled');
|
||||
});
|
||||
|
||||
it('should display Responder response action interface', () => {
|
||||
loadPage(caseUrlPath);
|
||||
closeAllToasts();
|
||||
openCaseAlertDetails();
|
||||
cy.getByTestSubj('endpointResponseActions-action-item').click();
|
||||
performResponderSanityChecks();
|
||||
});
|
||||
it(
|
||||
'should display Responder response action interface',
|
||||
{ tags: ['@brokenInServerless'] },
|
||||
() => {
|
||||
loadPage(caseUrlPath);
|
||||
closeAllToasts();
|
||||
openCaseAlertDetails();
|
||||
cy.getByTestSubj('endpointResponseActions-action-item').click();
|
||||
performResponderSanityChecks();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,12 +24,12 @@ import {
|
|||
} from '../../tasks/isolate';
|
||||
import { login } from '../../tasks/login';
|
||||
|
||||
describe('Response console', { tags: '@ess' }, () => {
|
||||
describe('Response console', { tags: ['@ess', '@serverless'] }, () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
describe('`isolate` command', () => {
|
||||
describe('`isolate` command', { tags: ['@brokenInServerless'] }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts>;
|
||||
let endpointHostname: string;
|
||||
let isolateRequestResponse: ActionDetails;
|
||||
|
@ -71,7 +71,7 @@ describe('Response console', { tags: '@ess' }, () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('`release` command', () => {
|
||||
describe('`release` command', { tags: ['@brokenInServerless'] }, () => {
|
||||
let endpointData: ReturnTypeFromChainable<typeof indexEndpointHosts>;
|
||||
let endpointHostname: string;
|
||||
let releaseRequestResponse: ActionDetails;
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
import { networkInterfaces } from 'node:os';
|
||||
|
||||
export const getLocalhostRealIp = (): string => {
|
||||
for (const netInterfaceList of Object.values(networkInterfaces())) {
|
||||
export const getBridgeNetworkHostIp = (): string => {
|
||||
// reverse to get the last interface first
|
||||
for (const netInterfaceList of Object.values(networkInterfaces()).reverse()) {
|
||||
if (netInterfaceList) {
|
||||
const netInterface = netInterfaceList.find(
|
||||
(networkInterface) =>
|
|
@ -11,7 +11,6 @@ import type { KbnClientOptions } from '@kbn/test';
|
|||
import { KbnClient } from '@kbn/test';
|
||||
import type { StatusResponse } from '@kbn/core-status-common-internal';
|
||||
import pRetry from 'p-retry';
|
||||
import nodeFetch from 'node-fetch';
|
||||
import type { ReqOptions } from '@kbn/test/src/kbn_client/kbn_client_requester';
|
||||
import { type AxiosResponse } from 'axios';
|
||||
import type { ClientOptions } from '@elastic/elasticsearch/lib/client';
|
||||
|
@ -19,7 +18,7 @@ import fs from 'fs';
|
|||
import { CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { catchAxiosErrorFormatAndThrow } from './format_axios_error';
|
||||
import { isLocalhost } from './is_localhost';
|
||||
import { getLocalhostRealIp } from './localhost_services';
|
||||
import { getBridgeNetworkHostIp } from './network_services';
|
||||
import { createSecuritySuperuser } from './security_user_services';
|
||||
|
||||
const CA_CERTIFICATE: Buffer = fs.readFileSync(CA_CERT_PATH);
|
||||
|
@ -117,7 +116,9 @@ export const createRuntimeServices = async ({
|
|||
let password = _password;
|
||||
|
||||
if (asSuperuser) {
|
||||
await waitForKibana(kibanaUrl);
|
||||
await waitForKibana(
|
||||
createKbnClient({ log, url: kibanaUrl, username, password, apiKey, noCertForSsl })
|
||||
);
|
||||
const tmpEsClient = createEsClient({
|
||||
url: elasticsearchUrl,
|
||||
username,
|
||||
|
@ -162,7 +163,7 @@ export const createRuntimeServices = async ({
|
|||
noCertForSsl,
|
||||
}),
|
||||
log,
|
||||
localhostRealIp: getLocalhostRealIp(),
|
||||
localhostRealIp: getBridgeNetworkHostIp(),
|
||||
apiKey: apiKey ?? '',
|
||||
user: {
|
||||
username,
|
||||
|
@ -306,24 +307,15 @@ export const fetchKibanaStatus = async (kbnClient: KbnClient): Promise<StatusRes
|
|||
|
||||
/**
|
||||
* Checks to ensure Kibana is up and running
|
||||
* @param kbnUrl
|
||||
* @param kbnClient
|
||||
*/
|
||||
export const waitForKibana = async (kbnUrl: string): Promise<void> => {
|
||||
const url = (() => {
|
||||
const u = new URL(kbnUrl);
|
||||
// This API seems to be available even if user is not authenticated
|
||||
u.pathname = '/api/status';
|
||||
return u.toString();
|
||||
})();
|
||||
|
||||
export const waitForKibana = async (kbnClient: KbnClient): Promise<void> => {
|
||||
await pRetry(
|
||||
async () => {
|
||||
const response = await nodeFetch(url);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(
|
||||
`Kibana not available. Returned: [${response.status}]: ${response.statusText}`
|
||||
);
|
||||
try {
|
||||
await kbnClient.status.get();
|
||||
} catch (err) {
|
||||
throw new Error(`Kibana not available: ${err.message}`);
|
||||
}
|
||||
},
|
||||
{ maxTimeout: 10000 }
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SERVERLESS_NODES } from '@kbn/es';
|
||||
import { EsVersion, readConfigFile } from '@kbn/test';
|
||||
import type { ToolingLog } from '@kbn/tooling-log';
|
||||
import { CA_TRUSTED_FINGERPRINT } from '@kbn/dev-utils';
|
||||
import { getLocalhostRealIp } from '../endpoint/common/localhost_services';
|
||||
import { getBridgeNetworkHostIp } from '../endpoint/common/network_services';
|
||||
import type { parseTestFileConfig } from './utils';
|
||||
|
||||
export const getFTRConfig = ({
|
||||
|
@ -59,7 +58,7 @@ export const getFTRConfig = ({
|
|||
// },
|
||||
},
|
||||
(vars) => {
|
||||
const hostRealIp = getLocalhostRealIp();
|
||||
const hostRealIp = getBridgeNetworkHostIp();
|
||||
|
||||
const hasFleetServerArgs = _.some(
|
||||
vars.kbnTestServer.serverArgs,
|
||||
|
@ -90,15 +89,15 @@ export const getFTRConfig = ({
|
|||
vars.kbnTestServer.serverArgs = _.map(vars.kbnTestServer.serverArgs, (value) => {
|
||||
if (
|
||||
vars.servers.elasticsearch.protocol === 'https' &&
|
||||
value.includes('--elasticsearch.hosts=http')
|
||||
value.includes('--elasticsearch.hosts=http://')
|
||||
) {
|
||||
return value.replace('http', 'https');
|
||||
}
|
||||
|
||||
if (
|
||||
vars.servers.kibana.protocol === 'https' &&
|
||||
(value.includes('--elasticsearch.hosts=http') ||
|
||||
value.includes('--server.publicBaseUrl=http'))
|
||||
(value.includes('--elasticsearch.hosts=http://') ||
|
||||
value.includes('--server.publicBaseUrl=http://'))
|
||||
) {
|
||||
return value.replace('http', 'https');
|
||||
}
|
||||
|
@ -135,14 +134,32 @@ export const getFTRConfig = ({
|
|||
|
||||
if (hasFleetServerArgs) {
|
||||
if (vars.serverless) {
|
||||
vars.esServerlessOptions = {
|
||||
...(vars.esServerlessOptions || {}),
|
||||
// Bind ES docker container to the host network so that the Elastic agent running in the VM can connect to it
|
||||
host: hostRealIp,
|
||||
};
|
||||
|
||||
vars.kbnTestServer.serverArgs.push(
|
||||
`--xpack.fleet.agents.fleet_server.hosts=["https://host.docker.internal:${fleetServerPort}"]`
|
||||
`--xpack.fleet.agents.fleet_server.hosts=["https://${hostRealIp}:${fleetServerPort}"]`
|
||||
);
|
||||
vars.kbnTestServer.serverArgs.push(
|
||||
`--xpack.fleet.agents.elasticsearch.host=https://${SERVERLESS_NODES[0].name}:${esPort}`
|
||||
);
|
||||
vars.kbnTestServer.serverArgs.push(
|
||||
`--xpack.fleet.agents.elasticsearch.ca_trusted_fingerprint=${CA_TRUSTED_FINGERPRINT}`
|
||||
`--xpack.fleet.outputs=${JSON.stringify([
|
||||
{
|
||||
id: 'fleet-default-output',
|
||||
name: 'default',
|
||||
is_default: true,
|
||||
is_default_monitoring: true,
|
||||
type: 'elasticsearch',
|
||||
ca_trusted_fingerprint: CA_TRUSTED_FINGERPRINT,
|
||||
hosts: [`https://${hostRealIp}:${esPort}`],
|
||||
config: {
|
||||
ssl: {
|
||||
verification_mode: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
])}`
|
||||
);
|
||||
} else {
|
||||
vars.kbnTestServer.serverArgs.push(
|
||||
|
@ -158,20 +175,11 @@ export const getFTRConfig = ({
|
|||
if (vars.serverless) {
|
||||
log.info(`Serverless mode detected`);
|
||||
|
||||
vars.kbnTestServer.serverArgs.push(
|
||||
`--elasticsearch.hosts=https://localhost:${esPort}`,
|
||||
`--server.publicBaseUrl=https://localhost:${kibanaPort}`
|
||||
);
|
||||
vars.esTestCluster.serverArgs.push(
|
||||
`xpack.security.authc.realms.saml.cloud-saml-kibana.sp.entity_id=http://host.docker.internal:${kibanaPort}`,
|
||||
`xpack.security.authc.realms.saml.cloud-saml-kibana.sp.logout=http://host.docker.internal:${kibanaPort}/logout`,
|
||||
`xpack.security.authc.realms.saml.cloud-saml-kibana.sp.acs=http://host.docker.internal:${kibanaPort}/api/security/saml/callback`
|
||||
);
|
||||
} else {
|
||||
vars.kbnTestServer.serverArgs.push(
|
||||
`--elasticsearch.hosts=http://localhost:${esPort}`,
|
||||
`--server.publicBaseUrl=http://localhost:${kibanaPort}`
|
||||
);
|
||||
}
|
||||
|
||||
if (specFileFTRConfig?.productTypes) {
|
||||
|
|
|
@ -176,6 +176,10 @@ ${JSON.stringify(cypressConfigFile, null, 2)}
|
|||
const fleetServerPorts: number[] = [8220];
|
||||
|
||||
const getEsPort = <T>(): T | number => {
|
||||
if (isOpen) {
|
||||
return 9220;
|
||||
}
|
||||
|
||||
const esPort = parseInt(`92${Math.floor(Math.random() * 89) + 10}`, 10);
|
||||
if (esPorts.includes(esPort)) {
|
||||
return getEsPort();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import { CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { getLocalhostRealIp } from '@kbn/security-solution-plugin/scripts/endpoint/common/localhost_services';
|
||||
import { getBridgeNetworkHostIp } from '@kbn/security-solution-plugin/scripts/endpoint/common/network_services';
|
||||
import { services } from './services';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
|
@ -18,7 +18,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
require.resolve('../functional/config.base.js')
|
||||
);
|
||||
|
||||
const hostIp = getLocalhostRealIp();
|
||||
const hostIp = getBridgeNetworkHostIp();
|
||||
|
||||
return {
|
||||
...kibanaCommonTestsConfig.getAll(),
|
||||
|
|
|
@ -1,65 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getLocalhostRealIp } from '@kbn/security-solution-plugin/scripts/endpoint/common/localhost_services';
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
|
||||
import { ExperimentalFeatures } from '@kbn/security-solution-plugin/common/experimental_features';
|
||||
import { DefendWorkflowsCypressCliTestRunner } from './runner';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const defendWorkflowsCypressConfig = await readConfigFile(require.resolve('./config.ts'));
|
||||
const svlSharedConfig = await readConfigFile(
|
||||
require.resolve('../../test_serverless/shared/config.base.ts')
|
||||
);
|
||||
|
||||
const hostIp = getLocalhostRealIp();
|
||||
|
||||
const enabledFeatureFlags: Array<keyof ExperimentalFeatures> = [];
|
||||
|
||||
return {
|
||||
...svlSharedConfig.getAll(),
|
||||
esTestCluster: {
|
||||
...svlSharedConfig.get('esTestCluster'),
|
||||
serverArgs: [
|
||||
...svlSharedConfig.get('esTestCluster.serverArgs'),
|
||||
// define custom es server here
|
||||
// API Keys is enabled at the top level
|
||||
],
|
||||
},
|
||||
servers: {
|
||||
...svlSharedConfig.get('servers'),
|
||||
fleetserver: {
|
||||
protocol: 'https',
|
||||
hostname: hostIp,
|
||||
port: 8220,
|
||||
},
|
||||
},
|
||||
kbnTestServer: {
|
||||
...svlSharedConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...svlSharedConfig.get('kbnTestServer.serverArgs'),
|
||||
'--csp.strict=false',
|
||||
'--csp.warnLegacyBrowsers=false',
|
||||
'--serverless=security',
|
||||
'--xpack.encryptedSavedObjects.encryptionKey="abcdefghijklmnopqrstuvwxyz123456"',
|
||||
|
||||
'--xpack.security.enabled=true',
|
||||
`--xpack.fleet.agents.fleet_server.hosts=["https://${hostIp}:8220"]`,
|
||||
`--xpack.fleet.agents.elasticsearch.host=http://${hostIp}:${defendWorkflowsCypressConfig.get(
|
||||
'servers.elasticsearch.port'
|
||||
)}`,
|
||||
|
||||
// set the packagerTaskInterval to 5s in order to speed up test executions when checking fleet artifacts
|
||||
'--xpack.securitySolution.packagerTaskInterval=5s',
|
||||
|
||||
`--xpack.securitySolution.enableExperimental=${JSON.stringify(enabledFeatureFlags)}`,
|
||||
],
|
||||
},
|
||||
testRunner: DefendWorkflowsCypressCliTestRunner,
|
||||
};
|
||||
}
|
|
@ -5,22 +5,31 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getLocalhostRealIp } from '@kbn/security-solution-plugin/scripts/endpoint/common/localhost_services';
|
||||
import { getBridgeNetworkHostIp } from '@kbn/security-solution-plugin/scripts/endpoint/common/network_services';
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
|
||||
import { ExperimentalFeatures } from '@kbn/security-solution-plugin/common/experimental_features';
|
||||
import { DefendWorkflowsCypressCliTestRunner } from './runner';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const defendWorkflowsCypressConfig = await readConfigFile(require.resolve('./config.ts'));
|
||||
const defendWorkflowsCypressConfig = await readConfigFile(
|
||||
require.resolve(
|
||||
'../../test_serverless/functional/test_suites/security/cypress/security_config.base.ts'
|
||||
)
|
||||
);
|
||||
const config = defendWorkflowsCypressConfig.getAll();
|
||||
const hostIp = getLocalhostRealIp();
|
||||
const hostIp = getBridgeNetworkHostIp();
|
||||
|
||||
const enabledFeatureFlags: Array<keyof ExperimentalFeatures> = [];
|
||||
|
||||
return {
|
||||
...config,
|
||||
|
||||
esTestCluster: {
|
||||
...config.esTestCluster,
|
||||
serverArgs: [...config.esTestCluster.serverArgs, 'http.host=0.0.0.0'],
|
||||
},
|
||||
|
||||
servers: {
|
||||
...config.servers,
|
||||
fleetserver: {
|
Loading…
Add table
Add a link
Reference in a new issue