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

[Security Solution] Extend upgrade prebuilt rules context with conflict resolution functionality #191721

Merged
merged 11 commits into from
Sep 10, 2024

Conversation

maximpn
Copy link
Contributor

@maximpn maximpn commented Aug 29, 2024

Addresses: #171520

Summary

This PR implements necessary UpgradePrebuiltRulesTableContext changes to provide uses a way to resolve conflicts manually by providing field's resolved value.

Details

During prebuilt rules upgrading users may encounter solvable and non-solvable conflicts between customized and target rule versions. Three-Way-Diff field component allow to specify a desired resolve value user expects to be in the rule after upgrading. It's also possible to customize rules during the upgrading process.

Current functionality is informational only without an ability to customize prebuilt rules. As the core part of that process it's required to manage the upgrading state and provide necessary data for downstream components rendering field diffs and accepting user input.

This PR extends UpgradePrebuiltRulesTableContext with rule upgrade state and provides it to ThreeWayDiffTab stub component. It's planned to add implementation to ThreeWayDiffTab in follow up PRs.

On top of that UpgradePrebuiltRulesTableContext and AddPrebuiltRulesTableContext were symmetrically refactored from architecture point of view to improve encapsulation by separation of concerns which leads to slight complexity reduction.

Feature flag prebuiltRulesCustomizationEnabled

ThreeWayDiffTab is hidden under a feature flag prebuiltRulesCustomizationEnabled. It accepts a finalDiffableRule which represents rule fields the user expects to see in the upgraded rule. finalDiffableRule is a combination of field resolved values and target rule fields where resolved values have precedence.

@maximpn maximpn added release_note:skip Skip the PR/issue when compiling release notes Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Team:Detection Rule Management Security Detection Rule Management Team v8.16.0 labels Aug 29, 2024
@maximpn maximpn self-assigned this Aug 29, 2024
@maximpn maximpn force-pushed the extends-upgrade-prebuilt-rules-context branch 5 times, most recently from 64bb1e5 to 9503044 Compare September 2, 2024 06:46
@maximpn maximpn marked this pull request as ready for review September 2, 2024 06:46
@maximpn maximpn requested review from a team as code owners September 2, 2024 06:46
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detections-response (Team:Detections and Resp)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detection-rule-management (Team:Detection Rule Management)

@maximpn maximpn added Feature:Prebuilt Detection Rules Security Solution Prebuilt Detection Rules area enhancement New value added to drive a business result labels Sep 2, 2024
@maximpn maximpn force-pushed the extends-upgrade-prebuilt-rules-context branch from 9503044 to 3425c13 Compare September 2, 2024 10:33
rule={rule}
size="l"
id={PREBUILT_RULE_UPDATE_FLYOUT_ANCHOR}
dataTestSubj="updatePrebuiltRulePreview"
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to allow passing dataTestSubj via props, because we used:

  • dataTestSubj="installPrebuiltRulePreview" for installation
  • dataTestSubj="updatePrebuiltRulePreview" for upgrade

We have a Cypress test that uses these, but it doesn't run because it has issues with tags. I have created a PR to make it run again. We'll need to run these changes through CI once that PR is merged.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also id={PREBUILT_RULE_UPDATE_FLYOUT_ANCHOR} is not needed for the installation use case. I'm thinking maybe we could have a generic prop like flyoutProps that we would spread over? wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, thanks for noticing. I planned to address data test subject ids in follow up PRs where we add tests. As you can see the current code doesn't cause any failures.

Adding flyoutProps right away looks as a good option.

isUpgradingSecurityPackages,
installOneRule,
]
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a space after this line for clarity?

ruleResolvedConflicts: RuleResolvedConflicts
): DiffableRule {
return {
...convertRuleToDiffable(ruleUpgradeInfo.target_rule),
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure if this is WIP, but if we want to get the "final version" of a rule, we should get all diffable fields, and then overwrite all fields that have a merged_version within diff.fields.

The logic here implemented is correct, but it will only work when the user manually does a change in the edit component.

I think the return value of this method should look something like:

  return {
    ...convertRuleToDiffable(ruleUpgradeInfo.target_rule),
    ...getFieldsWithMergedVersions(ruleUpgradeInfo.diff), // loops through diff.fields and retrieves fields with a merged_version
    ...ruleResolvedConflicts,
  } as DiffableRule;

Copy link
Contributor

@jpdjere jpdjere Sep 9, 2024

Choose a reason for hiding this comment

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

This will make sure to use the target version as the "initial" diffable rule, then overwrite with any values that were returned with a merged_version from /upgrade/_review, and finally overwrite any values that have been manually edited by the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. It makes sense. I made proper adjustments in the code.

Comment on lines 103 to 120
const fieldNamesWithNonSolvableConflicts = fieldNames.filter(
(fieldName) =>
ruleUpgradeInfo.diff.fields[fieldName]?.conflict === ThreeWayDiffConflict.NON_SOLVABLE
);
Copy link
Contributor

Choose a reason for hiding this comment

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

We spoke about this today, but posting here for transparency: this should include the fields with SOLVABLE conflicts, which should be accepted by the user as well in order to unblock the upgrade of the rule.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I changed the implementation to match our discussion results.

...ruleUpgradeInfo,
finalRule: calcFinalDiffableRule(
ruleUpgradeInfo,
rulesResolvedConflicts[ruleUpgradeInfo.id] ?? {}
Copy link
Contributor

Choose a reason for hiding this comment

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

If understand it correctly, we should use ruleUpgradeInfo.rule_id here and when calling calcUnresolvedConflicts below. Otherwise it won't find an item in rulesResolvedConflicts.

@maximpn maximpn force-pushed the extends-upgrade-prebuilt-rules-context branch from 2071dff to 6663685 Compare September 10, 2024 13:40
export function usePrebuiltRulesUpgradeState(
ruleUpgradeInfos: RuleUpgradeInfoForReview[]
): UseRulesUpgradeStateResult {
const [rulesResolvedConflicts, setRulesResolvedConflicts] = useState<RulesResolvedConflicts>({});
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should also let the user revert a conflict back to unresolved. Let's say they set some resolved value and then decide that it's not good and they want to start over from the initial state (merge proposal). In current implementation even if you close and reopen the flyout the state will be preserved. And if we later add persistence in sessionStorage even page reload won't help.

Should we then think about adding buttons for reverting? @maximpn @jpdjere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. It might be helpful feature. But it's possible to implement this feature on top of the current functionality. I wouldn't address that in the current PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, I agree, it's for a separate PR. I'm curious what you folks think in general about reverts - is it needed or not. Because it's something that we haven't discussed when planning the feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

We'll definitely need a way to "revert" conflict resolutions. Just as an example: a rule update has an ABC scenario conflict for its name field. The user manually resolves the conflict, but then manually deletes the input value in the edit component. Since name is required, we should unresolve the conflict and disable the "Update rule" button.

But yes, we can add this complexity incrementally, doesn't need to be part of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just realized that my message above refers to unresolving a conflict from the state management point of view (which can be handled using the existing setRulesResolvedConflicts setter), but what @nikitaindik meant was allowing the user to unaccept a change from the UI/UX perspective.

In the original plan, for each field, we'd have a Edit/Save button that switches back and forth between those two values when clicking on it. When clicking on Save, the change is accepted and conflict resolved, when clicking on Edit, it is un-accepted and conflict un-resolved.

However, this has one limitation that we need to resolved. Copying here what I pasted on Slack yesterday:

There's one thing that I think we need to figure out: when planning out this component we decided to simplify the UI by just having a button that switches back and forth betwen Edit and Save. And by clicking on "Save", that would mark the state as "accepted".

However, since the "SOLVABLE" conflicts appear first as Read-Only components, they are already "saved" from the UI perspective (the Edit button is visible, no the Save button), but not from the state management perspective. It feels like we still need to add a separate button to accept the changes, that is independent from the Edit/Save switch. But I'm afraid this might explode the complexity of the component's state.

What do you guys think? cc @maximpn

Copy link
Contributor

Choose a reason for hiding this comment

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

Continued the discussion in the Slack channel pasted above.

Copy link
Contributor

@jpdjere jpdjere left a comment

Choose a reason for hiding this comment

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

Thanks for addressing my comments. Now I see the expected finalVersion with the merged_versions of the fields that have updated. 👍

Copy link
Contributor

@nikitaindik nikitaindik left a comment

Choose a reason for hiding this comment

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

Thanks for the changes @maximpn! PR LGTM now.

@maximpn maximpn enabled auto-merge (squash) September 10, 2024 22:14
@maximpn maximpn merged commit 66af356 into elastic:main Sep 10, 2024
50 checks passed
@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
securitySolution 5733 5744 +11

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 19.7MB 19.7MB +8.4KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @maximpn

@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Sep 10, 2024
@maximpn maximpn deleted the extends-upgrade-prebuilt-rules-context branch September 11, 2024 03:35
jpdjere added a commit that referenced this pull request Sep 13, 2024
…Customization FF (#192919)

## Summary

With the merge of #191721, new
logic was introduce to disable the Upgrade rule button in the Rule
Upgrade table for rules which have conflicts in any of their fields.

**This change should be hidden behind a FF.** Otherwise the UI upgrade
flow might break for any users who might have customized the rule via
API and generated conflicts.
maximpn added a commit that referenced this pull request Sep 27, 2024
…Update Workflow (#193531)

**Epic:** #174168
**Addresses:** #171520

## Summary

This PR introduces a new `Update` tab allowing users to resolve rule upgrade conflicts. It's a result of combination of read-only components implemented in #193261 and rule upgrade state implemented in #191721.

## Details

The goal of this PR is to provide intermediate integration between rule upgrade state ([PR](#191721)) and components displaying the diff and read-only state ([PR](#193261)). It will facilitate further development of rule field editable components and streamline rule upgrade functionality developing.

## How to test?

The functionality is hidden under `prebuiltRulesCustomizationEnabled` feature flag. Add the following to your Kibana config

```yaml
xpack.securitySolution.enableExperimental:
  - prebuiltRulesCustomizationEnabled
```

When the above feature flag enabled the new `Update` tab is displayed instead of the old one.

## Screenshots

Suggested components design 
![image](https://github.com/user-attachments/assets/b5aaf571-286a-4595-9bd4-fdaf9a423b03)

New `Update` tab
<img width="1718" alt="image" src="https://github.com/user-attachments/assets/28aa6bb3-f805-4109-a808-d67e58c7c5b8">
kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Sep 27, 2024
…Update Workflow (elastic#193531)

**Epic:** elastic#174168
**Addresses:** elastic#171520

## Summary

This PR introduces a new `Update` tab allowing users to resolve rule upgrade conflicts. It's a result of combination of read-only components implemented in elastic#193261 and rule upgrade state implemented in elastic#191721.

## Details

The goal of this PR is to provide intermediate integration between rule upgrade state ([PR](elastic#191721)) and components displaying the diff and read-only state ([PR](elastic#193261)). It will facilitate further development of rule field editable components and streamline rule upgrade functionality developing.

## How to test?

The functionality is hidden under `prebuiltRulesCustomizationEnabled` feature flag. Add the following to your Kibana config

```yaml
xpack.securitySolution.enableExperimental:
  - prebuiltRulesCustomizationEnabled
```

When the above feature flag enabled the new `Update` tab is displayed instead of the old one.

## Screenshots

Suggested components design
![image](https://github.com/user-attachments/assets/b5aaf571-286a-4595-9bd4-fdaf9a423b03)

New `Update` tab
<img width="1718" alt="image" src="https://github.com/user-attachments/assets/28aa6bb3-f805-4109-a808-d67e58c7c5b8">

(cherry picked from commit 878ba13)
kibanamachine added a commit that referenced this pull request Sep 27, 2024
… Rule Update Workflow (#193531) (#194348)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution] Integrate state and components for Prebuilt Rule
Update Workflow
(#193531)](#193531)

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

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

<!--BACKPORT [{"author":{"name":"Maxim
Palenov","email":"maxim.palenov@elastic.co"},"sourceCommit":{"committedDate":"2024-09-27T21:07:12Z","message":"[Security
Solution] Integrate state and components for Prebuilt Rule Update
Workflow (#193531)\n\n**Epic:**
https://github.com/elastic/kibana/issues/174168\r\n**Addresses:**
https://github.com/elastic/kibana/issues/171520\r\n\r\n##
Summary\r\n\r\nThis PR introduces a new `Update` tab allowing users to
resolve rule upgrade conflicts. It's a result of combination of
read-only components implemented in
#193261 and rule upgrade state
implemented in https://github.com/elastic/kibana/pull/191721.\r\n\r\n##
Details\r\n\r\nThe goal of this PR is to provide intermediate
integration between rule upgrade state
([PR](#191721)) and components
displaying the diff and read-only state
([PR](#193261)). It will
facilitate further development of rule field editable components and
streamline rule upgrade functionality developing.\r\n\r\n## How to
test?\r\n\r\nThe functionality is hidden under
`prebuiltRulesCustomizationEnabled` feature flag. Add the following to
your Kibana
config\r\n\r\n```yaml\r\nxpack.securitySolution.enableExperimental:\r\n
- prebuiltRulesCustomizationEnabled\r\n```\r\n\r\nWhen the above feature
flag enabled the new `Update` tab is displayed instead of the old
one.\r\n\r\n## Screenshots\r\n\r\nSuggested components design
\r\n![image](https://github.com/user-attachments/assets/b5aaf571-286a-4595-9bd4-fdaf9a423b03)\r\n\r\nNew
`Update` tab\r\n<img width=\"1718\" alt=\"image\"
src=\"https://github.com/user-attachments/assets/28aa6bb3-f805-4109-a808-d67e58c7c5b8\">","sha":"878ba134e96245b038a9765148ad48a36bb2aa4b","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Detections
and Resp","Team: SecuritySolution","Team:Detection Rule
Management","backport:prev-minor"],"title":"[Security Solution]
Integrate state and components for Prebuilt Rule Update
Workflow","number":193531,"url":"https://github.com/elastic/kibana/pull/193531","mergeCommit":{"message":"[Security
Solution] Integrate state and components for Prebuilt Rule Update
Workflow (#193531)\n\n**Epic:**
https://github.com/elastic/kibana/issues/174168\r\n**Addresses:**
https://github.com/elastic/kibana/issues/171520\r\n\r\n##
Summary\r\n\r\nThis PR introduces a new `Update` tab allowing users to
resolve rule upgrade conflicts. It's a result of combination of
read-only components implemented in
#193261 and rule upgrade state
implemented in https://github.com/elastic/kibana/pull/191721.\r\n\r\n##
Details\r\n\r\nThe goal of this PR is to provide intermediate
integration between rule upgrade state
([PR](#191721)) and components
displaying the diff and read-only state
([PR](#193261)). It will
facilitate further development of rule field editable components and
streamline rule upgrade functionality developing.\r\n\r\n## How to
test?\r\n\r\nThe functionality is hidden under
`prebuiltRulesCustomizationEnabled` feature flag. Add the following to
your Kibana
config\r\n\r\n```yaml\r\nxpack.securitySolution.enableExperimental:\r\n
- prebuiltRulesCustomizationEnabled\r\n```\r\n\r\nWhen the above feature
flag enabled the new `Update` tab is displayed instead of the old
one.\r\n\r\n## Screenshots\r\n\r\nSuggested components design
\r\n![image](https://github.com/user-attachments/assets/b5aaf571-286a-4595-9bd4-fdaf9a423b03)\r\n\r\nNew
`Update` tab\r\n<img width=\"1718\" alt=\"image\"
src=\"https://github.com/user-attachments/assets/28aa6bb3-f805-4109-a808-d67e58c7c5b8\">","sha":"878ba134e96245b038a9765148ad48a36bb2aa4b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193531","number":193531,"mergeCommit":{"message":"[Security
Solution] Integrate state and components for Prebuilt Rule Update
Workflow (#193531)\n\n**Epic:**
https://github.com/elastic/kibana/issues/174168\r\n**Addresses:**
https://github.com/elastic/kibana/issues/171520\r\n\r\n##
Summary\r\n\r\nThis PR introduces a new `Update` tab allowing users to
resolve rule upgrade conflicts. It's a result of combination of
read-only components implemented in
#193261 and rule upgrade state
implemented in https://github.com/elastic/kibana/pull/191721.\r\n\r\n##
Details\r\n\r\nThe goal of this PR is to provide intermediate
integration between rule upgrade state
([PR](#191721)) and components
displaying the diff and read-only state
([PR](#193261)). It will
facilitate further development of rule field editable components and
streamline rule upgrade functionality developing.\r\n\r\n## How to
test?\r\n\r\nThe functionality is hidden under
`prebuiltRulesCustomizationEnabled` feature flag. Add the following to
your Kibana
config\r\n\r\n```yaml\r\nxpack.securitySolution.enableExperimental:\r\n
- prebuiltRulesCustomizationEnabled\r\n```\r\n\r\nWhen the above feature
flag enabled the new `Update` tab is displayed instead of the old
one.\r\n\r\n## Screenshots\r\n\r\nSuggested components design
\r\n![image](https://github.com/user-attachments/assets/b5aaf571-286a-4595-9bd4-fdaf9a423b03)\r\n\r\nNew
`Update` tab\r\n<img width=\"1718\" alt=\"image\"
src=\"https://github.com/user-attachments/assets/28aa6bb3-f805-4109-a808-d67e58c7c5b8\">","sha":"878ba134e96245b038a9765148ad48a36bb2aa4b"}}]}]
BACKPORT-->

Co-authored-by: Maxim Palenov <maxim.palenov@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting enhancement New value added to drive a business result Feature:Prebuilt Detection Rules Security Solution Prebuilt Detection Rules area release_note:skip Skip the PR/issue when compiling release notes Team:Detection Rule Management Security Detection Rule Management Team Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v8.16.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants