mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Security Solution][Risk Score]Code changes for limiting the transformID length to 36 characters (#213405)
## Summary The code changes in this PR ensure that the transform ID is limited to 36 characters when creating or updating the transform for risk-score. This adjustment aligns with ES constraint on transform ID length. ## Test Steps 1. Create a new namespace with a very long name. Ex : `namespace_that_stretches_farther_than_the_universe_and_beyond_like_buzz` 🚀 2. Enable the Risk Score in the new namespace. It should successfully get enabled. 3. Check the transform that was created (using dev tools) ``` GET _transform/risk_score_latest_transform_*?filter_path=transforms.id,transforms._meta.space_id ``` Output  ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Mark Hopkin <mark.hopkin@elastic.co>
This commit is contained in:
parent
bfe2db38e3
commit
a3f89ec2c2
7 changed files with 40 additions and 5 deletions
|
@ -12,6 +12,7 @@ describe('getTransformOptions', () => {
|
|||
const options = getTransformOptions({
|
||||
dest: 'dest',
|
||||
source: ['source'],
|
||||
namespace: 'tests',
|
||||
});
|
||||
|
||||
expect(options).toMatchInlineSnapshot(`
|
||||
|
@ -19,6 +20,7 @@ describe('getTransformOptions', () => {
|
|||
"_meta": Object {
|
||||
"managed": true,
|
||||
"managed_by": "security-entity-analytics",
|
||||
"space_id": "tests",
|
||||
"version": 3,
|
||||
},
|
||||
"dest": Object {
|
||||
|
|
|
@ -164,9 +164,11 @@ export type TransformOptions = Omit<TransformPutTransformRequest, 'transform_id'
|
|||
export const getTransformOptions = ({
|
||||
dest,
|
||||
source,
|
||||
namespace,
|
||||
}: {
|
||||
dest: string;
|
||||
source: string[];
|
||||
namespace: string;
|
||||
}): Omit<TransformPutTransformRequest, 'transform_id'> => ({
|
||||
dest: {
|
||||
index: dest,
|
||||
|
@ -206,5 +208,6 @@ export const getTransformOptions = ({
|
|||
version: 3, // When this field is updated we automatically update the transform
|
||||
managed: true, // Metadata that identifies the transform. It has no functionality
|
||||
managed_by: 'security-entity-analytics', // Metadata that identifies the transform. It has no functionality
|
||||
space_id: namespace, // Metadata that identifies the space where the transform is running. Helps in debugging as the original transformid could be hashed if longer than 64 characters
|
||||
},
|
||||
});
|
||||
|
|
|
@ -45,6 +45,7 @@ const totalFieldsLimit = 1000;
|
|||
describe('RiskScoreDataClient', () => {
|
||||
let riskScoreDataClient: RiskScoreDataClient;
|
||||
let riskScoreDataClientWithNameSpace: RiskScoreDataClient;
|
||||
let riskScoreDataClientWithLongNameSpace: RiskScoreDataClient;
|
||||
let mockSavedObjectClient: ReturnType<typeof savedObjectsClientMock.create>;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -60,6 +61,8 @@ describe('RiskScoreDataClient', () => {
|
|||
riskScoreDataClient = new RiskScoreDataClient(options);
|
||||
const optionsWithNamespace = { ...options, namespace: 'space-1' };
|
||||
riskScoreDataClientWithNameSpace = new RiskScoreDataClient(optionsWithNamespace);
|
||||
const optionsWithLongNamespace = { ...options, namespace: 'a_a-'.repeat(200) };
|
||||
riskScoreDataClientWithLongNameSpace = new RiskScoreDataClient(optionsWithLongNamespace);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -103,6 +106,10 @@ describe('RiskScoreDataClient', () => {
|
|||
assertIndex('space-1');
|
||||
assertTransform('space-1');
|
||||
|
||||
// Space with more than 36 characters
|
||||
await riskScoreDataClientWithLongNameSpace.init();
|
||||
assertTransform('a_a-'.repeat(200));
|
||||
|
||||
expect(
|
||||
(createOrUpdateComponentTemplate as jest.Mock).mock.lastCall[0].template.template
|
||||
).toMatchSnapshot();
|
||||
|
@ -443,7 +450,7 @@ const assertTransform = (namespace: string) => {
|
|||
field: '@timestamp',
|
||||
},
|
||||
},
|
||||
transform_id: `risk_score_latest_transform_${namespace}`,
|
||||
transform_id: transforms.getLatestTransformId(namespace),
|
||||
settings: {
|
||||
unattended: true,
|
||||
},
|
||||
|
@ -451,6 +458,7 @@ const assertTransform = (namespace: string) => {
|
|||
version: 3,
|
||||
managed: true,
|
||||
managed_by: 'security-entity-analytics',
|
||||
space_id: namespace,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -199,6 +199,7 @@ export class RiskScoreDataClient {
|
|||
...getTransformOptions({
|
||||
dest: getRiskScoreLatestIndex(namespace),
|
||||
source: [indexPatterns.alias],
|
||||
namespace: this.options.namespace,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
@ -363,6 +364,7 @@ export class RiskScoreDataClient {
|
|||
...getTransformOptions({
|
||||
dest: getRiskScoreLatestIndex(namespace),
|
||||
source: [indexPatterns.alias],
|
||||
namespace: this.options.namespace,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
scheduleLatestTransformNow,
|
||||
scheduleTransformNow,
|
||||
upgradeLatestTransformIfNeeded,
|
||||
getLatestTransformId,
|
||||
} from './transforms';
|
||||
|
||||
const transformId = 'test_transform_id';
|
||||
|
@ -48,6 +49,7 @@ const timeSeriesIndex = getRiskScoreTimeSeriesIndex('tests');
|
|||
const transformConfig = getTransformOptions({
|
||||
dest: latestIndex,
|
||||
source: [timeSeriesIndex],
|
||||
namespace: 'tests',
|
||||
});
|
||||
|
||||
const updatedTransformsMock = {
|
||||
|
@ -206,4 +208,12 @@ describe('transforms utils', () => {
|
|||
expect(esClient.transform.putTransform).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkTransformNameLength', () => {
|
||||
it('should limit the length of tranformId to less than or equal 64 characters', async () => {
|
||||
const longTransformId = 'a_a-'.repeat(1000);
|
||||
const response = await getLatestTransformId(longTransformId);
|
||||
expect(response.length).toBeLessThanOrEqual(36);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@ import type {
|
|||
TransformGetTransformStatsTransformStats,
|
||||
AcknowledgedResponseBase,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import murmurhash from 'murmurhash';
|
||||
import {
|
||||
getRiskScoreLatestIndex,
|
||||
getRiskScoreTimeSeriesIndex,
|
||||
|
@ -116,8 +117,15 @@ export const reinstallTransform = async ({
|
|||
});
|
||||
};
|
||||
|
||||
export const getLatestTransformId = (namespace: string): string =>
|
||||
`risk_score_latest_transform_${namespace}`;
|
||||
export const getLatestTransformId = (namespace: string): string => {
|
||||
const maxTransformId = 64;
|
||||
const prefix = `risk_score_latest_transform_`;
|
||||
const fullName = `${prefix}${namespace}`;
|
||||
|
||||
const processedNamespace =
|
||||
fullName.length > maxTransformId ? murmurhash.v3(namespace).toString(16) : namespace;
|
||||
return `${prefix}${processedNamespace}`;
|
||||
};
|
||||
|
||||
const hasTransformStarted = (transformStats: TransformGetTransformStatsTransformStats): boolean => {
|
||||
return transformStats.state === 'indexing' || transformStats.state === 'started';
|
||||
|
@ -174,6 +182,7 @@ export const upgradeLatestTransformIfNeeded = async ({
|
|||
const newConfig = getTransformOptions({
|
||||
dest: latestIndex,
|
||||
source: [timeSeriesIndex],
|
||||
namespace,
|
||||
});
|
||||
|
||||
if (isTransformOutdated(response.transforms[0], newConfig)) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import expect from '@kbn/expect';
|
||||
import { riskEngineConfigurationTypeName } from '@kbn/security-solution-plugin/server/lib/entity_analytics/risk_engine/saved_object';
|
||||
|
||||
import { getLatestTransformId } from '@kbn/security-solution-plugin/server/lib/entity_analytics/utils/transforms';
|
||||
import { riskEngineRouteHelpersFactory } from '../../utils';
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context';
|
||||
|
||||
|
@ -70,7 +71,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const indexTemplateName = '.risk-score.risk-score-default-index-template';
|
||||
const dataStreamName = 'risk-score.risk-score-default';
|
||||
const latestIndexName = 'risk-score.risk-score-latest-default';
|
||||
const transformId = 'risk_score_latest_transform_default';
|
||||
const transformId = getLatestTransformId('default');
|
||||
const defaultPipeline =
|
||||
'entity_analytics_create_eventIngest_from_timestamp-pipeline-default';
|
||||
|
||||
|
@ -350,7 +351,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
const indexTemplateName = `.risk-score.risk-score-${customSpaceName}-index-template`;
|
||||
const dataStreamName = `risk-score.risk-score-${customSpaceName}`;
|
||||
const latestIndexName = `risk-score.risk-score-latest-${customSpaceName}`;
|
||||
const transformId = `risk_score_latest_transform_${customSpaceName}`;
|
||||
const transformId = getLatestTransformId(customSpaceName);
|
||||
const defaultPipeline = `entity_analytics_create_eventIngest_from_timestamp-pipeline-${customSpaceName}`;
|
||||
|
||||
await riskEngineRoutesWithNamespace.init();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue