Skip to content

Commit

Permalink
[8.x] [EDR Workflows] Workflow Insights - RBAC (#205088) (#205684)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [[EDR Workflows] Workflow Insights - RBAC
(#205088)](#205088)

<!--- Backport version: 9.4.3 -->

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

<!--BACKPORT [{"author":{"name":"Konrad
Szwarc","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-01-07T09:33:25Z","message":"[EDR
Workflows] Workflow Insights - RBAC (#205088)\n\n## Access Control for
Endpoint Workflow Insights\r\n\r\nThis PR adds access control to the
Endpoint Workflow Insights\r\nfunctionality. Both the UI and API are
gated based on the following\r\nconditions. If these conditions are not
met, the content will not\r\nrender, and direct API calls will return
errors.\r\n\r\nAccess Conditions\r\n```\r\n1. Serverless: Requires the
Endpoint Complete Tier.\r\n2. ESS: Requires an Enterprise License.\r\n3.
User Privileges:\r\n 3.1 Endpoint Insights Privilege must be
enabled:\r\n 3.1.1 Endpoint Insights All: Grants full access.\r\n\t3.1.2
Endpoint Insights Read:\r\n\t 3.1.2.1 Allows users to view generated
insights but prevents triggering new scans.\r\n\t 3.1.2.2 With Trusted
Applications privilege: Users can remediate already generated
insights.\r\n\t 3.1.2.3 Without Trusted Applications privilege: No
actions can be taken.\r\n\t3.1.3Endpoint Insights None: The section is
not rendered.\r\n```\r\n\r\nPredefined serverless roles that should
include endpoint insights\r\nprivilege(as
defined\r\n[here](https://github.com/elastic/security-team/issues/11460)):\r\n-
Tier 3 analyst\r\n- Rule Author\r\n- SOC Manager\r\n- Endpoint
Operations Analyst\r\n- Endpoint Policy Manager\r\n- Platform
Engineer\r\n\r\nOnce this PR is merged and changes make it to canary
release,
[this\r\nfollow-up\r\nPR](elastic/elasticsearch-controller#816)
should\r\nbe merged.\r\n\r\nNote on Testing and Local Setup\r\n\r\nTo
test these changes locally, the `defendInsights` assistant
feature\r\nmust be enabled. You can do this by updating the following
line in the\r\ncode: [Enable
defendInsights\r\nhere](https://github.com/elastic/kibana/blob/2ae68bdaac180c62750798c148bed4fd01de07fe/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts#L23).\r\n\r\nCypress
Tests\r\n\r\nCypress tests in this PR are currently skipped because
the\r\n`defendInsights` feature is not enabled by default. These tests
should\r\nbe enabled once the feature is turned on in the main branch.
Successful\r\nrun with all cypress tests enabled can be
found\r\n[here](https://buildkite.com/elastic/kibana-pull-request/builds/262774#0193f3c2-eddd-48b6-9103-fb7338304f15).\r\n\r\n<details>\r\n<summary>Screenshots</summary>\r\n\r\n\r\n![396870292-b5bbedad-330f-4ef5-8281-29699cf01a98](https://github.com/user-attachments/assets/586745d4-9e8d-42b4-8d70-e32737285f5c)\r\n\r\n![b](https://github.com/user-attachments/assets/0926b696-37ef-48e8-9dfb-d6f735033583)\r\n\r\n![a](https://github.com/user-attachments/assets/afa799bd-7e07-4a1a-b63e-6448ae56b21a)\r\n\r\n![c](https://github.com/user-attachments/assets/cc3a2e07-0955-4348-a954-1914c5a85e81)\r\n![Screenshot
2024-12-23 at 13
32\r\n57](https://github.com/user-attachments/assets/fbb28bce-eedd-4a6e-85c3-b2a07f40ab27)\r\n</details>\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"2f61892e84b31ebd4774cae2686ebd6c4c2cab89","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Fleet","v9.0.0","Team:Defend
Workflows","backport:prev-minor","v8.18.0"],"title":"[EDR Workflows]
Workflow Insights - RBAC
","number":205088,"url":"https://github.com/elastic/kibana/pull/205088","mergeCommit":{"message":"[EDR
Workflows] Workflow Insights - RBAC (#205088)\n\n## Access Control for
Endpoint Workflow Insights\r\n\r\nThis PR adds access control to the
Endpoint Workflow Insights\r\nfunctionality. Both the UI and API are
gated based on the following\r\nconditions. If these conditions are not
met, the content will not\r\nrender, and direct API calls will return
errors.\r\n\r\nAccess Conditions\r\n```\r\n1. Serverless: Requires the
Endpoint Complete Tier.\r\n2. ESS: Requires an Enterprise License.\r\n3.
User Privileges:\r\n 3.1 Endpoint Insights Privilege must be
enabled:\r\n 3.1.1 Endpoint Insights All: Grants full access.\r\n\t3.1.2
Endpoint Insights Read:\r\n\t 3.1.2.1 Allows users to view generated
insights but prevents triggering new scans.\r\n\t 3.1.2.2 With Trusted
Applications privilege: Users can remediate already generated
insights.\r\n\t 3.1.2.3 Without Trusted Applications privilege: No
actions can be taken.\r\n\t3.1.3Endpoint Insights None: The section is
not rendered.\r\n```\r\n\r\nPredefined serverless roles that should
include endpoint insights\r\nprivilege(as
defined\r\n[here](https://github.com/elastic/security-team/issues/11460)):\r\n-
Tier 3 analyst\r\n- Rule Author\r\n- SOC Manager\r\n- Endpoint
Operations Analyst\r\n- Endpoint Policy Manager\r\n- Platform
Engineer\r\n\r\nOnce this PR is merged and changes make it to canary
release,
[this\r\nfollow-up\r\nPR](elastic/elasticsearch-controller#816)
should\r\nbe merged.\r\n\r\nNote on Testing and Local Setup\r\n\r\nTo
test these changes locally, the `defendInsights` assistant
feature\r\nmust be enabled. You can do this by updating the following
line in the\r\ncode: [Enable
defendInsights\r\nhere](https://github.com/elastic/kibana/blob/2ae68bdaac180c62750798c148bed4fd01de07fe/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts#L23).\r\n\r\nCypress
Tests\r\n\r\nCypress tests in this PR are currently skipped because
the\r\n`defendInsights` feature is not enabled by default. These tests
should\r\nbe enabled once the feature is turned on in the main branch.
Successful\r\nrun with all cypress tests enabled can be
found\r\n[here](https://buildkite.com/elastic/kibana-pull-request/builds/262774#0193f3c2-eddd-48b6-9103-fb7338304f15).\r\n\r\n<details>\r\n<summary>Screenshots</summary>\r\n\r\n\r\n![396870292-b5bbedad-330f-4ef5-8281-29699cf01a98](https://github.com/user-attachments/assets/586745d4-9e8d-42b4-8d70-e32737285f5c)\r\n\r\n![b](https://github.com/user-attachments/assets/0926b696-37ef-48e8-9dfb-d6f735033583)\r\n\r\n![a](https://github.com/user-attachments/assets/afa799bd-7e07-4a1a-b63e-6448ae56b21a)\r\n\r\n![c](https://github.com/user-attachments/assets/cc3a2e07-0955-4348-a954-1914c5a85e81)\r\n![Screenshot
2024-12-23 at 13
32\r\n57](https://github.com/user-attachments/assets/fbb28bce-eedd-4a6e-85c3-b2a07f40ab27)\r\n</details>\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"2f61892e84b31ebd4774cae2686ebd6c4c2cab89"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/205088","number":205088,"mergeCommit":{"message":"[EDR
Workflows] Workflow Insights - RBAC (#205088)\n\n## Access Control for
Endpoint Workflow Insights\r\n\r\nThis PR adds access control to the
Endpoint Workflow Insights\r\nfunctionality. Both the UI and API are
gated based on the following\r\nconditions. If these conditions are not
met, the content will not\r\nrender, and direct API calls will return
errors.\r\n\r\nAccess Conditions\r\n```\r\n1. Serverless: Requires the
Endpoint Complete Tier.\r\n2. ESS: Requires an Enterprise License.\r\n3.
User Privileges:\r\n 3.1 Endpoint Insights Privilege must be
enabled:\r\n 3.1.1 Endpoint Insights All: Grants full access.\r\n\t3.1.2
Endpoint Insights Read:\r\n\t 3.1.2.1 Allows users to view generated
insights but prevents triggering new scans.\r\n\t 3.1.2.2 With Trusted
Applications privilege: Users can remediate already generated
insights.\r\n\t 3.1.2.3 Without Trusted Applications privilege: No
actions can be taken.\r\n\t3.1.3Endpoint Insights None: The section is
not rendered.\r\n```\r\n\r\nPredefined serverless roles that should
include endpoint insights\r\nprivilege(as
defined\r\n[here](https://github.com/elastic/security-team/issues/11460)):\r\n-
Tier 3 analyst\r\n- Rule Author\r\n- SOC Manager\r\n- Endpoint
Operations Analyst\r\n- Endpoint Policy Manager\r\n- Platform
Engineer\r\n\r\nOnce this PR is merged and changes make it to canary
release,
[this\r\nfollow-up\r\nPR](elastic/elasticsearch-controller#816)
should\r\nbe merged.\r\n\r\nNote on Testing and Local Setup\r\n\r\nTo
test these changes locally, the `defendInsights` assistant
feature\r\nmust be enabled. You can do this by updating the following
line in the\r\ncode: [Enable
defendInsights\r\nhere](https://github.com/elastic/kibana/blob/2ae68bdaac180c62750798c148bed4fd01de07fe/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts#L23).\r\n\r\nCypress
Tests\r\n\r\nCypress tests in this PR are currently skipped because
the\r\n`defendInsights` feature is not enabled by default. These tests
should\r\nbe enabled once the feature is turned on in the main branch.
Successful\r\nrun with all cypress tests enabled can be
found\r\n[here](https://buildkite.com/elastic/kibana-pull-request/builds/262774#0193f3c2-eddd-48b6-9103-fb7338304f15).\r\n\r\n<details>\r\n<summary>Screenshots</summary>\r\n\r\n\r\n![396870292-b5bbedad-330f-4ef5-8281-29699cf01a98](https://github.com/user-attachments/assets/586745d4-9e8d-42b4-8d70-e32737285f5c)\r\n\r\n![b](https://github.com/user-attachments/assets/0926b696-37ef-48e8-9dfb-d6f735033583)\r\n\r\n![a](https://github.com/user-attachments/assets/afa799bd-7e07-4a1a-b63e-6448ae56b21a)\r\n\r\n![c](https://github.com/user-attachments/assets/cc3a2e07-0955-4348-a954-1914c5a85e81)\r\n![Screenshot
2024-12-23 at 13
32\r\n57](https://github.com/user-attachments/assets/fbb28bce-eedd-4a6e-85c3-b2a07f40ab27)\r\n</details>\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"2f61892e84b31ebd4774cae2686ebd6c4c2cab89"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Konrad Szwarc <[email protected]>
  • Loading branch information
kibanamachine and szwarckonrad authored Jan 7, 2025
1 parent 9e2e935 commit e723e75
Show file tree
Hide file tree
Showing 40 changed files with 691 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ t3_analyst:
- feature_siem.actions_log_management_all # Response actions history
- feature_siem.file_operations_all
- feature_siem.scan_operations_all
- feature_siem.workflow_insights_all
- feature_securitySolutionCasesV2.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
Expand Down Expand Up @@ -430,6 +431,7 @@ rule_author:
- feature_siem.host_isolation_exceptions_read
- feature_siem.blocklist_all # Elastic Defend Policy Management
- feature_siem.actions_log_management_read
- feature_siem.workflow_insights_all
- feature_securitySolutionCasesV2.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
Expand Down Expand Up @@ -502,6 +504,7 @@ soc_manager:
- feature_siem.file_operations_all
- feature_siem.execute_operations_all
- feature_siem.scan_operations_all
- feature_siem.workflow_insights_all
- feature_securitySolutionCasesV2.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
Expand Down Expand Up @@ -621,6 +624,7 @@ platform_engineer:
- feature_siem.host_isolation_exceptions_all
- feature_siem.blocklist_all # Elastic Defend Policy Management
- feature_siem.actions_log_management_read
- feature_siem.workflow_insights_all
- feature_securitySolutionCasesV2.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
Expand Down Expand Up @@ -694,6 +698,7 @@ endpoint_operations_analyst:
- feature_siem.file_operations_all
- feature_siem.execute_operations_all
- feature_siem.scan_operations_all
- feature_siem.workflow_insights_all
- feature_securitySolutionCasesV2.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
Expand Down Expand Up @@ -769,6 +774,7 @@ endpoint_policy_manager:
- feature_siem.event_filters_all
- feature_siem.host_isolation_exceptions_all
- feature_siem.blocklist_all # Elastic Defend Policy Management
- feature_siem.workflow_insights_all
- feature_securitySolutionCasesV2.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
Expand Down
12 changes: 12 additions & 0 deletions x-pack/platform/plugins/shared/fleet/common/constants/authz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,18 @@ export const ENDPOINT_PRIVILEGES: Record<string, PrivilegeMapObject> = deepFreez
privilegeType: 'api',
privilegeName: 'writeScanOperations',
},
writeWorkflowInsights: {
appId: DEFAULT_APP_CATEGORIES.security.id,
privilegeSplit: '-',
privilegeType: 'api',
privilegeName: 'writeWorkflowInsights',
},
readWorkflowInsights: {
appId: DEFAULT_APP_CATEGORIES.security.id,
privilegeSplit: '-',
privilegeType: 'api',
privilegeName: 'readWorkflowInsights',
},
});

export const ENDPOINT_EXCEPTIONS_PRIVILEGES: Record<string, PrivilegeMapObject> = deepFreeze({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export enum ProductFeatureSecurityKey {
* enables the integration assistant
*/
integrationAssistant = 'integration_assistant',

/** Enables Endpoint Workflow Insights */
securityWorkflowInsights = 'security_workflow_insights',
}

export enum ProductFeatureCasesKey {
Expand Down Expand Up @@ -137,6 +140,7 @@ export enum SecuritySubFeatureId {
eventFilters = 'eventFiltersSubFeature',
policyManagement = 'policyManagementSubFeature',
responseActionsHistory = 'responseActionsHistorySubFeature',
workflowInsights = 'workflowInsightsSubFeature',
hostIsolation = 'hostIsolationSubFeature',
processOperations = 'processOperationsSubFeature',
fileOperations = 'fileOperationsSubFeature',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,58 @@ const scanActionSubFeature = (): SubFeatureConfig => ({
],
});

const workflowInsightsSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.workflowInsights.privilegesTooltip',
{
defaultMessage: 'All Spaces is required for Endpoint Insights access.',
}
),
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.workflowInsights',
{
defaultMessage: 'Endpoint Insights',
}
),
description: i18n.translate(
'securitySolutionPackages.features.featureRegistry.subFeatures.workflowInsights.description',
{
defaultMessage: 'Access the endpoint insights.',
}
),

privilegeGroups: [
{
groupType: 'mutually_exclusive',
privileges: [
{
api: [`${APP_ID}-writeWorkflowInsights`, `${APP_ID}-readWorkflowInsights`],
id: 'workflow_insights_all',
includeIn: 'none',
name: 'All',
savedObject: {
all: [],
read: [],
},
ui: ['writeWorkflowInsights', 'readWorkflowInsights'],
},
{
api: [`${APP_ID}-readWorkflowInsights`],
id: 'workflow_insights_read',
includeIn: 'none',
name: 'Read',
savedObject: {
all: [],
read: [],
},
ui: ['readWorkflowInsights'],
},
],
},
],
});

const endpointExceptionsSubFeature = (): SubFeatureConfig => ({
requireAllSpaces: true,
privilegesTooltip: i18n.translate(
Expand Down Expand Up @@ -709,6 +761,14 @@ export const getSecuritySubFeaturesMap = ({
// securitySubFeaturesList.push([SecuritySubFeatureId.featureId, featureSubFeature]);
// }

if (experimentalFeatures.defendInsights) {
// place with other All/Read/None options
securitySubFeaturesList.splice(1, 0, [
SecuritySubFeatureId.workflowInsights,
enableSpaceAwarenessIfNeeded(workflowInsightsSubFeature()),
]);
}

const securitySubFeaturesMap = new Map<SecuritySubFeatureId, SubFeatureConfig>(
securitySubFeaturesList
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ export const securityDefaultProductFeaturesConfig: DefaultSecurityProductFeature
],
},

[ProductFeatureSecurityKey.securityWorkflowInsights]: {
subFeatureIds: [SecuritySubFeatureId.workflowInsights],
},
// Product features without RBAC
// Endpoint/Osquery PLIs
[ProductFeatureSecurityKey.osqueryAutomatedResponseActions]: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { serverMock } from '../../__mocks__/server';
import { isDefendInsightsEnabled, updateDefendInsightLastViewedAt } from './helpers';
import { getDefendInsightRoute } from './get_defend_insight';
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';

jest.mock('./helpers');

Expand Down Expand Up @@ -73,6 +74,20 @@ describe('getDefendInsightRoute', () => {
jest.clearAllMocks();
});

it('Insufficient license', async () => {
const insufficientLicense = licensingMock.createLicense({ license: { type: 'basic' } });
const tools = requestContextMock.createTools();
tools.context.licensing.license = insufficientLicense;
jest.spyOn(insufficientLicense, 'hasAtLeast').mockReturnValue(false);

await expect(
server.inject(
getDefendInsightRequest('insight-id1'),
requestContextMock.convertContext(tools.context)
)
).rejects.toThrowError('Encountered unexpected call to response.forbidden');
});

it('should handle successful request', async () => {
const response = await server.inject(
getDefendInsightRequest('insight-id1'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getDefendInsightRoute = (router: IRouter<ElasticAssistantRequestHan
path: DEFEND_INSIGHTS_BY_ID,
security: {
authz: {
requiredPrivileges: ['elasticAssistant'],
requiredPrivileges: ['securitySolution-readWorkflowInsights'],
},
},
})
Expand All @@ -48,7 +48,9 @@ export const getDefendInsightRoute = (router: IRouter<ElasticAssistantRequestHan
},
async (context, request, response): Promise<IKibanaResponse<DefendInsightGetResponse>> => {
const resp = buildResponse(response);
const assistantContext = await context.elasticAssistant;
const ctx = await context.resolve(['licensing', 'elasticAssistant']);

const assistantContext = ctx.elasticAssistant;
const logger: Logger = assistantContext.logger;
try {
const isEnabled = isDefendInsightsEnabled({
Expand All @@ -60,6 +62,15 @@ export const getDefendInsightRoute = (router: IRouter<ElasticAssistantRequestHan
return response.notFound();
}

if (!ctx.licensing.license.hasAtLeast('enterprise')) {
return response.forbidden({
body: {
message:
'Your license does not support Defend Workflows. Please upgrade your license.',
},
});
}

const dataClient = await assistantContext.getDefendInsightsDataClient();
const authenticatedUser = assistantContext.getCurrentUser();
if (authenticatedUser == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { serverMock } from '../../__mocks__/server';
import { isDefendInsightsEnabled, updateDefendInsightsLastViewedAt } from './helpers';
import { getDefendInsightsRoute } from './get_defend_insights';
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';

jest.mock('./helpers');

Expand Down Expand Up @@ -73,6 +74,20 @@ describe('getDefendInsightsRoute', () => {
jest.clearAllMocks();
});

it('Insufficient license', async () => {
const insufficientLicense = licensingMock.createLicense({ license: { type: 'basic' } });
const tools = requestContextMock.createTools();
tools.context.licensing.license = insufficientLicense;
jest.spyOn(insufficientLicense, 'hasAtLeast').mockReturnValue(false);

await expect(
server.inject(
getDefendInsightsRequest({ connector_id: 'connector-id1' }),
requestContextMock.convertContext(tools.context)
)
).rejects.toThrowError('Encountered unexpected call to response.forbidden');
});

it('should handle successful request', async () => {
const response = await server.inject(
getDefendInsightsRequest({ connector_id: 'connector-id1' }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getDefendInsightsRoute = (router: IRouter<ElasticAssistantRequestHa
path: DEFEND_INSIGHTS,
security: {
authz: {
requiredPrivileges: ['elasticAssistant'],
requiredPrivileges: ['securitySolution-readWorkflowInsights'],
},
},
})
Expand All @@ -48,8 +48,12 @@ export const getDefendInsightsRoute = (router: IRouter<ElasticAssistantRequestHa
},
async (context, request, response): Promise<IKibanaResponse<DefendInsightsGetResponse>> => {
const resp = buildResponse(response);
const assistantContext = await context.elasticAssistant;

const ctx = await context.resolve(['licensing', 'elasticAssistant']);

const assistantContext = ctx.elasticAssistant;
const logger: Logger = assistantContext.logger;

try {
const isEnabled = isDefendInsightsEnabled({
request,
Expand All @@ -60,6 +64,15 @@ export const getDefendInsightsRoute = (router: IRouter<ElasticAssistantRequestHa
return response.notFound();
}

if (!ctx.licensing.license.hasAtLeast('enterprise')) {
return response.forbidden({
body: {
message:
'Your license does not support Defend Workflows. Please upgrade your license.',
},
});
}

const dataClient = await assistantContext.getDefendInsightsDataClient();

const authenticatedUser = assistantContext.getCurrentUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { getDefendInsightsSearchEsMock } from '../../__mocks__/defend_insights_s
import { postDefendInsightsRequest } from '../../__mocks__/request';
import { getAssistantTool, createDefendInsight, isDefendInsightsEnabled } from './helpers';
import { postDefendInsightsRoute } from './post_defend_insights';
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';

jest.mock('./helpers');

Expand Down Expand Up @@ -111,6 +112,20 @@ describe('postDefendInsightsRoute', () => {
jest.clearAllMocks();
});

it('Insufficient license', async () => {
const insufficientLicense = licensingMock.createLicense({ license: { type: 'basic' } });
const tools = requestContextMock.createTools();
tools.context.licensing.license = insufficientLicense;
jest.spyOn(insufficientLicense, 'hasAtLeast').mockReturnValue(false);

await expect(
server.inject(
postDefendInsightsRequest(mockRequestBody),
requestContextMock.convertContext(tools.context)
)
).rejects.toThrowError('Encountered unexpected call to response.forbidden');
});

it('should handle successful request', async () => {
const response = await server.inject(
postDefendInsightsRequest(mockRequestBody),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const postDefendInsightsRoute = (router: IRouter<ElasticAssistantRequestH
},
security: {
authz: {
requiredPrivileges: ['elasticAssistant'],
requiredPrivileges: ['securitySolution-writeWorkflowInsights'],
},
},
})
Expand All @@ -69,7 +69,11 @@ export const postDefendInsightsRoute = (router: IRouter<ElasticAssistantRequestH
async (context, request, response): Promise<IKibanaResponse<DefendInsightsPostResponse>> => {
const startTime = moment(); // start timing the generation
const resp = buildResponse(response);
const assistantContext = await context.elasticAssistant;

const ctx = await context.resolve(['licensing', 'elasticAssistant']);

const assistantContext = ctx.elasticAssistant;

const logger: Logger = assistantContext.logger;
const telemetry = assistantContext.telemetry;

Expand All @@ -83,6 +87,15 @@ export const postDefendInsightsRoute = (router: IRouter<ElasticAssistantRequestH
return response.notFound();
}

if (!ctx.licensing.license.hasAtLeast('enterprise')) {
return response.forbidden({
body: {
message:
'Your license does not support Defend Workflows. Please upgrade your license.',
},
});
}

const actions = assistantContext.actions;
const actionsClient = await actions.getActionsClientWithRequest(request);
const dataClient = await assistantContext.getDefendInsightsDataClient();
Expand Down
Loading

0 comments on commit e723e75

Please sign in to comment.