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

Project deletion metadata audit log #4262

Merged
merged 14 commits into from
Aug 28, 2024
Merged

Project deletion metadata audit log #4262

merged 14 commits into from
Aug 28, 2024

Conversation

teodor-yanev
Copy link
Contributor

Summary

Provide a brief overview of the changes and the issue being addressed.
Explain the rationale and any background necessary for understanding the changes.
List dependencies required by this change, if any.

In order for us to be able to calculate customer churn, we need to keep track of the deleted projects/accounts on Minder and the relevant metadata from a business perspective.

Fixes https://app.zenhub.com/workspaces/minder-sprints-666857b34fcef725d2efba7c/issues/gh/stacklok/infra/1906

Change Type

Mark the type of change your PR introduces:

  • 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

Outline how the changes were tested, including steps to reproduce and any relevant configurations.
Attach screenshots if helpful.

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.

@teodor-yanev teodor-yanev self-assigned this Aug 23, 2024
@coveralls
Copy link

coveralls commented Aug 23, 2024

Coverage Status

coverage: 53.943% (+0.2%) from 53.703%
when pulling 7324d0b on project-deletion-audit
into 0cbe5ab on main.

Copy link
Member

@evankanderson evankanderson left a comment

Choose a reason for hiding this comment

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

I think there are other paths which can delete projects, in particular at least https://github.com/stacklok/minder/blob/main/internal/projects/deleter.go#L70 and https://github.com/stacklok/minder/blob/main/internal/projects/deleter.go#L117.

There's a path via https://github.com/stacklok/minder/blob/main/internal/controlplane/identity_events.go#L81 where users who delete their Stacklok IDP accounts (e.g. in Keycloak) will have their resources automatically cleaned up. That seems to call the non-struct version of DeleteUser, which is also called by the DeleteUser grpc endpoint.

Comment on lines 67 to 68
// ProjectMetadata can be used to store project metadata in the context.
type ProjectMetadata struct {
Copy link
Member

Choose a reason for hiding this comment

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

Can we call this "ProjectTombstone" or "ProjectDeletion", so it's clear that this is specifically for the case when a project is deleted?

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 for catching that and my bad for the obvious miss!

I've added the log audit at the core function which seems to be called from all other paths.

Copy link
Member

@evankanderson evankanderson left a comment

Choose a reason for hiding this comment

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

(Realized the previous comment should have been as "request changes")

var err error
entitlements, err = qtx.GetEntitlementsByProjectID(ctx, projectID)
return err
})
Copy link
Contributor

Choose a reason for hiding this comment

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

If these calls aren't used anymore, can you clean these up from the database queries?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They are, in internal/projects/deleter.go

Copy link
Member

@evankanderson evankanderson left a comment

Choose a reason for hiding this comment

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

If we care about this functionality, we should add a test for it.

Comment on lines 190 to 208
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
var err error
profilesCount, err = qtx.CountProfilesByProjectID(ctx, projectID)
return err
})
g.Go(func() error {
var err error
reposCount, err = qtx.CountRepositoriesByProjectID(ctx, projectID)
return err
})
g.Go(func() error {
var err error
entitlements, err = qtx.GetEntitlementsByProjectID(ctx, projectID)
return err
})

if err := g.Wait(); err != nil {
return nil, fmt.Errorf("error getting project metadata: %w", err)
Copy link
Member

Choose a reason for hiding this comment

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

Is it worth the effort to parallelize these three queries?

)

g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
Copy link
Member

Choose a reason for hiding this comment

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

If you use a named argument, this would be much shorter:

g.Go(func() err error {
  profilesCount, err = qtx.CountProfilesByProjectID(ctx, projectID)
}

return nil, fmt.Errorf("error getting project metadata: %w", err)
}

var entitlementsFeatures []string
Copy link
Member

Choose a reason for hiding this comment

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

Use make with a size argument to avoid needing extra resizes:

Suggested change
var entitlementsFeatures []string
entitlementsFeatures := make([]string, 0, len(entitlements))

Comment on lines 54 to 59
mockStore.EXPECT().CountProfilesByProjectID(gomock.Any(), proj).
Return(int64(0), nil)
mockStore.EXPECT().CountRepositoriesByProjectID(gomock.Any(), proj).
Return(int64(0), nil)
mockStore.EXPECT().GetEntitlementsByProjectID(gomock.Any(), proj).
Return([]db.Entitlement{}, nil)
Copy link
Member

Choose a reason for hiding this comment

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

Can you add at least one test where you verify that these are getting added to the telemetry context?

evankanderson
evankanderson previously approved these changes Aug 27, 2024
Copy link
Member

@evankanderson evankanderson left a comment

Choose a reason for hiding this comment

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

A couple very minor simplifications, but I think this can merge as-is.

Comment on lines 82 to 93
return pt.Project == other.Project &&
pt.ProfileCount == other.ProfileCount &&
pt.RepositoriesCount == other.RepositoriesCount &&
len(pt.Entitlements) == len(other.Entitlements) &&
func() bool {
for i, v := range pt.Entitlements {
if v != other.Entitlements[i] {
return false
}
}
return true
}()
Copy link
Member

Choose a reason for hiding this comment

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

This is probably simpler as:

Suggested change
return pt.Project == other.Project &&
pt.ProfileCount == other.ProfileCount &&
pt.RepositoriesCount == other.RepositoriesCount &&
len(pt.Entitlements) == len(other.Entitlements) &&
func() bool {
for i, v := range pt.Entitlements {
if v != other.Entitlements[i] {
return false
}
}
return true
}()
for i, v := range pt.Entitlements {
if v != other.Entitlements[i] {
return false
}
}
return pt.Project == other.Project &&
pt.ProfileCount == other.ProfileCount &&
pt.RepositoriesCount == other.RepositoriesCount &&
len(pt.Entitlements) == len(other.Entitlements)

Copy link
Contributor Author

@teodor-yanev teodor-yanev Aug 28, 2024

Choose a reason for hiding this comment

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

True -> updated

There is a potential out-of-bounds issue with the suggested code so I changed it a bit.

Comment on lines 10 to 12
FROM entitlements
WHERE project_id = sqlc.arg(project_id)::UUID;
Copy link
Member

Choose a reason for hiding this comment

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

I'm guessing if this was SELECT feature FROM entitlements you still wouldn't get a []string as the return type...

Copy link
Contributor Author

@teodor-yanev teodor-yanev Aug 28, 2024

Choose a reason for hiding this comment

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

It actually does return a []string. I did it this way to be more generic and reusable in the future but if you think it's better for this one to only return a slice of the feature names then I'm ok with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, thanks

evankanderson
evankanderson previously approved these changes Aug 28, 2024
Comment on lines 82 to 90
if len(pt.Entitlements) != len(other.Entitlements) {
return false
}

for i, v := range pt.Entitlements {
if v != other.Entitlements[i] {
return false
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Ooops, I just realized that there is slices.Equal that should do all this.

@evankanderson
Copy link
Member

Go ahead and merge without slices.Equal, or ping me when you push the change.

evankanderson
evankanderson previously approved these changes Aug 28, 2024
@teodor-yanev teodor-yanev merged commit 9a439d5 into main Aug 28, 2024
21 checks passed
@teodor-yanev teodor-yanev deleted the project-deletion-audit branch August 28, 2024 14:37
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