Skip to content

Conversation

@javirln
Copy link
Member

@javirln javirln commented Jun 13, 2024

This patch introduces a new configuration option that enables a Chainloop instance to automatically onboard new users into predefined organizations with specific roles.

For example:

# config.devel.yaml

# Previous existing configuration

onboarding:
  - name: "read-only-demo"
    role: "viewer"
  - name: "read-write-demo"
    role: "owner"

With this configuration, new and existing users will be automatically onboarded into the read-only-demo and chainloop organizations with the roles of viewer and owner, respectively. When users log in to Chainloop for the first time, the server will:

  • Find or create the specified organizations
  • Create memberships for users in these organizations if they do not already exist. Existing memberships will not be modified.

Refs #942

Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln javirln requested review from jiparis and migmartri June 13, 2024 16:40
Copy link
Member

@migmartri migmartri left a comment

Choose a reason for hiding this comment

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

More feedback to come

Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
Copy link
Member

@migmartri migmartri left a comment

Choose a reason for hiding this comment

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

Some comments on code structuring and how to use what we already have.

Thanks!

Copy link
Member

@migmartri migmartri left a comment

Choose a reason for hiding this comment

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

requesting changes per our conversation offline, thanks

@javirln javirln marked this pull request as draft June 14, 2024 11:27
@javirln javirln self-assigned this Jun 16, 2024
Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln javirln marked this pull request as ready for review June 17, 2024 06:49
@javirln
Copy link
Member Author

javirln commented Jun 17, 2024

All changes addressed:

  • Moved logic to biz
  • Moved all integration tests to organization_integration_tests
  • Example of configuration the sample config
  • Created an alternative method of creating users otherwise integration tests won't make sense. Another option was to use a repo on the integration tests but, not super happy about it.

Copy link
Member

@migmartri migmartri left a comment

Choose a reason for hiding this comment

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

Thanks Javi, looks good in general!

// If the organization does not exist, it creates it.
func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spec *conf.OnboardingSpec) (*Organization, error) {
// Ensure the organization exists or create it if it doesn't
org, err := uc.FindByName(ctx, spec.GetName())
Copy link
Member

Choose a reason for hiding this comment

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

why are you using the use-case here instead of the existing underlying repo? I'd say that this private method should use the private repo instead. It will also make error handling easier.

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed the method and used the repos instead.

return uc.userRepo.Delete(ctx, userUUID)
}

func (uc *UserUseCase) CreateByEmail(ctx context.Context, email string) (*User, error) {
Copy link
Member

Choose a reason for hiding this comment

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

I have mixed feelings of creating methods just for testing (same about findbyname), it feels upside down to me.

In fact I think in this case this is wrong and can be confusing, it's not trivial to know that createbyemail will not add auto-onboarding.

Personally, I've have passed an extra optional argument WithDisableAutoOnboarding or make it part of the the userUsecase struct`

Copy link
Member Author

@javirln javirln Jun 17, 2024

Choose a reason for hiding this comment

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

This additional methods were to ease the testing indeed since I didn't want to use the repos on the integration tests but well, seems we can do it as well.

I've added an optional parameter to the method to disable the auto onboarding. Please note that I didn't create a regular Builder with all Its options because I do believe it's too verbose for just one configuration.

@javirln javirln marked this pull request as draft June 17, 2024 09:30
Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
Copy link
Member Author

@javirln javirln left a comment

Choose a reason for hiding this comment

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

I've removed the methods FinByName and CreateByEmail, the dependencies on the private methods and reworked on the tests

// If the organization does not exist, it creates it.
func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spec *conf.OnboardingSpec) (*Organization, error) {
// Ensure the organization exists or create it if it doesn't
org, err := uc.FindByName(ctx, spec.GetName())
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed the method and used the repos instead.

return uc.userRepo.Delete(ctx, userUUID)
}

func (uc *UserUseCase) CreateByEmail(ctx context.Context, email string) (*User, error) {
Copy link
Member Author

@javirln javirln Jun 17, 2024

Choose a reason for hiding this comment

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

This additional methods were to ease the testing indeed since I didn't want to use the repos on the integration tests but well, seems we can do it as well.

I've added an optional parameter to the method to disable the auto onboarding. Please note that I didn't create a regular Builder with all Its options because I do believe it's too verbose for just one configuration.

@javirln javirln marked this pull request as ready for review June 17, 2024 10:00
Copy link
Member

@migmartri migmartri left a comment

Choose a reason for hiding this comment

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

LGTM!


// ensureOrganizationExists ensures that an organization specified by the onboarding configuration exists.
// If the organization does not exist, it creates it.
func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spec *conf.OnboardingSpec) (*Organization, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Not a blocker but in general I prefer to make the arguments as scooped down as possible. For example instead of the whole spec, here I think you just need the name string, and in the other one you need the role.

Copy link
Member

Choose a reason for hiding this comment

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

👍 I agree. It would be simpler to just pass the name of the org.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree with you but in this case, we need the whole spec, the expected roles as well, so effectively what's being passed in the name of the orgs and the roles it should be applied.


// ensureOrganizationExists ensures that an organization specified by the onboarding configuration exists.
// If the organization does not exist, it creates it.
func (uc *OrganizationUseCase) ensureOrganizationExists(ctx context.Context, spec *conf.OnboardingSpec) (*Organization, error) {
Copy link
Member

Choose a reason for hiding this comment

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

👍 I agree. It would be simpler to just pass the name of the org.

// FindOrCreateByEmail finds or creates a user by email. By default, it will auto-onboard the user
// to the organizations defined in the configuration. If disableAutoOnboarding is set to true, it will
// skip the auto-onboarding process.
func (uc *UserUseCase) FindOrCreateByEmail(ctx context.Context, email string, disableAutoOnboarding ...bool) (*User, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Why ...bool? How many bools are we expecting here?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's an optional parameter otherwise we would have to add that parameter to all occurrences.

org, err := uc.orgRepo.FindByName(ctx, spec.GetName())
if err != nil {
return nil, fmt.Errorf("failed to find organization: %w", err)
} else if org == nil {
Copy link
Member

Choose a reason for hiding this comment

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

I might be wrong, but I remember we talked offline about about not creating orgs, and assume they existed previously.

Copy link
Member Author

Choose a reason for hiding this comment

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

As far as I remember if it was because of the possible collisions it was solved on the DB. In any case we can always come back and remove it.

Maybe when we have #945 done.

Copy link
Member

Choose a reason for hiding this comment

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

True, I'd do it in another smaller follow up PR

Copy link
Member

@jiparis jiparis left a comment

Choose a reason for hiding this comment

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

Thanks! Just a couple of minor comments.

@javirln javirln merged commit 8c537cf into main Jun 17, 2024
@javirln javirln deleted the feat/942-auto-onboarding branch June 17, 2024 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants