Skip to content

Commit

Permalink
Change new schema
Browse files Browse the repository at this point in the history
  • Loading branch information
cnasikas committed May 23, 2024
1 parent 5184d21 commit 06d8499
Show file tree
Hide file tree
Showing 17 changed files with 227 additions and 191 deletions.
45 changes: 25 additions & 20 deletions x-pack/examples/alerting_example/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,27 @@ export class AlertingExamplePlugin implements Plugin<void, void, AlertingExample
insightsAndAlerting: ['triggersActions'],
},
category: DEFAULT_APP_CATEGORIES.management,
alerting: {
ruleTypeIds: [alwaysFiringRule.id, peopleInSpaceRule.id, INDEX_THRESHOLD_ID],
consumers: [ALERTING_EXAMPLE_APP_ID],
},
alerting: [
{ ruleTypeId: alwaysFiringRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: peopleInSpaceRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: INDEX_THRESHOLD_ID, consumers: [ALERTING_EXAMPLE_APP_ID] },
],
privileges: {
all: {
alerting: {
rule: {
all: {
ruleTypeIds: [alwaysFiringRule.id, peopleInSpaceRule.id, INDEX_THRESHOLD_ID],
consumers: [ALERTING_EXAMPLE_APP_ID],
},
all: [
{ ruleTypeId: alwaysFiringRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: peopleInSpaceRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: INDEX_THRESHOLD_ID, consumers: [ALERTING_EXAMPLE_APP_ID] },
],
},
alert: {
all: {
ruleTypeIds: [alwaysFiringRule.id, peopleInSpaceRule.id, INDEX_THRESHOLD_ID],
consumers: [ALERTING_EXAMPLE_APP_ID],
},
all: [
{ ruleTypeId: alwaysFiringRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: peopleInSpaceRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: INDEX_THRESHOLD_ID, consumers: [ALERTING_EXAMPLE_APP_ID] },
],
},
},
savedObject: {
Expand All @@ -107,16 +110,18 @@ export class AlertingExamplePlugin implements Plugin<void, void, AlertingExample
read: {
alerting: {
rule: {
read: {
ruleTypeIds: [alwaysFiringRule.id, peopleInSpaceRule.id, INDEX_THRESHOLD_ID],
consumers: [ALERTING_EXAMPLE_APP_ID],
},
read: [
{ ruleTypeId: alwaysFiringRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: peopleInSpaceRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: INDEX_THRESHOLD_ID, consumers: [ALERTING_EXAMPLE_APP_ID] },
],
},
alert: {
read: {
ruleTypeIds: [alwaysFiringRule.id, peopleInSpaceRule.id, INDEX_THRESHOLD_ID],
consumers: [ALERTING_EXAMPLE_APP_ID],
},
read: [
{ ruleTypeId: alwaysFiringRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: peopleInSpaceRule.id, consumers: [ALERTING_EXAMPLE_APP_ID] },
{ ruleTypeId: INDEX_THRESHOLD_ID, consumers: [ALERTING_EXAMPLE_APP_ID] },
],
},
},
savedObject: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ const SECURITY_RULE_TYPES = [
NEW_TERMS_RULE_TYPE_ID,
];

const alertingFeatures = SECURITY_RULE_TYPES.map((ruleTypeId) => ({
ruleTypeId,
consumers: [SERVER_APP_ID],
}));

export const getSecurityBaseKibanaFeature = ({
savedObjects,
}: SecurityFeatureParams): BaseKibanaFeatureConfig => ({
Expand All @@ -57,7 +62,7 @@ export const getSecurityBaseKibanaFeature = ({
management: {
insightsAndAlerting: ['triggersActions'],
},
alerting: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] },
alerting: alertingFeatures,
privileges: {
all: {
app: [APP_ID, CLOUD_POSTURE_APP_ID, CLOUD_DEFEND_APP_ID, 'kibana'],
Expand All @@ -78,12 +83,8 @@ export const getSecurityBaseKibanaFeature = ({
read: [],
},
alerting: {
rule: {
all: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] },
},
alert: {
all: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] },
},
rule: { all: alertingFeatures },
alert: { all: alertingFeatures },
},
management: {
insightsAndAlerting: ['triggersActions'],
Expand All @@ -100,10 +101,10 @@ export const getSecurityBaseKibanaFeature = ({
},
alerting: {
rule: {
read: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] },
read: alertingFeatures,
},
alert: {
all: { ruleTypeIds: SECURITY_RULE_TYPES, consumers: [SERVER_APP_ID] },
all: alertingFeatures,
},
},
management: {
Expand Down
8 changes: 4 additions & 4 deletions x-pack/plugins/features/common/feature_kibana_privileges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export interface FeatureKibanaPrivileges {
* }
* ```
*/
all?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] };
all?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>;
/**
* List of rule types which users should have read-only access to when granted this privilege.
* @example
Expand All @@ -113,7 +113,7 @@ export interface FeatureKibanaPrivileges {
* }
* ```
*/
read?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] };
read?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>;
};
alert?: {
/**
Expand All @@ -125,7 +125,7 @@ export interface FeatureKibanaPrivileges {
* }
* ```
*/
all?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] };
all?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>;
/**
* List of rule types for which users should have read-only access to their alert data when granted this privilege.
* @example
Expand All @@ -135,7 +135,7 @@ export interface FeatureKibanaPrivileges {
* }
* ```
*/
read?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] };
read?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>;
};
};

Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/features/common/kibana_feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export interface KibanaFeatureConfig {
* Include both Alert Types registered by the feature and external Alert Types such as built-in
* Alert Types and Alert Types provided by other features to which you wish to grant access.
*/
alerting?: { ruleTypeIds?: readonly string[]; consumers?: readonly string[] };
alerting?: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>;

/**
* If your feature grants access to specific case types, you can specify them here to control visibility based on the current space.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,50 +108,43 @@ function mergeWithSubFeatures(
subFeaturePrivilege.savedObject.read
);

const mergeAlertingEntries = (
entries: ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }>
): ReadonlyArray<{ ruleTypeId: string; consumers: readonly string[] }> => {
const alertingMap = new Map<string, Set<string>>();

for (const entry of entries) {
const consumers = alertingMap.get(entry.ruleTypeId) ?? new Set();
entry.consumers.forEach((consumer) => consumers.add(consumer));
alertingMap.set(entry.ruleTypeId, consumers);
}

return Array.from(alertingMap).map(([ruleTypeId, consumers]) => ({
ruleTypeId,
consumers: Array.from(consumers),
}));
};

mergedConfig.alerting = {
rule: {
all: {
ruleTypeIds: mergeArrays(
mergedConfig.alerting?.rule?.all?.ruleTypeIds ?? [],
subFeaturePrivilege.alerting?.rule?.all?.ruleTypeIds ?? []
),
consumers: mergeArrays(
mergedConfig.alerting?.rule?.all?.consumers ?? [],
subFeaturePrivilege.alerting?.rule?.all?.consumers ?? []
),
},
read: {
ruleTypeIds: mergeArrays(
mergedConfig.alerting?.rule?.read?.ruleTypeIds ?? [],
subFeaturePrivilege.alerting?.rule?.read?.ruleTypeIds ?? []
),
consumers: mergeArrays(
mergedConfig.alerting?.rule?.read?.consumers ?? [],
subFeaturePrivilege.alerting?.rule?.read?.consumers ?? []
),
},
all: mergeAlertingEntries([
...(mergedConfig.alerting?.rule?.all ?? []),
...(subFeaturePrivilege.alerting?.rule?.all ?? []),
]),
read: mergeAlertingEntries([
...(mergedConfig.alerting?.rule?.read ?? []),
...(subFeaturePrivilege.alerting?.rule?.read ?? []),
]),
},
alert: {
all: {
ruleTypeIds: mergeArrays(
mergedConfig.alerting?.alert?.all?.ruleTypeIds ?? [],
subFeaturePrivilege.alerting?.alert?.all?.ruleTypeIds ?? []
),
consumers: mergeArrays(
mergedConfig.alerting?.alert?.all?.consumers ?? [],
subFeaturePrivilege.alerting?.alert?.all?.consumers ?? []
),
},
read: {
ruleTypeIds: mergeArrays(
mergedConfig.alerting?.alert?.read?.ruleTypeIds ?? [],
subFeaturePrivilege.alerting?.alert?.read?.ruleTypeIds ?? []
),
consumers: mergeArrays(
mergedConfig.alerting?.alert?.read?.consumers ?? [],
subFeaturePrivilege.alerting?.alert?.read?.consumers ?? []
),
},
all: mergeAlertingEntries([
...(mergedConfig.alerting?.alert?.all ?? []),
...(subFeaturePrivilege.alerting?.alert?.all ?? []),
]),
read: mergeAlertingEntries([
...(mergedConfig.alerting?.alert?.read ?? []),
...(subFeaturePrivilege.alerting?.alert?.read ?? []),
]),
},
};

Expand Down
49 changes: 28 additions & 21 deletions x-pack/plugins/features/server/feature_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ const managementSchema = schema.recordOf(
listOfCapabilitiesSchema
);
const catalogueSchema = listOfCapabilitiesSchema;
const alertingSchema = schema.object({
ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())),
consumers: schema.maybe(schema.arrayOf(schema.string())),
});
const alertingSchema = schema.arrayOf(
schema.object({
ruleTypeId: schema.string(),
consumers: schema.arrayOf(schema.string()),
})
);

const casesSchema = schema.arrayOf(schema.string());

const appCategorySchema = schema.object({
Expand Down Expand Up @@ -277,13 +280,7 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
kibanaFeatureSchema.validate(feature);

// the following validation can't be enforced by the Joi schema, since it'd require us looking "up" the object graph for the list of valid value, which they explicitly forbid.
const {
app = [],
management = {},
catalogue = [],
alerting: { ruleTypeIds = [], consumers = [] } = {},
cases = [],
} = feature;
const { app = [], management = {}, catalogue = [], alerting = [], cases = [] } = feature;

const unseenApps = new Set(app);

Expand All @@ -296,7 +293,9 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {

const unseenCatalogue = new Set(catalogue);

const unseenAlertTypes = new Set([...ruleTypeIds, ...consumers]);
const unseenAlertTypes = new Set(
alerting.flatMap(({ ruleTypeId, consumers }) => [ruleTypeId, ...consumers])
);

const unseenCasesTypes = new Set(cases);

Expand Down Expand Up @@ -327,23 +326,31 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) {
}

function validateAlertingEntry(privilegeId: string, entry: FeatureKibanaPrivileges['alerting']) {
const getRuleTypeIdAndConsumers = ({
ruleTypeId,
consumers,
}: {
ruleTypeId: string;
consumers: readonly string[];
}) => [ruleTypeId, ...consumers];

const all: string[] = [
...(entry?.rule?.all?.consumers ?? []),
...(entry?.rule?.all?.ruleTypeIds ?? []),
...(entry?.alert?.all?.consumers ?? []),
...(entry?.alert?.all?.ruleTypeIds ?? []),
...(entry?.rule?.all?.flatMap(getRuleTypeIdAndConsumers) ?? []),
...(entry?.alert?.all?.flatMap(getRuleTypeIdAndConsumers) ?? []),
];
const read: string[] = [
...(entry?.rule?.read?.consumers ?? []),
...(entry?.rule?.read?.ruleTypeIds ?? []),
...(entry?.alert?.read?.consumers ?? []),
...(entry?.alert?.read?.ruleTypeIds ?? []),
...(entry?.rule?.read?.flatMap(getRuleTypeIdAndConsumers) ?? []),
...(entry?.alert?.read?.flatMap(getRuleTypeIdAndConsumers) ?? []),
];

all.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes));
read.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes));

const unknownAlertingEntries = difference([...all, ...read], [...ruleTypeIds, ...consumers]);
const unknownAlertingEntries = difference(
[...all, ...read],
alerting.flatMap(({ ruleTypeId, consumers }) => [ruleTypeId, ...consumers])
);

if (unknownAlertingEntries.length > 0) {
throw new Error(
`Feature privilege ${
Expand Down
13 changes: 9 additions & 4 deletions x-pack/plugins/ml/common/types/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ export function getDefaultCapabilities(): MlCapabilities {
};
}

const alertingFeatures = Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({
ruleTypeId,
consumers: [PLUGIN_ID],
}));

export function getPluginPrivileges() {
const apmUserMlCapabilitiesKeys = Object.keys(apmUserMlCapabilities);
const userMlCapabilitiesKeys = Object.keys(userMlCapabilities);
Expand Down Expand Up @@ -149,10 +154,10 @@ export function getPluginPrivileges() {
},
alerting: {
rule: {
all: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] },
all: alertingFeatures,
},
alert: {
all: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] },
all: alertingFeatures,
},
},
},
Expand All @@ -171,10 +176,10 @@ export function getPluginPrivileges() {
},
alerting: {
rule: {
read: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] },
read: alertingFeatures,
},
alert: {
read: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] },
read: alertingFeatures,
},
},
},
Expand Down
5 changes: 4 additions & 1 deletion x-pack/plugins/ml/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ export class MlServerPlugin
management: {
insightsAndAlerting: ['jobsListLink', 'triggersActions'],
},
alerting: { ruleTypeIds: Object.values(ML_ALERT_TYPES), consumers: [PLUGIN_ID] },
alerting: Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({
ruleTypeId,
consumers: [PLUGIN_ID],
})),
privileges: {
all: admin,
read: user,
Expand Down
Loading

0 comments on commit 06d8499

Please sign in to comment.