[8.18] [Siem Migration] - Start/Stop Translation integration tests (#212030) (#213219)

# Backport

This will backport the following commits from `main` to `8.18`:
- [[Siem Migration] - Start/Stop Translation integration tests
(#212030)](https://github.com/elastic/kibana/pull/212030)

<!--- Backport version: 9.6.6 -->

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

<!--BACKPORT [{"author":{"name":"Jatin
Kathuria","email":"jatin.kathuria@elastic.co"},"sourceCommit":{"committedDate":"2025-03-05T11:06:06Z","message":"[Siem
Migration] - Start/Stop Translation integration tests (#212030)\n\n##
Summary\n\nHandles\n-
https://github.com/elastic/security-team/issues/11232\n\nThis PR adds
the integration tests for \n- Start Translation API\n- Stop Translation
API","sha":"4998b75677557f4781b94bd58cf04eae118943d6","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:version","v8.18.0","v9.1.0","v8.19.0"],"title":"[Siem
Migration] - Start/Stop Translation integration
tests","number":212030,"url":"https://github.com/elastic/kibana/pull/212030","mergeCommit":{"message":"[Siem
Migration] - Start/Stop Translation integration tests (#212030)\n\n##
Summary\n\nHandles\n-
https://github.com/elastic/security-team/issues/11232\n\nThis PR adds
the integration tests for \n- Start Translation API\n- Stop Translation
API","sha":"4998b75677557f4781b94bd58cf04eae118943d6"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/212030","number":212030,"mergeCommit":{"message":"[Siem
Migration] - Start/Stop Translation integration tests (#212030)\n\n##
Summary\n\nHandles\n-
https://github.com/elastic/security-team/issues/11232\n\nThis PR adds
the integration tests for \n- Start Translation API\n- Stop Translation
API","sha":"4998b75677557f4781b94bd58cf04eae118943d6"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Jatin Kathuria <jatin.kathuria@elastic.co>
This commit is contained in:
Kibana Machine 2025-03-06 00:04:33 +11:00 committed by GitHub
parent ecca188cc7
commit a2d89b0a90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 288 additions and 6 deletions

View file

@ -82,7 +82,7 @@ export const registerSiemRuleMigrationsStartRoute = (
});
if (!exists) {
return res.noContent();
return res.notFound();
}
await siemMigrationAuditLogger.logStart({ migrationId });

View file

@ -45,7 +45,7 @@ export const registerSiemRuleMigrationsStopRoute = (
const { exists, stopped } = await ruleMigrationsClient.task.stop(migrationId);
if (!exists) {
return res.noContent();
return res.notFound();
}
await siemMigrationAuditLogger.logStop({ migrationId });

View file

@ -149,9 +149,9 @@ export class RuleMigrationsTaskClient {
const { rules } = await this.data.rules.getStats(migrationId);
if (rules.total > 0) {
return { exists: true, stopped: false };
return { exists: true, stopped: true };
}
return { exists: false, stopped: false };
return { exists: false, stopped: true };
} catch (err) {
this.logger.error(`Error stopping migration ID:${migrationId}`, err);
return { exists: true, stopped: false };

View file

@ -30,3 +30,17 @@ export const PRECONFIGURED_ACTION_CONNECTORS: Record<string, PreconfiguredConnec
},
},
};
export const PRECONFIGURED_BEDROCK_ACTION = {
'preconfigured-bedrock': {
name: 'preconfigured-bedrock',
actionTypeId: '.bedrock',
config: {
apiUrl: 'https://example.com',
},
secrets: {
username: 'user',
password: 'password',
},
},
};

View file

@ -6,16 +6,26 @@
*/
import { FtrConfigProviderContext } from '@kbn/test';
import { PRECONFIGURED_BEDROCK_ACTION } from '../../../../../config/shared';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const functionalConfig = await readConfigFile(
require.resolve('../../../../../config/ess/config.base.trial')
);
const defaultConfig = functionalConfig.getAll();
return {
...functionalConfig.getAll(),
...defaultConfig,
testFiles: [require.resolve('..')],
junit: {
reportName: 'SIEM Migrations Integration Tests - ESS Env - Trial License',
},
kbnTestServer: {
...defaultConfig.kbnTestServer,
serverArgs: [
...defaultConfig.kbnTestServer.serverArgs,
`--xpack.actions.preconfigured=${JSON.stringify(PRECONFIGURED_BEDROCK_ACTION)}`,
],
},
};
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { PRECONFIGURED_BEDROCK_ACTION } from '../../../../../config/shared';
import { createTestConfig } from '../../../../../config/serverless/config.base';
export default createTestConfig({
@ -15,6 +16,7 @@ export default createTestConfig({
{ product_line: 'endpoint', product_tier: 'complete' },
{ product_line: 'cloud', product_tier: 'complete' },
])}`,
`--xpack.actions.preconfigured=${JSON.stringify(PRECONFIGURED_BEDROCK_ACTION)}`,
],
testFiles: [require.resolve('..')],
junit: {

View file

@ -7,12 +7,14 @@
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('@ess SecuritySolution SIEM Migrations', () => {
describe('@ess @serverless SecuritySolution SIEM Migrations', () => {
loadTestFile(require.resolve('./create'));
loadTestFile(require.resolve('./get_prebuilt_rules'));
loadTestFile(require.resolve('./get'));
loadTestFile(require.resolve('./install'));
loadTestFile(require.resolve('./stats'));
loadTestFile(require.resolve('./update'));
loadTestFile(require.resolve('./start'));
loadTestFile(require.resolve('./stop'));
});
}

View file

@ -0,0 +1,127 @@
/*
* 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 { v4 as uuidv4 } from 'uuid';
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../../ftr_provider_context';
import {
SiemMigrationsAPIErrorResponse,
defaultOriginalRule,
migrationRulesRouteHelpersFactory,
} from '../../utils';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const migrationRulesRoutes = migrationRulesRouteHelpersFactory(supertest);
describe('Start Migration', () => {
let migrationId: string;
beforeEach(async () => {
migrationId = uuidv4();
await migrationRulesRoutes.create({
migrationId,
payload: [defaultOriginalRule],
});
});
afterEach(async () => {
await migrationRulesRoutes.stop({ migrationId });
});
it('should start migration successfully', async () => {
const response = await migrationRulesRoutes.start({
migrationId,
payload: {
connector_id: 'preconfigured-bedrock',
},
});
expect(response.body).to.eql({ started: true });
});
it('should return status of running migration correctly ', async () => {
await migrationRulesRoutes.start({
migrationId,
payload: {
connector_id: 'preconfigured-bedrock',
},
});
const response = await migrationRulesRoutes.stats({ migrationId });
expect(response.body).keys('status', 'rules', 'id', 'created_at', 'last_updated_at');
expect(response.body.rules).to.eql({
completed: 0,
failed: 0,
pending: 1,
processing: 0,
total: 1,
});
expect(response.body.status).to.equal('running');
expect(response.body.id).to.equal(migrationId);
});
it('should return started false for already running migration', async () => {
await migrationRulesRoutes.start({
migrationId,
payload: {
connector_id: 'preconfigured-bedrock',
},
});
const response = await migrationRulesRoutes.start({
migrationId,
expectStatusCode: 200,
payload: {
connector_id: 'preconfigured-bedrock',
},
});
expect(response.body).to.eql({ started: false });
});
describe('error scenarios', () => {
it('should reject if connector_id is incorrect', async () => {
const response = await migrationRulesRoutes.start({
migrationId: 'invalid_migration_id',
expectStatusCode: 400,
payload: {
connector_id: 'preconfigured_bedrock',
},
});
expect((response.body as unknown as SiemMigrationsAPIErrorResponse).message).to.eql(
'Saved object [action/preconfigured_bedrock] not found'
);
});
it('should reject if connector_id is not provided', async () => {
const response = await migrationRulesRoutes.start({
migrationId,
expectStatusCode: 400,
payload: {
// @ts-expect-error
connector_id: undefined,
},
});
expect((response.body as unknown as SiemMigrationsAPIErrorResponse).message).to.eql(
'[request body]: connector_id: Required'
);
});
it('should reject with 404 if migrationId is not found', async () => {
await migrationRulesRoutes.start({
migrationId: 'invalid_migration_id',
expectStatusCode: 404,
payload: {
connector_id: 'preconfigured-bedrock',
},
});
});
});
});
};

View file

@ -0,0 +1,67 @@
/*
* 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 { v4 as uuidv4 } from 'uuid';
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../../ftr_provider_context';
import { defaultOriginalRule, migrationRulesRouteHelpersFactory } from '../../utils';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertest');
const migrationRulesRoutes = migrationRulesRouteHelpersFactory(supertest);
describe('Stop Migration', () => {
let migrationId: string;
beforeEach(async () => {
migrationId = uuidv4();
await migrationRulesRoutes.create({
migrationId,
payload: [defaultOriginalRule],
});
});
afterEach(async () => {
await migrationRulesRoutes.stop({ migrationId });
});
it('should stop a running migration successfully', async () => {
// start migration
const { body } = await migrationRulesRoutes.start({
migrationId,
payload: {
connector_id: 'preconfigured-bedrock',
},
});
expect(body).to.eql({ started: true });
// check if it running correctly
let statsResponse = await migrationRulesRoutes.stats({ migrationId });
expect(statsResponse.body.status).to.eql('running');
// Stop Migration
const response = await migrationRulesRoutes.stop({ migrationId });
expect(response.body).to.eql({ stopped: true });
// check if the migration is stopped
statsResponse = await migrationRulesRoutes.stats({ migrationId });
expect(statsResponse.body.status).to.eql('ready');
});
describe('error scenarios', () => {
it('should return 404 if migration id is invalid and non-existent', async () => {
await migrationRulesRoutes.start({
migrationId: 'invalid_migration_id',
expectStatusCode: 404,
payload: { connector_id: 'preconfigured-bedrock' },
});
});
it('should return correct output when migration is not even running', async () => {
const stopResponse = await migrationRulesRoutes.stop({ migrationId });
expect(stopResponse.body).to.eql({ stopped: true });
});
});
});
};

View file

@ -18,8 +18,10 @@ import {
SIEM_RULE_MIGRATIONS_PREBUILT_RULES_PATH,
SIEM_RULE_MIGRATION_INSTALL_PATH,
SIEM_RULE_MIGRATION_PATH,
SIEM_RULE_MIGRATION_START_PATH,
SIEM_RULE_MIGRATION_STATS_PATH,
SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH,
SIEM_RULE_MIGRATION_STOP_PATH,
} from '@kbn/security-solution-plugin/common/siem_migrations/constants';
import {
CreateRuleMigrationResponse,
@ -29,11 +31,20 @@ import {
GetRuleMigrationResponse,
GetRuleMigrationStatsResponse,
InstallMigrationRulesResponse,
StartRuleMigrationRequestBody,
StartRuleMigrationResponse,
StopRuleMigrationResponse,
UpdateRuleMigrationResponse,
} from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen';
import { API_VERSIONS } from '@kbn/security-solution-plugin/common/constants';
import { assertStatusCode } from './asserts';
export interface SiemMigrationsAPIErrorResponse {
status_code: number;
error: string;
message: string;
}
export interface RequestParams {
/** Optional expected status code parameter */
expectStatusCode?: number;
@ -67,6 +78,10 @@ export interface InstallRulesParams extends MigrationRequestParams {
payload?: any;
}
export type StartMigrationRuleParams = MigrationRequestParams & {
payload: StartRuleMigrationRequestBody;
};
export const migrationRulesRouteHelpersFactory = (supertest: SuperTest.Agent) => {
return {
get: async ({
@ -202,5 +217,50 @@ export const migrationRulesRouteHelpersFactory = (supertest: SuperTest.Agent) =>
return response;
},
start: async ({
migrationId,
expectStatusCode = 200,
payload,
}: StartMigrationRuleParams): Promise<{
body: StartRuleMigrationResponse;
}> => {
const response = await supertest
.put(
replaceParams(SIEM_RULE_MIGRATION_START_PATH, {
migration_id: migrationId,
})
)
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.internal.v1)
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send(payload);
assertStatusCode(expectStatusCode, response);
return response;
},
stop: async ({
migrationId,
expectStatusCode = 200,
}: MigrationRequestParams): Promise<{
body: StopRuleMigrationResponse;
}> => {
const response = await supertest
.put(
replaceParams(SIEM_RULE_MIGRATION_STOP_PATH, {
migration_id: migrationId,
})
)
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, API_VERSIONS.internal.v1)
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send();
assertStatusCode(expectStatusCode, response);
return response;
},
};
};