Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ResponseOps][Rules] Fix case action templates in stack for security serverless #195763

Merged
merged 6 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react
import { useGetAllCaseConfigurations } from '../../../containers/configure/use_get_all_case_configurations';
import { useGetAllCaseConfigurationsResponse } from '../../configure_cases/__mock__';
import { templatesConfigurationMock } from '../../../containers/mock';
import * as utils from '../../../containers/configure/utils';

jest.mock('@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view');
jest.mock('../../../common/lib/kibana/use_application');
Expand All @@ -29,10 +30,6 @@ const useAlertsDataViewMock = jest.mocked(useAlertsDataView);
const useApplicationMock = useApplication as jest.Mock;
const useGetAllCaseConfigurationsMock = useGetAllCaseConfigurations as jest.Mock;

useKibanaMock.mockReturnValue({
services: { ...createStartServicesMock(), data: { dataViews: {} } },
} as unknown as ReturnType<typeof useKibana>);

const actionParams = {
subAction: 'run',
subActionParams: {
Expand Down Expand Up @@ -98,6 +95,9 @@ describe('CasesParamsFields renders', () => {
},
});
useGetAllCaseConfigurationsMock.mockImplementation(() => useGetAllCaseConfigurationsResponse);
useKibanaMock.mockReturnValue({
services: { ...createStartServicesMock(), data: { dataViews: {} } },
} as unknown as ReturnType<typeof useKibana>);
});

afterEach(() => {
Expand Down Expand Up @@ -268,6 +268,54 @@ describe('CasesParamsFields renders', () => {
expect(await screen.findByText(templatesConfigurationMock[1].name)).toBeInTheDocument();
});

it('renders security templates if the project is serverless security', async () => {
useKibanaMock.mockReturnValue({
services: {
...createStartServicesMock(),
// simulate a serverless security project
cloud: { isServerlessEnabled: true, serverless: { projectType: 'security' } },
data: { dataViews: {} },
},
} as unknown as ReturnType<typeof useKibana>);

const configuration = {
...useGetAllCaseConfigurationsResponse.data[0],
templates: templatesConfigurationMock,
};
useGetAllCaseConfigurationsMock.mockImplementation(() => ({
...useGetAllCaseConfigurationsResponse,
data: [configuration],
}));
const getConfigurationByOwnerSpy = jest
.spyOn(utils, 'getConfigurationByOwner')
.mockImplementation(() => configuration);

const observabilityOwnedRule = {
...defaultProps,
// these two would normally produce an observability owner
producerId: 'observability',
featureId: 'observability',
actionParams: {
subAction: 'run',
subActionParams: {
...actionParams.subActionParams,
templateId: templatesConfigurationMock[1].key,
},
},
};

render(<CasesParamsFields {...observabilityOwnedRule} />);

expect(getConfigurationByOwnerSpy).toHaveBeenCalledWith(
expect.objectContaining({
// the security owner was forced
owner: 'securitySolution',
})
);

getConfigurationByOwnerSpy.mockRestore();
});

it('updates template correctly', async () => {
useGetAllCaseConfigurationsMock.mockReturnValueOnce({
...useGetAllCaseConfigurationsResponse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,20 @@ export const CasesParamsFieldsComponent: React.FunctionComponent<
ActionParamsProps<CasesActionParams>
> = ({ actionParams, editAction, errors, index, producerId, featureId }) => {
const {
cloud,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a reminder that the cases_params component is rendered through various applications that provide the KibanaContextProvider. Even if the triggers actions UI provides cloud maybe other solutions will not. If it is working in Security then they definitely provide it 🙂.

Copy link
Contributor Author

@adcoelho adcoelho Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this portion of cases' code is only used by triggers_actions_ui so it's safe to assume that cloud will be provided no? I added cloud to triggers actions UI because they define Kibana context for connectors.

If it is working in Security then they definitely provide it 🙂.

The important part is that it works in Stack Management so that is independent of security right? (even if the project is security serverless)

Copy link
Member

@cnasikas cnasikas Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This portion of code is being used everywhere the alerts flyout is being used. Also, the actions component is being exported and used by the Security solution in their rules form:

Screenshot 2024-10-11 at 2 13 16 PM

Nevertheless, even if the cloud plugin is not available because you can only create security rules there the owner will always be correct + @js-jankisalvi tested it 🙂 . The issue is on Stack so it should be fine.

data: { dataViews: dataViewsService },
http,
notifications: { toasts },
data: { dataViews: dataViewsService },
} = useKibana().services;
const owner = getOwnerFromRuleConsumerProducer({ consumer: featureId, producer: producerId });

const owner = getOwnerFromRuleConsumerProducer({
consumer: featureId,
producer: producerId,
// This is a workaround for a very specific bug with the cases action in serverless security
// More info here: https://github.com/elastic/kibana/issues/195599
isServerlessSecurity:
cloud?.isServerlessEnabled && cloud?.serverless.projectType === 'security',
});

const { dataView, isLoading: loadingAlertDataViews } = useAlertsDataView({
http,
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/cases/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type { ContentManagementPublicStart } from '@kbn/content-management-plugi
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public';

import type { CloudStart } from '@kbn/cloud-plugin/public';
import type { UseCasesAddToExistingCaseModal } from './components/all_cases/selector_modal/use_cases_add_to_existing_case_modal';
import type { UseCasesAddToNewCaseFlyout } from './components/create/flyout/use_cases_add_to_new_case_flyout';
import type { UseIsAddToCaseOpen } from './components/cases_context/state/use_is_add_to_case_open';
Expand Down Expand Up @@ -73,6 +74,7 @@ export interface CasesPublicSetupDependencies {

export interface CasesPublicStartDependencies {
apm?: ApmBase;
cloud?: CloudStart;
data: DataPublicPluginStart;
embeddable: EmbeddableStart;
features: FeaturesPluginStart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { ruleDetailsRoute } from '@kbn/rule-data-utils';
import { QueryClientProvider } from '@tanstack/react-query';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { ExpressionsStart } from '@kbn/expressions-plugin/public';
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { suspendedComponentWithProps } from './lib/suspended_component_with_props';
import {
ActionTypeRegistryContract,
Expand All @@ -61,6 +62,7 @@ const RuleDetailsRoute = lazy(

export interface TriggersAndActionsUiServices extends CoreStart {
actions: ActionsPublicPluginSetup;
cloud?: CloudSetup;
data: DataPublicPluginStart;
dataViews: DataViewsPublicPluginStart;
dataViewEditor: DataViewEditorStart;
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/triggers_actions_ui/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { FieldFormatsRegistry } from '@kbn/field-formats-plugin/common';
import { LensPublicStart } from '@kbn/lens-plugin/public';
import { RuleAction } from '@kbn/alerting-plugin/common';
import { TypeRegistry } from '@kbn/alerts-ui-shared/src/common/type_registry';
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { getAlertsTableDefaultAlertActionsLazy } from './common/get_alerts_table_default_row_actions';
import type { AlertActionsProps, RuleUiAction } from './types';
import type { AlertsSearchBarProps } from './application/sections/alerts_search_bar';
Expand Down Expand Up @@ -167,7 +168,7 @@ export interface TriggersAndActionsUIPublicPluginStart {
interface PluginsSetup {
management: ManagementSetup;
home?: HomePublicPluginSetup;
cloud?: { isCloudEnabled: boolean };
cloud?: CloudSetup;
actions: ActionsPublicPluginSetup;
}

Expand Down Expand Up @@ -305,6 +306,7 @@ export class Plugin
...coreStart,
actions: plugins.actions,
dashboard: pluginsStart.dashboard,
cloud: plugins.cloud,
data: pluginsStart.data,
dataViews: pluginsStart.dataViews,
dataViewEditor: pluginsStart.dataViewEditor,
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/triggers_actions_ui/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
"@kbn/visualization-utils",
"@kbn/core-ui-settings-browser",
"@kbn/observability-alerting-rule-utils",
"@kbn/core-application-browser"
"@kbn/core-application-browser",
"@kbn/cloud-plugin"
],
"exclude": ["target/**/*"]
}