-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[RAM] Adds auto-incrementing revision field to rules #147398
Conversation
I believe (and would need to double-check) that the |
Good point @pmuellr! It doesn't look like this was discussed in the original issue (#136213), but I can bring it up with the team. I've been out on parental leave and just picked up this task, but from my understanding this is the first step in the larger scope of providing users the ability to have full revision control over their rules, and so having |
I'd say let's do it in a separate PR and include both fields: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an absolute ton of changes in so many files -- thank you for all the efforts @spong! I'm leaning towards merging this PR as soon as we can, but I also have quite a bunch of concerns related to code quality and test coverage that I think we should work more on that, probably in a follow-up PR(s).
As for the code coverage, I suggest to write a test plan for revision calculation/update logic and cover it with a set of integration tests. There are too many moving parts to not have it covered...
Let's sync up on the comments and decide what we do next.
export const fieldsToExcludeFromRevisionUpdates: ReadonlySet<keyof RuleTypeParams> = new Set([ | ||
'activeSnoozes', | ||
'alertTypeId', | ||
'apiKey', | ||
'apiKeyOwner', | ||
'consumer', | ||
'createdAt', | ||
'createdBy', | ||
'enabled', | ||
'executionStatus', | ||
'id', | ||
'isSnoozedUntil', | ||
'lastRun', | ||
'monitoring', | ||
'muteAll', | ||
'mutedInstanceIds', | ||
'nextRun', | ||
'revision', | ||
'running', | ||
'snoozeSchedule', | ||
'updatedBy', | ||
'updatedAt', | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a new field is added to the rule schema, how do we make sure that the developer who adds the field checks this list and updates or leaves it as is accordingly?
Should we have a test for this similar to what Core has for SO fields?
src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts
export const fieldsToExcludeFromRevisionUpdates: ReadonlySet<keyof RuleTypeParams> = new Set([ | ||
'activeSnoozes', | ||
'alertTypeId', | ||
'apiKey', | ||
'apiKeyOwner', | ||
'consumer', | ||
'createdAt', | ||
'createdBy', | ||
'enabled', | ||
'executionStatus', | ||
'id', | ||
'isSnoozedUntil', | ||
'lastRun', | ||
'monitoring', | ||
'muteAll', | ||
'mutedInstanceIds', | ||
'nextRun', | ||
'revision', | ||
'running', | ||
'snoozeSchedule', | ||
'updatedBy', | ||
'updatedAt', | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fieldsToExcludeFromRevisionUpdates
is used from incrementRevision
and not used from the file where it's defined. Probably worth moving closer to the usage. Side-effect would be less chances for introducing circular dependencies between files.
currentRule: SavedObject<RawRule>, | ||
{ data }: UpdateOptions<Params>, | ||
updatedParams: RuleTypeParams |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the first glance, these parameters are obscure and it would be helpful to add JSDoc comments clarifying what they exactly mean.
For instance, updatedParams: RuleTypeParams
-- is this the same as data.params
?
import { RawRule, RuleTypeParams } from '../../types'; | ||
import { fieldsToExcludeFromRevisionUpdates, UpdateOptions } from '..'; | ||
|
||
export function incrementRevision<Params extends RuleTypeParams>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: maybeIncrementRevision
or getNextRevision
would be more precise since it doesn't always increment it
import { RawRule, RuleTypeParams } from '../../types'; | ||
import { fieldsToExcludeFromRevisionUpdates, UpdateOptions } from '..'; | ||
|
||
export function incrementRevision<Params extends RuleTypeParams>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it a generic function? Can we use just the RuleTypeParams
type?
@@ -251,6 +253,7 @@ describe('bulkEdit()', () => { | |||
type: 'alert', | |||
attributes: expect.objectContaining({ | |||
tags: ['foo', 'test-1'], | |||
revision: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is the issue with a lot of our tests: while the test says should add new tag
it also verifies that the revision gets incremented. This has a few very important downsides that make it much harder to maintain them when there are a lot of them:
- It makes testing (for the revision update logic) implicit and buried under all the other testing logic.
- It makes tests more brittle and prone to false positive errors: when the revision update logic changes, it will make tests like
should add new tag
red although the logic of updating the tags themselves still works correctly.
I think this should be a separate test, and along with other tests, a whole suite of tests checking in what conditions and cases the revision gets incremented and in what cases it doesn't.
Let's please extract tests for revision either into a separate test suite, or just have separate it
blocks for them in every relevant test suite under rules_client/tests
, and be very specific about what we check in them.
@@ -302,6 +306,7 @@ describe('bulkEdit()', () => { | |||
type: 'alert', | |||
attributes: expect.objectContaining({ | |||
tags: [], | |||
revision: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a part of the test should delete tag
.
I don't get why the revision gets incremented here from 0 to 1, while the test doesn't seem to be deleting a tag that actually exists in a rule.
@@ -44,6 +44,7 @@ export const RuleToImport = t.intersection([ | |||
created_by, | |||
related_integrations: RelatedIntegrationArray, | |||
required_fields: RequiredFieldArray, | |||
revision, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we just ignore it and don't add to the schema? Will then a ndjson
file with a revision
be accepted, but the revision will be stripped out?
@@ -544,6 +544,7 @@ export const performBulkActionRoute = ( | |||
exceptionsList: exceptions, | |||
}, | |||
}, | |||
shouldIncrementRevision: () => false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a hack 🙂 The only reason is that we need to update the rule the second time with the newly created exception list?
I guess this is ok but could represent some problem in the future when we need to implement rule history -- which is going to be based on revisions.
@@ -141,6 +141,7 @@ export const importRules = async ({ | |||
exceptions_list: [...exceptions], | |||
}, | |||
allowMissingConnectorSecrets, | |||
shouldIncrementRevision: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why exactly it is false here?
When testing import I noticed a bug and I suspect this might be causing it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had a chat with @spong on the next steps and I'm leaning towards fixing leftover bugs within this PR, merging it, and addressing the rest of the comments separately.
💚 Build Succeeded
Metrics [docs]Public APIs missing comments
Async chunks
Public APIs missing exports
Saved Objects .kibana field count
Unknown metric groupsAPI count
ESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: cc @spong |
## Summary Resolves elastic#137164. This PR adds a new `revision` field (number) to Alerting Rules that auto-increments when relevant content changes have been made via the `Rules Client`. _Relevant content changes_ are defined as any content change that the user may either want to be notified about, or have the option to later revert to. This will include most all changes, except the enabling/disabling of the rule, or updates to metadata fields like `executionStatus` or `monitoring`. This `revision` field is not intended to be user editable, and should be ignored if ever provided via the API. See elastic#136213 for additional details. To be followed-up by elastic#137168, which will remove the version bump logic from security solution. ## Details ### Migrations Includes SO migration to default `revision` to `0` when upgrading a cluster, or when importing `pre-8.8.0` rules via the SO Management UI. For consistency, security rule import follows the same logic as SO Management and will not reset the `revision` to `0` when overriding or creating a new rule. ### Downstream Index Updates * EventLog _has not_ been updated to include `revision` along with basic rule fields currently being written. Should we? * AAD Schema will be updated in elastic#151388 (as this one is getting pretty big) to include `revision` so alerts written will include which specific revision of the rule created the alert. ### Reference Fields Any creation of or modification to `actions` will result in a revision increment. More typical reference fields like `exception lists` on the security side will only result in a revision increment when the list is initially associated/deleted from the rule (as subsequent updates will be done directly against the list). ### RuleClient Updates The following methods within the RuleClient have been updated to support incrementing revision when relevant field changes have been detected: * `clone()` - resets to 0 currently (see open question) * `update()` - increments `revision` so long a change has been made to relevant fields (fields not in [ignore list](https://github.com/elastic/kibana/pull/147398/files#diff-6736e143ede2dc06e825bddcdc23b4d088a6620805751db4eddc5900d586c4dfR69-R85)) * `bulkEdit()` - increments `revision` for relevant fields (all current bulk edit fields minus api key/snooze/mute) Mutation methods not updated to include revision log: * `snooze()` * `unsnooze()` * `clearExpiredSnoozes()` * `muteAll()` * `unmuteAll()` * `muteInstance()` * `unmuteInstance()` * `updateApiKey()` - increments revision as rule functionality could be impacted ## Open questions: - [X] Should `clone()` in RulesClient reset revision to 0 as if it's a new rule, or keep the current value? (see [comment](https://github.com/elastic/kibana/pull/147398/files#r1106484105)) - [X] What about snooze/un-snooze, and mute/unmute? Should we update revision on these field changes as well? (see [comment](https://github.com/elastic/kibana/pull/147398/files#r1106431966)) - Discussed with @XavierM and determined to not update on snooze/mute/API key changes as this actions could be plentiful and don't necessarily represent a version of the rule a user would want to revert to, thus polluting the revision history. - [ ] Should we write `revision` to EventLog? --- ### Checklist Delete any items that are not applicable to this PR. - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] To work with docs team - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [X] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
@banderror -- here's the issue for tracking the remaining feedback: #153144 I will resolve your above comments with links to the specific commits they're addressed in 👍 |
## Summary Resolves #137168 by removing the logic to bump the `version` of security rules. Also adds an SO migration to set the initial `revision` as the current `version`. Note: this was originally a branched off #147398, so the large commit list is resulting from there as Github doesn't seem to re-write after after a rebase w/ `main` and a force push. ### Checklist ~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ * Found no reference with regards to the auto-incrementing version logic in [current docs](https://www.elastic.co/guide/en/security/current/detection-engine-overview.html). - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
## Summary Follow up from #147398, which adds `revision` to the alerts schema so the rule's current revision is included when creating alerts. In Security Solution: <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/227386305-c8afe295-b79b-4b28-838a-cc3bed0f3eda.png" /> </p> In Observability: <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/227577019-05307860-e0e3-4e1e-b4cf-604bdb52afdf.png" /> </p> Note: this was originally a branched off #147398, so the large commit list is resulting from there as Github doesn't seem to re-write after after a rebase w/ `main` and a force push. ### Checklist Delete any items that are not applicable to this PR. - [ ] ~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ * Base docs to be added for #147398 - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
## Summary Follow up from elastic#147398, which adds `revision` to the alerts schema so the rule's current revision is included when creating alerts. In Security Solution: <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/227386305-c8afe295-b79b-4b28-838a-cc3bed0f3eda.png" /> </p> In Observability: <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/227577019-05307860-e0e3-4e1e-b4cf-604bdb52afdf.png" /> </p> Note: this was originally a branched off elastic#147398, so the large commit list is resulting from there as Github doesn't seem to re-write after after a rebase w/ `main` and a force push. ### Checklist Delete any items that are not applicable to this PR. - [ ] ~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ * Base docs to be added for elastic#147398 - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
## Summary Follow on from #151388 & #147398, which includes the rule's current `revision` when writing to the kibana event-log. Note: Added as `kibana.alert.rule.revision` instead of as ECS field `rule.version` as the [ECS docs](https://www.elastic.co/guide/en/ecs/current/ecs-rule.html#field-rule-version) conflate `version` & `revision` and figured it was best to be explicit. If we do indeed want to use `rule.version` I'll make the change. <p align="center"> <img width="500" src="https://user-images.githubusercontent.com/2946766/233216775-f371f412-dcf6-4ef7-a396-84ec853eebbb.png" /> </p> ### Checklist Delete any items that are not applicable to this PR. - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
Summary
Resolves #137164.
This PR adds a new
revision
field (number) to Alerting Rules that auto-increments when relevant content changes have been made via theRules Client
. Relevant content changes are defined as any content change that the user may either want to be notified about, or have the option to later revert to. This will include most all changes, except the enabling/disabling of the rule, or updates to metadata fields likeexecutionStatus
ormonitoring
. Thisrevision
field is not intended to be user editable, and should be ignored if ever provided via the API.See #136213 for additional details. To be followed-up by #137168, which will remove the version bump logic from security solution.
Details
Migrations
Includes SO migration to default
revision
to0
when upgrading a cluster, or when importingpre-8.8.0
rules via the SO Management UI. For consistency, security rule import follows the same logic as SO Management and will not reset therevision
to0
when overriding or creating a new rule.Downstream Index Updates
revision
along with basic rule fields currently being written. Should we?revision
so alerts written will include which specific revision of the rule created the alert.Reference Fields
Any creation of or modification to
actions
will result in a revision increment. More typical reference fields likeexception lists
on the security side will only result in a revision increment when the list is initially associated/deleted from the rule (as subsequent updates will be done directly against the list).RuleClient Updates
The following methods within the RuleClient have been updated to support incrementing revision when relevant field changes have been detected:
clone()
- resets to 0 currently (see open question)update()
- incrementsrevision
so long a change has been made to relevant fields (fields not in ignore list)bulkEdit()
- incrementsrevision
for relevant fields (all current bulk edit fields minus api key/snooze/mute)Mutation methods not updated to include revision log:
snooze()
unsnooze()
clearExpiredSnoozes()
muteAll()
unmuteAll()
muteInstance()
unmuteInstance()
updateApiKey()
- increments revision as rule functionality could be impactedOpen questions:
clone()
in RulesClient reset revision to 0 as if it's a new rule, or keep the current value? (see comment)revision
to EventLog?Checklist
Delete any items that are not applicable to this PR.
For maintainers