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

asserts,registry: define confdb-control assertion #14705

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

st3v3nmw
Copy link

Define the confdb-control assertion and add a feature flag. The bits on the API (delegating, revoking, etc) will be added later when the design discussions are finalized.

Copy link

codecov bot commented Nov 11, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 77.99%. Comparing base (96ea7b0) to head (a1c0302).
Report is 137 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #14705      +/-   ##
==========================================
- Coverage   78.95%   77.99%   -0.96%     
==========================================
  Files        1084     1135      +51     
  Lines      146638   150521    +3883     
==========================================
+ Hits       115773   117403    +1630     
- Misses      23667    25854    +2187     
- Partials     7198     7264      +66     
Flag Coverage Δ
unittests 77.99% <100.00%> (-0.96%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@st3v3nmw st3v3nmw marked this pull request as ready for review November 11, 2024 14:21
@miguelpires miguelpires self-requested a review November 12, 2024 09:33
@miguelpires
Copy link
Contributor

For posterity, this was split off of #14508

@st3v3nmw st3v3nmw changed the title asserts: define confdb-control assertion asserts,confdb: define confdb-control assertion Nov 14, 2024
Comment on lines 73 to 79
cc := &ConfdbControl{
assertionBase: assert,
operators: make(map[string]*confdb.Operator),
}
if err := parseConfdbControlGroups(cc, groups); err != nil {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

In general, I'd say it's better to have parseConfdbControlGroups return a map[string]*confdb.Operator which gets put into cc rather than modify a parameter directly


func parseConfdbControlGroups(cc *ConfdbControl, rawGroups []interface{}) error {
for i, rawGroup := range rawGroups {
errPrefix := fmt.Sprintf("group at position %d", i+1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
errPrefix := fmt.Sprintf("group at position %d", i+1)
errPrefix := fmt.Sprintf("cannot parse group at position %d", i+1)

if err != nil {
return fmt.Errorf(`%s: "authentication" %w`, errPrefix, err)
}
if auth == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

This also needs to check that the auth method is operator-key or store

Copy link
Author

Choose a reason for hiding this comment

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

The check ends up happening inside registry/confdb_control/(AddGroup -> convertToAuthenticationMethod -> isValidAuthenticationMethod). It's a bit nested but if we do it here, we'll end up running the check twice. I could bump up the check though

Comment on lines 85 to 87
if len(auth) == 0 {
return fmt.Errorf(`"authentication" must be a non-empty list`)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no "authentication" here. I know this comes from the field in the assertion but out of that context it's not clear what this is referring to. The check should be reformulated

Copy link
Author

Choose a reason for hiding this comment

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

I've changed the errors to cannot add group: "auth" must be a non-empty list & cannot add group: "views" must be a non-empty list to be more descriptive. auth & views are the parameters passed to op.AddGroup

}

if len(views) == 0 {
return fmt.Errorf(`"views" must be a non-empty list`)
Copy link
Contributor

Choose a reason for hiding this comment

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

same

return nil
}

func compact[T comparable](s []T) []T {
Copy link
Contributor

Choose a reason for hiding this comment

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

This could use a comment mentioning that s has to be sorted

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this assertion can go into the file with the registry (soon to be confdb) assertion?

@@ -150,6 +154,7 @@ var featuresExported = map[SnapdFeature]bool{

RefreshAppAwarenessUX: true,
Registries: true,
ConfdbControl: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to export this flag? Based on the spec I don't see a reason to, at the moment, but maybe there's more to it

Copy link
Author

Choose a reason for hiding this comment

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

Yep, that flag shouldn't have been exported. Removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say lets put this in registry/ for now so it's grouped up with the other code. Once I open rename, it will all get moved together

@st3v3nmw st3v3nmw changed the title asserts,confdb: define confdb-control assertion asserts,registry: define confdb-control assertion Nov 20, 2024
@pedronis pedronis added the Needs Samuele review Needs a review from Samuele before it can land label Nov 20, 2024
miguelpires
miguelpires previously approved these changes Nov 26, 2024
Copy link
Contributor

@miguelpires miguelpires left a comment

Choose a reason for hiding this comment

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

thank you

}

// Group holds a set of views delegated through the given authentication.
type Group struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wondering whether DelegatedViews or ControlGroup wouldn't be better as Group is fairly generic but it's minor anyway

Copy link
Author

Choose a reason for hiding this comment

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

I was trying to match the spec but I agree, something like ControlGroup is clearer.

Thanks for the review!

Copy link
Collaborator

@pedronis pedronis Dec 3, 2024

Choose a reason for hiding this comment

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

given that is shows up as registry.Group I think we definitely need a more precise name, "group" in the context of the assertion is fine as it is scoped to the assertion, but the type name here is not

Copy link
Author

Choose a reason for hiding this comment

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

@pedronis, I've renamed it to ControlGroup... registry.ControlGroup or confdb.ControlGroup seems better.

Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

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

thank you, did a pass, main comment is how we store views in ControlGroup for usage

@@ -142,7 +142,7 @@ func (*viewSuite) TestNewRegistry(c *C) {
c.Assert(err.Error(), Equals, tc.err, cmt)
} else {
c.Assert(err, IsNil, cmt)
c.Check(registry, Not(IsNil), cmt)
c.Check(registry, NotNil, cmt)
Copy link
Collaborator

Choose a reason for hiding this comment

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

for next time: it's best to do this kind of small tweaks/fixes as their own PR or commit with something like "drive-by" in the commit message

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, I'll keep this in mind for future changes.

@@ -450,7 +450,7 @@ func getPlaceholders(viewStr string) map[string]bool {
return placeholders
}

// View returns an view from the registry.
// View returns a view from the registry.
Copy link
Collaborator

Choose a reason for hiding this comment

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

same

validAccountID = regexp.MustCompile("^(?:[a-z0-9A-Z]{32}|[-a-z0-9]{2,28})$")
)

type AuthenticationMethod string
Copy link
Collaborator

Choose a reason for hiding this comment

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

this probably merits a doc comment

Copy link
Author

Choose a reason for hiding this comment

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

I've added a comment here and to the OperatorKey & Store options

// ControlGroup holds a set of views delegated through the given authentication.
type ControlGroup struct {
Authentication []AuthenticationMethod
Views []string
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't this contain structs already parsed into account/confdb/view ?

Copy link
Author

Choose a reason for hiding this comment

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

In the assertion, the list of groups is flat.. like so:

groups:
  - operator-id:        john
    authentication: 	[ operator-key, store ]
    views:
      - a/b/c
      - d/e/f
  - operator-id:        john
    authentication: 	[ store ]
    views:
      - x/y/z

Internally though, we're grouping by operator to make this easier to look up later since all the API operations revolve around an operator. For instance, isDelegated(operator, view), delegate(operator, views, authMethods), revoke(operator, ...).

operators:
  john:
    ID: john
    Groups:
      - Authentication: [ operator-key, store ]
        Views:
          - a/b/c
          - d/e/f
      - Authentication: [ store ]
        Views:
          - x/y/z

Edit:

Or do you mean we should store the Views as a "set" for faster lookup.. Something like map[string]struct{}?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean of doing something like this after the parsing:

Views []*ViewRef

type ViewRef struct {
   Account string
   Confdb string
   View string
}

or similar

does this make sense to you @miguelpires as well ?

Copy link
Author

Choose a reason for hiding this comment

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

Ah, okay. That makes sense. I've made the necessary changes to reflect this.

Copy link
Contributor

Choose a reason for hiding this comment

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

makes sense to me 👍


// compact replaces consecutive runs of equal elements with a single copy.
// The provided slice s should be sorted.
func compact[T comparable](s []T) []T {
Copy link
Collaborator

Choose a reason for hiding this comment

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

unique might be a more common name for this

@@ -108,3 +109,110 @@ func assembleRegistry(assert assertionBase) (Assertion, error) {
timestamp: timestamp,
}, nil
}

// ConfdbControl holds a confdb-control assertion, which holds lists of
// views delegated by the device to an operator.
Copy link
Collaborator

Choose a reason for hiding this comment

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

s/to an operator/to operators/

}

// convertToAuthenticationMethod converts and validates a []string to []AuthenticationMethod
func convertToAuthenticationMethod(methods []string) ([]AuthenticationMethod, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe "...Methods" as it is producing a slice

})

// remove duplicates
methods = compact(methods)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see code in the tests that check that this is done

Copy link
Author

Choose a reason for hiding this comment

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

It's a bit hidden but this test checks that behavior

@pedronis pedronis dismissed miguelpires’s stale review December 4, 2024 11:13

changed enough that might be a good idea to re-review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Samuele review Needs a review from Samuele before it can land
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants