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 the /upgrade/_review endpoint contract and functionality #187770

Merged
merged 38 commits into from
Jul 25, 2024

Conversation

jpdjere
Copy link
Contributor

@jpdjere jpdjere commented Jul 8, 2024

Resolves: #180153
Resolves: #188277

Summary

  • Extend the POST /upgrade/_review API endpoint's contract and functionality

  • Changes has_conflict property within each rule field's ThreeWayDiff from boolean to enum with possible values:

    • NONE: no conflicts in three way diff
    • SOLVABLE: conflict detected but was successfully resolved by our algorithms
    • NON_SOLVABLE: conflict detected and could not be resolved by our algorithms.
  • Adds has_base_version boolean field within each field diff calculation. Has values:

    • true: the base version of the field was found and is either defined or undefined
    • false: the base version of the field was not found
  • The possible values for has_conflict for each concrete diff algorithm are:

    • single line strings: NO, NON_SOLVABLE
    • multi line strings: NO, SOLVABLE, NON_SOLVABLE
    • numbers: NO, NON_SOLVABLE
    • array of scalar values: NO, SOLVABLE
  • Adds new logic to handle [Security Solution] Updates diff outcome logic to return CustomizedValueCanUpdate on scenario -AB #186435 (comment)

For maintainers

@jpdjere jpdjere added 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 8.16 candidate labels Jul 8, 2024
@jpdjere jpdjere self-assigned this Jul 8, 2024
@jpdjere jpdjere added release_note:skip Skip the PR/issue when compiling release notes Feature:Prebuilt Detection Rules Security Solution Prebuilt Detection Rules area v8.16.0 and removed 8.16 candidate labels Jul 8, 2024
@jpdjere
Copy link
Contributor Author

jpdjere commented Jul 8, 2024

/ci

2 similar comments
@jpdjere
Copy link
Contributor Author

jpdjere commented Jul 9, 2024

/ci

@jpdjere
Copy link
Contributor Author

jpdjere commented Jul 10, 2024

/ci

@jpdjere
Copy link
Contributor Author

jpdjere commented Jul 12, 2024

/ci

@jpdjere jpdjere marked this pull request as ready for review July 15, 2024 10:14
@jpdjere jpdjere requested a review from a team as a code owner July 15, 2024 10:14
@jpdjere jpdjere requested a review from dplumlee July 15, 2024 10:14
@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)

Copy link
Contributor

@dplumlee dplumlee left a comment

Choose a reason for hiding this comment

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

This looks good for the most part @jpdjere! Just left one comment about naming and we can figure out how to sync with #188022

@@ -19,6 +19,12 @@ import type { ThreeWayMergeOutcome } from './three_way_merge_outcome';
export const MissingVersion = Symbol('MissingVersion');
export type MissingVersion = typeof MissingVersion;

export enum ThreeWayDiffConflictResolutionResult {
NO = 'NO',
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be something like NO_CONFLICT? I guess NO makes sense in the conflict: no assignment but it does look a bit weird standalone

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the enum for clarity

@jpdjere jpdjere requested a review from a team as a code owner July 17, 2024 09:36
@jpdjere jpdjere requested a review from a team as a code owner July 22, 2024 11:26
@jpdjere jpdjere requested a review from nkhristinin July 22, 2024 11:26
@jpdjere
Copy link
Contributor Author

jpdjere commented Jul 22, 2024

@banderror @nikitaindik @dplumlee

Thanks for the review. I've addressed your feedback, and included in the changes of this PR the handling of scenarios with a missing base version, with the "compromise" solution we had decided here.

Please take a look when you can.

@jpdjere jpdjere removed request for nkhristinin and a team July 22, 2024 15:42
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 updates to PR @jpdjere! I have only reviewed changes related to MissingVersion - they look good to me!

Copy link
Contributor

@dplumlee dplumlee left a comment

Choose a reason for hiding this comment

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

The new changes look great to me @jpdjere, thanks for incorporating all this into the existing diff work! I do like the idea you mentioned here, not sure if there's a reason we didn't incorporate this before other than not really having any special logic needs for those cases with the initial implementation

@@ -144,10 +138,11 @@ describe('multiLineStringDiffAlgorithm', () => {

expect(result).toEqual(
expect.objectContaining({
has_base_version: false,
base_version: undefined,
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Comment on lines 81 to 83
case ThreeWayDiffOutcome.StockValueNoUpdate: // Scenarios AAA and -AA
case ThreeWayDiffOutcome.CustomizedValueNoUpdate: // Scenario ABA
case ThreeWayDiffOutcome.CustomizedValueSameUpdate: // Scenario ABB
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice idea to put these scenarios in here, I think I'll incorporate this into some other diff files as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dplumlee I ended up removing these, since now each scenario has its own ThreeWayDiffOutcome and there's no case like // Scenarios AAA and -AA anymore.

@jpdjere jpdjere requested a review from banderror July 24, 2024 13:53
@jpdjere
Copy link
Contributor Author

jpdjere commented Jul 24, 2024

@banderror Reintroduced ThreeWayMergeOutcome enum as we discussed.

@dplumlee While introducing/modifying the integration tests for scenarios MissingBaseNoUpdate and MissingBaseCanUpdate, I realised that doing assertions on the whole reviewResponse.rules[0].diff.fields object was confusing, since version is always present and we need to describe its behaviour in all unrelated tests.

For example, the assertion in the case of the -AA or MissingBaseNoUpdate scenario was:

              const reviewResponse = await reviewPrebuiltRulesToUpgrade(supertest);
              expect(reviewResponse.rules[0].diff.fields).toEqual({
                version: {
                  current_version: 1,
                  target_version: 2,
                  merged_version: 2,
                  diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate,
                  merge_outcome: ThreeWayMergeOutcome.Target,
                  has_conflict: false,
                  has_update: true,
                },
              });

which in my opinion creates cognitive dissonance because the reader of the test is expecting to see diff_outcome: ThreeWayDiffOutcome.MissingBaseNoUpdate but actually sees StockValueCanUpdate. It might take a while to realize that StockValueCanUpdate refers only to version and that the actual field being tested actually does have has a merge_outcome of ThreeWayDiffOutcome.MissingBaseNoUpdate, but it's just not returned as part of the diff object by the endpoint.

So I went ahead and simplified all integration tests, now doing assertions only on the field that should/shouldn't be part of the diff object - so that if the scenario excludes the field from the diff object, then the assertion is just expect(reviewResponse.rules[0].diff.fields.name).toBeUndefined().

So now the focus of each test is exclusively on the field that corresponds to the algorithm type.

Copy link
Contributor

@banderror banderror left a comment

Choose a reason for hiding this comment

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

Thanks @jpdjere, I left a couple more comments. Approving in advance 👍

}

const addedCurrent = difference(dedupedCurrentVersion, dedupedBaseVersion);
const addedCurrent = difference(dedupedCurrentVersion, dedupedBaseVersion as TValue[]);
Copy link
Contributor

Choose a reason for hiding this comment

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

We always try to avoid as casting in production code, can we try to rewrite this algorithm in a type-safe way?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

const removedCurrent = difference(dedupedBaseVersion, dedupedCurrentVersion);

const addedTarget = difference(dedupedTargetVersion, dedupedBaseVersion);
const addedTarget = difference(dedupedTargetVersion, dedupedBaseVersion as TValue[]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

const mergedVersion = merge(currentVersion, baseVersion, targetVersion, {
// TS does not realize that in ABC scenario, baseVersion cannot be missing
// Missing baseVersion scenarios were handled as -AA and -AB.
const mergedVersion = merge(currentVersion, baseVersion as string, targetVersion, {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

@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 5611 5612 +1

Async chunks

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

id before after diff
securitySolution 20.4MB 20.4MB +568.0B

History

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

cc @jpdjere

@jpdjere jpdjere merged commit fb82b0e into elastic:main Jul 25, 2024
40 checks passed
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Jul 25, 2024
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 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
7 participants