mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[RAC][o11y] fix o11y privileges when rule created in stack (#110167)
* fix o11y privileges when rule created in stack * fix merge * fix dsl alerts * fix privileges on o11y * after discussion with o11y, we agree to simplify logic of the count of alerts * remove unused variable * fix one more type error Co-authored-by: mgiota <panagiota.mitsopoulou@elastic.co>
This commit is contained in:
parent
03469515cf
commit
782f29a407
8 changed files with 73 additions and 27 deletions
|
@ -64,7 +64,7 @@ export const APM_FEATURE = {
|
|||
management: {
|
||||
insightsAndAlerting: ['triggersActions'],
|
||||
},
|
||||
ui: ['show', 'alerting:show', 'alerting:save'],
|
||||
ui: ['show', 'alerting:show'],
|
||||
},
|
||||
},
|
||||
subFeatures: [
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Capabilities } from '../../../../../src/core/types';
|
|||
export interface UseGetUserAlertsPermissionsProps {
|
||||
crud: boolean;
|
||||
read: boolean;
|
||||
loading: boolean;
|
||||
loading?: boolean;
|
||||
featureId: string | null;
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,12 @@ export const getAlertsPermissions = (
|
|||
}
|
||||
|
||||
return {
|
||||
crud: uiCapabilities[featureId].save as boolean,
|
||||
read: uiCapabilities[featureId].show as boolean,
|
||||
loading: false,
|
||||
crud: (featureId === 'apm'
|
||||
? uiCapabilities[featureId]['alerting:save']
|
||||
: uiCapabilities[featureId].save) as boolean,
|
||||
read: (featureId === 'apm'
|
||||
? uiCapabilities[featureId]['alerting:show']
|
||||
: uiCapabilities[featureId].show) as boolean,
|
||||
featureId,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
ALERT_DURATION as ALERT_DURATION_TYPED,
|
||||
ALERT_REASON as ALERT_REASON_TYPED,
|
||||
ALERT_RULE_CONSUMER,
|
||||
ALERT_RULE_PRODUCER,
|
||||
ALERT_STATUS as ALERT_STATUS_TYPED,
|
||||
ALERT_WORKFLOW_STATUS as ALERT_WORKFLOW_STATUS_TYPED,
|
||||
} from '@kbn/rule-data-utils';
|
||||
|
@ -173,6 +174,9 @@ function ObservabilityActions({
|
|||
const alertDataConsumer = useMemo<string>(() => get(dataFieldEs, ALERT_RULE_CONSUMER, [''])[0], [
|
||||
dataFieldEs,
|
||||
]);
|
||||
const alertDataProducer = useMemo<string>(() => get(dataFieldEs, ALERT_RULE_PRODUCER, [''])[0], [
|
||||
dataFieldEs,
|
||||
]);
|
||||
|
||||
const alert = parseObservabilityAlert(dataFieldEs);
|
||||
const { prepend } = core.http.basePath;
|
||||
|
@ -204,7 +208,10 @@ function ObservabilityActions({
|
|||
}
|
||||
}, [setActionsPopover, refetch]);
|
||||
|
||||
const alertPermissions = useGetUserAlertsPermissions(capabilities, alertDataConsumer);
|
||||
const alertPermissions = useGetUserAlertsPermissions(
|
||||
capabilities,
|
||||
alertDataConsumer === 'alerts' ? alertDataProducer : alertDataConsumer
|
||||
);
|
||||
|
||||
const statusActionItems = useStatusBulkActionItems({
|
||||
eventIds: [eventId],
|
||||
|
@ -298,8 +305,11 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
|||
const casePermissions = useGetUserCasesPermissions();
|
||||
|
||||
const hasAlertsCrudPermissions = useCallback(
|
||||
(featureId: string) => {
|
||||
return getAlertsPermissions(capabilities, featureId).crud;
|
||||
({ ruleConsumer, ruleProducer }: { ruleConsumer: string; ruleProducer?: string }) => {
|
||||
if (ruleConsumer === 'alerts' && ruleProducer) {
|
||||
return getAlertsPermissions(capabilities, ruleProducer).crud;
|
||||
}
|
||||
return getAlertsPermissions(capabilities, ruleConsumer).crud;
|
||||
},
|
||||
[capabilities]
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ALERT_RULE_CONSUMER } from '@kbn/rule-data-utils';
|
||||
import { ALERT_RULE_CONSUMER, ALERT_RULE_PRODUCER } from '@kbn/rule-data-utils';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
|
||||
import { EuiDataGridCellValueElementProps } from '@elastic/eui';
|
||||
|
@ -42,16 +42,26 @@ export const getEventIdToDataMapping = (
|
|||
eventIds: string[],
|
||||
fieldsToKeep: string[],
|
||||
hasAlertsCrud: boolean,
|
||||
hasAlertsCrudPermissionsByFeatureId?: (featureId: string) => boolean
|
||||
hasAlertsCrudPermissionsByRule?: ({
|
||||
ruleConsumer,
|
||||
ruleProducer,
|
||||
}: {
|
||||
ruleConsumer: string;
|
||||
ruleProducer?: string;
|
||||
}) => boolean
|
||||
): Record<string, TimelineNonEcsData[]> =>
|
||||
timelineData.reduce((acc, v) => {
|
||||
// FUTURE DEVELOPER
|
||||
// We only have one featureId for security solution therefore we can just use hasAlertsCrud
|
||||
// but for o11y we can multiple featureIds so we need to check every consumer
|
||||
// of the alert to see if they have the permission to update the alert
|
||||
const alertConsumers = v.data.find((d) => d.field === ALERT_RULE_CONSUMER)?.value ?? [];
|
||||
const hasPermissions = hasAlertsCrudPermissionsByFeatureId
|
||||
? alertConsumers.some((consumer) => hasAlertsCrudPermissionsByFeatureId(consumer))
|
||||
const ruleConsumers = v.data.find((d) => d.field === ALERT_RULE_CONSUMER)?.value ?? [];
|
||||
const ruleProducers = v.data.find((d) => d.field === ALERT_RULE_PRODUCER)?.value ?? [];
|
||||
const hasPermissions = hasAlertsCrudPermissionsByRule
|
||||
? hasAlertsCrudPermissionsByRule({
|
||||
ruleConsumer: ruleConsumers.length > 0 ? ruleConsumers[0] : '',
|
||||
ruleProducer: ruleProducers.length > 0 ? ruleProducers[0] : undefined,
|
||||
})
|
||||
: hasAlertsCrud;
|
||||
|
||||
const fvm =
|
||||
|
|
|
@ -32,7 +32,7 @@ import React, {
|
|||
import { connect, ConnectedProps, useDispatch } from 'react-redux';
|
||||
|
||||
import styled, { ThemeContext } from 'styled-components';
|
||||
import { ALERT_RULE_CONSUMER } from '@kbn/rule-data-utils';
|
||||
import { ALERT_RULE_CONSUMER, ALERT_RULE_PRODUCER } from '@kbn/rule-data-utils';
|
||||
import {
|
||||
TGridCellAction,
|
||||
BulkActionsProp,
|
||||
|
@ -105,7 +105,13 @@ interface OwnProps {
|
|||
trailingControlColumns?: ControlColumnProps[];
|
||||
unit?: (total: number) => React.ReactNode;
|
||||
hasAlertsCrud?: boolean;
|
||||
hasAlertsCrudPermissions?: (featureId: string) => boolean;
|
||||
hasAlertsCrudPermissions?: ({
|
||||
ruleConsumer,
|
||||
ruleProducer,
|
||||
}: {
|
||||
ruleConsumer: string;
|
||||
ruleProducer?: string;
|
||||
}) => boolean;
|
||||
totalSelectAllAlerts?: number;
|
||||
}
|
||||
|
||||
|
@ -180,7 +186,13 @@ const transformControlColumns = ({
|
|||
theme: EuiTheme;
|
||||
setEventsLoading: SetEventsLoading;
|
||||
setEventsDeleted: SetEventsDeleted;
|
||||
hasAlertsCrudPermissions?: (featureId: string) => boolean;
|
||||
hasAlertsCrudPermissions?: ({
|
||||
ruleConsumer,
|
||||
ruleProducer,
|
||||
}: {
|
||||
ruleConsumer: string;
|
||||
ruleProducer?: string;
|
||||
}) => boolean;
|
||||
}): EuiDataGridControlColumn[] =>
|
||||
controlColumns.map(
|
||||
({ id: columnId, headerCellRender = EmptyHeaderCellRender, rowCellRender, width }, i) => ({
|
||||
|
@ -208,7 +220,6 @@ const transformControlColumns = ({
|
|||
</>
|
||||
);
|
||||
},
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
rowCellRender: ({
|
||||
isDetails,
|
||||
|
@ -224,9 +235,15 @@ const transformControlColumns = ({
|
|||
if (rowData) {
|
||||
addBuildingBlockStyle(rowData.ecs, theme, setCellProps);
|
||||
if (columnId === 'checkbox-control-column' && hasAlertsCrudPermissions != null) {
|
||||
const alertConsumers =
|
||||
// FUTURE ENGINEER, the assumption here is you can only have one producer and consumer at this time
|
||||
const ruleConsumers =
|
||||
rowData.data.find((d) => d.field === ALERT_RULE_CONSUMER)?.value ?? [];
|
||||
disabled = alertConsumers.some((consumer) => !hasAlertsCrudPermissions(consumer));
|
||||
const ruleProducers =
|
||||
rowData.data.find((d) => d.field === ALERT_RULE_PRODUCER)?.value ?? [];
|
||||
disabled = !hasAlertsCrudPermissions({
|
||||
ruleConsumer: ruleConsumers.length > 0 ? ruleConsumers[0] : '',
|
||||
ruleProducer: ruleProducers.length > 0 ? ruleProducers[0] : undefined,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// disable the cell when it has no data
|
||||
|
|
|
@ -94,7 +94,13 @@ export interface TGridStandaloneProps {
|
|||
filters: Filter[];
|
||||
footerText: React.ReactNode;
|
||||
filterStatus: AlertStatus;
|
||||
hasAlertsCrudPermissions: (featureId: string) => boolean;
|
||||
hasAlertsCrudPermissions: ({
|
||||
ruleConsumer,
|
||||
ruleProducer,
|
||||
}: {
|
||||
ruleConsumer: string;
|
||||
ruleProducer?: string;
|
||||
}) => boolean;
|
||||
height?: number;
|
||||
indexNames: string[];
|
||||
itemsPerPageOptions: number[];
|
||||
|
@ -229,8 +235,8 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
|
|||
hasAlertsCrud: boolean;
|
||||
totalSelectAllAlerts: number;
|
||||
}>(
|
||||
(acc, [featureId, nbrAlerts]) => {
|
||||
const featureHasPermission = hasAlertsCrudPermissions(featureId);
|
||||
(acc, [ruleConsumer, nbrAlerts]) => {
|
||||
const featureHasPermission = hasAlertsCrudPermissions({ ruleConsumer });
|
||||
return {
|
||||
hasAlertsCrud: featureHasPermission || acc.hasAlertsCrud,
|
||||
totalSelectAllAlerts: featureHasPermission
|
||||
|
|
|
@ -38,7 +38,7 @@ export const timelineEventsAll: TimelineFactory<TimelineEventsQueries.all> = {
|
|||
let { fieldRequested, ...queryOptions } = cloneDeep(options);
|
||||
queryOptions.fields = buildFieldsRequest(fieldRequested, queryOptions.excludeEcsData);
|
||||
const { activePage, querySize } = options.pagination;
|
||||
const buckets = getOr([], 'aggregations.consumers.buckets', response.rawResponse);
|
||||
const producerBuckets = getOr([], 'aggregations.producers.buckets', response.rawResponse);
|
||||
const totalCount = response.rawResponse.hits.total || 0;
|
||||
const hits = response.rawResponse.hits.hits;
|
||||
|
||||
|
@ -62,7 +62,7 @@ export const timelineEventsAll: TimelineFactory<TimelineEventsQueries.all> = {
|
|||
)
|
||||
);
|
||||
|
||||
const consumers = buckets.reduce(
|
||||
const consumers: Record<string, number> = producerBuckets.reduce(
|
||||
(acc: Record<string, number>, b: { key: string; doc_count: number }) => ({
|
||||
...acc,
|
||||
[b.key]: b.doc_count,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ALERT_RULE_CONSUMER } from '@kbn/rule-data-utils';
|
||||
import { ALERT_RULE_PRODUCER } from '@kbn/rule-data-utils';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
|
||||
import {
|
||||
|
@ -69,8 +69,8 @@ export const buildTimelineEventsAllQuery = ({
|
|||
body: {
|
||||
...(!isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}),
|
||||
aggregations: {
|
||||
consumers: {
|
||||
terms: { field: ALERT_RULE_CONSUMER },
|
||||
producers: {
|
||||
terms: { field: ALERT_RULE_PRODUCER, exclude: ['alerts'] },
|
||||
},
|
||||
},
|
||||
query: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue