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

Take selectors into use in executor #4004

Merged
merged 7 commits into from
Jul 26, 2024
Merged

Conversation

jhrozek
Copy link
Contributor

@jhrozek jhrozek commented Jul 25, 2024

Summary

  • Change the BulkGetProfilesByID DB query to return an embedded profile - This will make it easier to extend what the query returns
  • Extend the BulkGetProfilesByID DB query with selectors - This is to return the selectors at the same time as querying the profiles from the DB and be able to use them in the executor.
  • Extend the ProfileAggregate structure with selectors - returns the selectors to the engine through the ProfileAggregate struct
  • Change the selector's NewSelectionFromProfile API to accept the structure from the models API - This will make it easier to use the method in the executor
  • Integrate the selectors into the executor - When an entity is not selected for a profile, let's save that into a profile-global status override and use that for all the statuses instead of calling eval
  • Include which selector did unselect the entity - In addition to returning a bool, let's also return which selector did shortcut the evaluation when returning false

Fixes: #3724
Fixes: #3725

Change Type

  • Bug fix (resolves an issue without affecting existing features)
  • Feature (adds new functionality without breaking changes)
  • Breaking change (may impact existing functionalities or require documentation updates)
  • Documentation (updates or additions to documentation)
  • Refactoring or test improvements (no bug fixes or new functionality)

Testing

manual

Review Checklist:

  • Reviewed my own code for quality and clarity.
  • Added comments to complex or tricky code sections.
  • Updated any affected documentation.
  • Included tests that validate the fix or feature.
  • Checked that related changes are merged.

@jhrozek jhrozek requested a review from a team as a code owner July 25, 2024 21:21
GROUP BY pr.id
)
SELECT sqlc.embed(profiles),
helper.selectors::profile_selector[] AS profiles_with_selectors
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If this is too hairy, we can instead just loop over the profiles and do a get for each profile

Copy link
Contributor Author

Choose a reason for hiding this comment

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

on the other hand, having everything in a single call is probably safer in the long run

@@ -107,6 +107,7 @@ func newEnvForEntity(varName string, typ any, typName string) (*cel.Env, error)
}

type compiledSelector struct {
orig string
Copy link
Contributor Author

Choose a reason for hiding this comment

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

there is ast.ToString but it doesn't guarantee that the result will be exactly the same, only that it will have the same meaning..

@@ -258,9 +260,9 @@ type EntitySelection struct {
}

// Select return true if the entity matches all the compiled expressions and false otherwise
func (s *EntitySelection) Select(se *internalpb.SelectorEntity, userOpts ...SelectOption) (bool, error) {
func (s *EntitySelection) Select(se *internalpb.SelectorEntity, userOpts ...SelectOption) (bool, string, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I started wondering if it would be better to return a struct that would contain bool and string for now. Three return values from a function already starts to smell especially if the function is used in an interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think having a dedicated struct would be cleaner in terms of returning it and using it. A bool and a string can get confusing. However, this is not blocking IMO and can be done later.

Copy link
Member

Choose a reason for hiding this comment

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

Alternatively, you could use presence or absence of the error as part of the boolean (and a particular error interface to indicate "not selected"), but I'm happy with this interface.

@coveralls
Copy link

coveralls commented Jul 25, 2024

Coverage Status

coverage: 54.504% (+0.06%) from 54.441%
when pulling 1d88d5b on jhrozek:selectors_executor
into b9170e5 on stacklok:main.

@@ -131,10 +136,14 @@ func (e *executor) EvalEntityEvent(ctx context.Context, inf *entities.EntityInfo
return fmt.Errorf("error while retrieving profiles and rule instances: %w", err)
}

// For each profile, evaluate each rule and store the outcome in the database
// For each profile, get the profile-override status. Then, if there is no profile-override status,
// evaluate each rule and store the outcome in the database or store the override status for all rules
Copy link
Contributor

Choose a reason for hiding this comment

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

remind me what the "profile override status" is

JAORMX
JAORMX previously approved these changes Jul 26, 2024
Copy link
Contributor

@JAORMX JAORMX left a comment

Choose a reason for hiding this comment

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

logic LGTM

for _, profile := range profileAggregates {

profileEvalStatus := e.profileEvalStatus(ctx, provider, inf, profile)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@JAORMX I called the variable actually profileEvalStatus, but "profile-override status" in the comment. I'll fix the naming since it's confusing.

This will make it easier to extend what the query returns
This is to return the selectors at the same time as querying the
profiles from the DB and be able to use them in the executor.
This returns the selectors to the engine through the ProfileAggregate
structure
…ture from the models API

This will make it easier to use the method in the executor
When an entity is not selected for a profile, let's save that into a
profile-global status override and use that for all the statuses instead
calling eval.

Fixes: mindersec#3724
In addition to returning a bool, let's also return which selector did
shortcut the evaluation when returning false
@jhrozek jhrozek merged commit c9688e6 into mindersec:main Jul 26, 2024
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants