Skip to content

Commit

Permalink
[9.0] [Siem Migration] - Start/Stop Translation integration tests (#2…
Browse files Browse the repository at this point in the history
…12030) (#213221)

# Backport

This will backport the following commits from `main` to `9.0`:
- [[Siem Migration] - Start/Stop Translation integration tests
(#212030)](#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>
  • Loading branch information
kibanamachine and logeekal authored Mar 5, 2025
1 parent 3bf69b0 commit f62e695
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const registerSiemRuleMigrationsStartRoute = (
});

if (!exists) {
return res.noContent();
return res.notFound();
}

await siemMigrationAuditLogger.logStart({ migrationId });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
14 changes: 14 additions & 0 deletions x-pack/test/security_solution_api_integration/config/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`,
],
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { PRECONFIGURED_BEDROCK_ACTION } from '../../../../../config/shared';
import { createTestConfig } from '../../../../../config/serverless/config.base';

export default createTestConfig({
Expand All @@ -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: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
});
}
Original file line number Diff line number Diff line change
@@ -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',
},
});
});
});
});
};
Original file line number Diff line number Diff line change
@@ -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 });
});
});
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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 ({
Expand Down Expand Up @@ -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;
},
};
};

0 comments on commit f62e695

Please sign in to comment.