Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
db444a9
small refactor
semd Jul 23, 2025
51779a1
rely on (safe) mutations
semd Jul 23, 2025
3c86d37
Merge remote-tracking branch 'upstream/main' into security_solution/p…
semd Jul 24, 2025
7208422
code simplification
semd Jul 24, 2025
3b82104
fix types
semd Jul 24, 2025
03c3738
[CI] Auto-commit changed files from 'node scripts/eslint_all_files --…
kibanamachine Jul 24, 2025
d42f705
service complexity reduction
semd Jul 25, 2025
e8f24a3
solve conflict
semd Jul 25, 2025
b7b9776
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Jul 25, 2025
14def6c
simplify offering product features configs
semd Jul 25, 2025
ab7f382
improve helper to create map and add test
semd Jul 28, 2025
a1bb73f
[CI] Auto-commit changed files from 'node scripts/eslint_all_files --…
kibanamachine Jul 28, 2025
7d340bd
fix lint issue
semd Jul 28, 2025
e72ec96
Merge remote-tracking branch 'refs/remotes/origin/security_solution/p…
semd Jul 28, 2025
a9f1c32
add tests
semd Jul 29, 2025
e7666ae
Merge remote-tracking branch 'upstream/main' into security_solution/p…
semd Jul 29, 2025
971f22b
add tests for the features modifiers in ess and serverless
semd Jul 29, 2025
37170ca
implement extensions
semd Jul 30, 2025
f75c9c0
fix tests
semd Jul 31, 2025
5da1359
unify sub-features version config
semd Jul 31, 2025
1d81120
clean old files
semd Jul 31, 2025
bb421ae
tests fixed
semd Jul 31, 2025
2c406bc
feature utils
semd Jul 31, 2025
beb3ba3
Merge remote-tracking branch 'upstream/main' into security_solution/p…
semd Jul 31, 2025
b2a2288
set require all spaces correctly
semd Jul 31, 2025
a8e654a
extend subFeatures with gwriteGlobalArtifact
semd Aug 1, 2025
b33a8cb
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 1, 2025
8a7ed50
cleaning test
semd Aug 1, 2025
b2b76e0
fix mock
semd Aug 1, 2025
146e807
update snapshot
semd Aug 1, 2025
a2f2d10
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 8, 2025
b2d1fa6
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 12, 2025
af31727
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 21, 2025
62f9888
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 21, 2025
f5e4f15
change `featureConfigModifier` to an array
gergoabraham Aug 22, 2025
58f6031
rename `skipPrivilegeCopy` to `removeOriginalPrivileges` for clarity …
gergoabraham Aug 22, 2025
9f6667c
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 22, 2025
5e51bd8
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 25, 2025
04d4700
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 26, 2025
51c7b1f
Merge branch 'main' into security_solution/product_features_custom_co…
gergoabraham Aug 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/platform/packages/shared/kbn-utility-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ export type PublicMethodsOf<T> = Pick<T, MethodKeysOf<T>>;
export type Writable<T> = {
-readonly [K in keyof T]: T[K];
};
/**
* Makes an object with readonly properties mutable.
*/
export type RecursiveWritable<T> = {
-readonly [K in keyof T]: RecursiveWritable<T[K]>;
};

/**
* XOR for some properties applied to a type
Expand Down
16 changes: 0 additions & 16 deletions x-pack/solutions/security/packages/features/config.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { AssistantSubFeatureId } from '../product_features_keys';
import type { AssistantSubFeatureId, ProductFeatureAssistantKey } from '../product_features_keys';
import type { ProductFeatureParams } from '../types';
import { getAssistantBaseKibanaFeature } from './kibana_features';
import {
getAssistantBaseKibanaSubFeatureIds,
getAssistantSubFeaturesMap,
} from './kibana_sub_features';
import { assistantProductFeaturesConfig } from './product_feature_config';

export const getAssistantFeature = (
experimentalFeatures: Record<string, boolean>
): ProductFeatureParams<AssistantSubFeatureId> => ({
): ProductFeatureParams<ProductFeatureAssistantKey, AssistantSubFeatureId> => ({
baseKibanaFeature: getAssistantBaseKibanaFeature(),
baseKibanaSubFeatureIds: getAssistantBaseKibanaSubFeatureIds(),
subFeaturesMap: getAssistantSubFeaturesMap(experimentalFeatures),
productFeatureConfig: assistantProductFeaturesConfig,
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,11 @@
*/

import { AssistantSubFeatureId, ProductFeatureAssistantKey } from '../product_features_keys';
import type { ProductFeatureKibanaConfig } from '../types';
import type { ProductFeaturesConfig } from '../types';

/**
* App features privileges configuration for the Security Assistant Kibana Feature app.
* These are the configs that are shared between both offering types (ess and serverless).
* They can be extended on each offering plugin to register privileges using different way on each offering type.
*
* Privileges can be added in different ways:
* - `privileges`: the privileges that will be added directly into the main Security feature.
* - `subFeatureIds`: the ids of the sub-features that will be added into the Security subFeatures entry.
* - `subFeaturesPrivileges`: the privileges that will be added into the existing Security subFeature with the privilege `id` specified.
*/
export const assistantDefaultProductFeaturesConfig: Record<
export const assistantProductFeaturesConfig: ProductFeaturesConfig<
ProductFeatureAssistantKey,
ProductFeatureKibanaConfig<AssistantSubFeatureId>
AssistantSubFeatureId
> = {
[ProductFeatureAssistantKey.assistant]: {
privileges: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

import { getAttackDiscoveryBaseKibanaFeature } from './kibana_features';
import type { ProductFeatureParams } from '../types';
import { attackDiscoveryProductFeaturesConfig } from './product_feature_config';
import type { ProductFeatureAttackDiscoveryKey } from '../product_features_keys';

export const getAttackDiscoveryFeature = (): ProductFeatureParams => ({
baseKibanaFeature: getAttackDiscoveryBaseKibanaFeature(),
baseKibanaSubFeatureIds: [],
subFeaturesMap: new Map(),
});
export const getAttackDiscoveryFeature =
(): ProductFeatureParams<ProductFeatureAttackDiscoveryKey> => ({
baseKibanaFeature: getAttackDiscoveryBaseKibanaFeature(),
productFeatureConfig: attackDiscoveryProductFeaturesConfig,
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,16 @@
*/

import { ProductFeatureAttackDiscoveryKey } from '../product_features_keys';
import type { ProductFeatureKibanaConfig } from '../types';
import type { ProductFeaturesConfig } from '../types';

/**
* App features privileges configuration for the Attack discovery feature.
* These are the configs that are shared between both offering types (ess and serverless).
* They can be extended on each offering plugin to register privileges using different way on each offering type.
*
* Privileges can be added in different ways:
* - `privileges`: the privileges that will be added directly into the main Security feature.
* - `subFeatureIds`: the ids of the sub-features that will be added into the Security subFeatures entry.
* - `subFeaturesPrivileges`: the privileges that will be added into the existing Security subFeature with the privilege `id` specified.
*/
export const attackDiscoveryDefaultProductFeaturesConfig: Record<
ProductFeatureAttackDiscoveryKey,
ProductFeatureKibanaConfig
> = {
[ProductFeatureAttackDiscoveryKey.attackDiscovery]: {
privileges: {
all: {
ui: ['attack-discovery'],
export const attackDiscoveryProductFeaturesConfig: ProductFeaturesConfig<ProductFeatureAttackDiscoveryKey> =
{
[ProductFeatureAttackDiscoveryKey.attackDiscovery]: {
privileges: {
all: {
ui: ['attack-discovery'],
},
},
subFeatureIds: [],
},
subFeatureIds: [],
},
};
};
23 changes: 12 additions & 11 deletions x-pack/solutions/security/packages/features/src/cases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { CasesSubFeatureId } from '../product_features_keys';
import type { CasesSubFeatureId, ProductFeatureCasesKey } from '../product_features_keys';
import type { ProductFeatureParams } from '../types';
import { getCasesBaseKibanaFeature } from './v1_features/kibana_features';
import {
getCasesBaseKibanaSubFeatureIds,
getCasesSubFeaturesMap,
getCasesBaseKibanaSubFeatureIdsV1,
getCasesSubFeaturesMapV1,
} from './v1_features/kibana_sub_features';
import type { CasesFeatureParams } from './types';
import { getCasesBaseKibanaFeatureV2 } from './v2_features/kibana_features';
Expand All @@ -22,30 +22,31 @@ import {
getCasesBaseKibanaSubFeatureIdsV3,
getCasesSubFeaturesMapV3,
} from './v3_features/kibana_sub_features';
import { getCasesProductFeaturesConfig } from './product_feature_config';

/**
* @deprecated Use getCasesV2Feature instead
*/
export const getCasesFeature = (
params: CasesFeatureParams
): ProductFeatureParams<CasesSubFeatureId> => ({
): ProductFeatureParams<ProductFeatureCasesKey, CasesSubFeatureId> => ({
baseKibanaFeature: getCasesBaseKibanaFeature(params),
baseKibanaSubFeatureIds: getCasesBaseKibanaSubFeatureIds(),
subFeaturesMap: getCasesSubFeaturesMap(params),
baseKibanaSubFeatureIds: getCasesBaseKibanaSubFeatureIdsV1(),
subFeaturesMap: getCasesSubFeaturesMapV1(params),
productFeatureConfig: getCasesProductFeaturesConfig(params),
});

export const getCasesV2Feature = (
params: CasesFeatureParams
): ProductFeatureParams<CasesSubFeatureId> => ({
): ProductFeatureParams<ProductFeatureCasesKey, CasesSubFeatureId> => ({
baseKibanaFeature: getCasesBaseKibanaFeatureV2(params),
baseKibanaSubFeatureIds: getCasesBaseKibanaSubFeatureIdsV2(),
subFeaturesMap: getCasesSubFeaturesMapV2(params),
productFeatureConfig: getCasesProductFeaturesConfig(params),
});

export const getCasesV3Feature = (
params: CasesFeatureParams
): ProductFeatureParams<CasesSubFeatureId> => ({
): ProductFeatureParams<ProductFeatureCasesKey, CasesSubFeatureId> => ({
baseKibanaFeature: getCasesBaseKibanaFeatureV3(params),
baseKibanaSubFeatureIds: getCasesBaseKibanaSubFeatureIdsV3(),
subFeaturesMap: getCasesSubFeaturesMapV3(params),
productFeatureConfig: getCasesProductFeaturesConfig(params),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* 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 { i18n } from '@kbn/i18n';
import type { SubFeatureConfig } from '@kbn/features-plugin/common';
import { APP_ID } from '../constants';
import type { CasesFeatureParams } from './types';

export const getDeleteCasesSubFeature = ({
apiTags,
uiCapabilities,
savedObjects,
}: CasesFeatureParams): SubFeatureConfig => ({
name: i18n.translate('securitySolutionPackages.features.featureRegistry.deleteSubFeatureName', {
defaultMessage: 'Delete',
}),
privilegeGroups: [
{
groupType: 'independent',
privileges: [
{
api: apiTags.default.delete,
id: 'cases_delete',
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.deleteSubFeatureDetails',
{ defaultMessage: 'Delete cases and comments' }
),
includeIn: 'all',
savedObject: {
all: [...savedObjects.files],
read: [...savedObjects.files],
},
cases: {
delete: [APP_ID],
},
ui: uiCapabilities.default.delete,
},
],
},
],
});

export const getCasesSettingsCasesSubFeature = ({
uiCapabilities,
savedObjects,
}: CasesFeatureParams): SubFeatureConfig => ({
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureName',
{ defaultMessage: 'Case settings' }
),
privilegeGroups: [
{
groupType: 'independent',
privileges: [
{
id: 'cases_settings',
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureDetails',
{ defaultMessage: 'Edit case settings' }
),
includeIn: 'all',
savedObject: {
all: [...savedObjects.files],
read: [...savedObjects.files],
},
cases: {
settings: [APP_ID],
},
ui: uiCapabilities.default.settings,
},
],
},
],
});

export const getCasesAddCommentsCasesSubFeature = ({
apiTags,
uiCapabilities,
savedObjects,
}: CasesFeatureParams): SubFeatureConfig => ({
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.addCommentsSubFeatureName',
{ defaultMessage: 'Create comments & attachments' }
),
privilegeGroups: [
{
groupType: 'independent',
privileges: [
{
api: apiTags.default.createComment,
id: 'create_comment',
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.addCommentsSubFeatureDetails',
{ defaultMessage: 'Add comments to cases' }
),
includeIn: 'all',
savedObject: {
all: [...savedObjects.files],
read: [...savedObjects.files],
},
cases: {
createComment: [APP_ID],
},
ui: uiCapabilities.default.createComment,
},
],
},
],
});

export const getCasesReopenCaseSubFeature = ({
uiCapabilities,
}: CasesFeatureParams): SubFeatureConfig => ({
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.reopenCaseSubFeatureName',
{ defaultMessage: 'Re-open' }
),
privilegeGroups: [
{
groupType: 'independent',
privileges: [
{
id: 'case_reopen',
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.reopenCaseSubFeatureDetails',
{ defaultMessage: 'Re-open closed cases' }
),
includeIn: 'all',
savedObject: {
all: [],
read: [],
},
cases: {
reopenCase: [APP_ID],
},
ui: uiCapabilities.default.reopenCase,
},
],
},
],
});

export const getCasesAssignUsersCasesSubFeature = ({
uiCapabilities,
}: CasesFeatureParams): SubFeatureConfig => ({
name: i18n.translate('securitySolutionPackages.features.assignUsersSubFeatureName', {
defaultMessage: 'Assign users',
}),
privilegeGroups: [
{
groupType: 'independent',
privileges: [
{
id: 'cases_assign',
name: i18n.translate('securitySolutionPackages.features.assignUsersSubFeatureName', {
defaultMessage: 'Assign users to cases',
}),
includeIn: 'all',
savedObject: {
all: [],
read: [],
},
cases: {
assign: [APP_ID],
},
ui: uiCapabilities.default.assignCase,
},
],
},
],
});
Loading