Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

feat/enterpriseportal: all subscriptions APIs use enterprise portal DB #63959

Conversation

bobheadxi
Copy link
Member

@bobheadxi bobheadxi commented Jul 19, 2024

This change follows https://github.com/sourcegraph/sourcegraph/pull/63858 by making the all subscriptions APIs read and write to the Enterprise Portal database, instead of dotcomdb, using the data that we sync from dotcomdb into Enterprise Portal.

With this PR, all initially proposed subscriptions APIs are at least partially implemented.

Uses hexops/valast#27 for custom autogold rendering of utctime.Time

Closes https://linear.app/sourcegraph/issue/CORE-156
Part of https://linear.app/sourcegraph/issue/CORE-158

Test plan

@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from 7e86a43 to 152047a Compare July 19, 2024 21:05
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from fa7d5bc to 2ada484 Compare July 19, 2024 21:05
@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from 152047a to 16bc317 Compare July 19, 2024 21:07
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from 2ada484 to 42751d4 Compare July 19, 2024 21:07
Comment on lines 63 to 87
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionRead)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)

subscriptionID := req.Msg.GetId()
if subscriptionID == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("subscription_id is required"))
}

sub, err := s.store.GetEnterpriseSubscription(ctx, subscriptionID)
if err != nil {
if errors.Is(err, subscriptions.ErrSubscriptionNotFound) {
return nil, connect.NewError(connect.CodeNotFound, err)
}
return nil, connectutil.InternalError(ctx, logger, err, "failed to find subscription")
}

proto := convertSubscriptionToProto(sub)
logger.Scoped("audit").Info("GetEnterpriseSubscription",
log.String("subscription", proto.Id))
return connect.NewResponse(&subscriptionsv1.GetEnterpriseSubscriptionResponse{
Subscription: proto,
}), nil

Check notice

Code scanning / Semgrep OSS

Semgrep Finding: security-semgrep-rules.semgrep-rules.generic.comment-tagging-rule Note

Code that highlight SECURITY in comment has changed. Please review the code for changes. The changes might be sensitive.
Comment on lines 611 to 757
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionWrite)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)

licenseID := req.Msg.LicenseId
if licenseID == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("license_id is required"))
}

license, err := s.store.RevokeEnterpriseSubscriptionLicense(ctx, licenseID, subscriptions.RevokeLicenseOpts{
Message: req.Msg.GetReason(),
Time: pointers.Ptr(utctime.Now()),
})
if err != nil {
if errors.Is(err, subscriptions.ErrSubscriptionLicenseNotFound) {
return nil, connect.NewError(connect.CodeNotFound, err)
}
return nil, connectutil.InternalError(ctx, logger, err, "failed to revoked license")
}

logger.Scoped("audit").Info("RevokeEnterpriseSubscriptionLicense",
log.String("subscription", license.SubscriptionID),
log.String("revokedLicense", license.ID))
return connect.NewResponse(&subscriptionsv1.RevokeEnterpriseSubscriptionLicenseResponse{}), nil

Check notice

Code scanning / Semgrep OSS

Semgrep Finding: security-semgrep-rules.semgrep-rules.generic.comment-tagging-rule Note

Code that highlight SECURITY in comment has changed. Please review the code for changes. The changes might be sensitive.
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from 42751d4 to 23df245 Compare July 19, 2024 21:26
@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from 16bc317 to d0bce4c Compare July 23, 2024 18:56
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from 23df245 to c2e0a5d Compare July 23, 2024 18:56
@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from d0bce4c to 80c6ad1 Compare July 23, 2024 19:05
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from c2e0a5d to cca76b4 Compare July 23, 2024 19:05
@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from 80c6ad1 to 99e6e2a Compare July 23, 2024 19:21
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from cca76b4 to 1cc2185 Compare July 23, 2024 19:21
@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from 99e6e2a to 38aaf6b Compare July 23, 2024 22:09
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from 1cc2185 to c6041c4 Compare July 23, 2024 22:09
@bobheadxi bobheadxi force-pushed the 07-18-feat_enterpriseportal_subscriptions_read_apis_use_enterprise_portal_db branch from 38aaf6b to d279b4e Compare July 23, 2024 23:43
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from c6041c4 to aea1c9a Compare July 23, 2024 23:43
@bobheadxi bobheadxi marked this pull request as ready for review July 23, 2024 23:46
@bobheadxi bobheadxi force-pushed the 07-26-feat_enterpriseportal_more_list_options_for_subscriptions_and_licenses branch from 480c94b to 8fd0533 Compare August 9, 2024 16:37
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from 06eecf1 to 2e737a6 Compare August 9, 2024 16:37
Base automatically changed from 07-26-feat_enterpriseportal_more_list_options_for_subscriptions_and_licenses to main August 9, 2024 16:43
@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from 2e737a6 to b042f89 Compare August 9, 2024 16:54
logger := trace.Logger(ctx, s.logger)

// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionRead)
Copy link
Member

Choose a reason for hiding this comment

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

Throughout this file it seems to use the string literal permission in numerous places rather than using the exported value from the sdk

Suggested change
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionRead)
requiredScope := samsm2m.EnterprisePortalScope(scopes.PermissionEnterprisePortalSubscription, scopes.ActionRead)

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right, this predates the change to make the permissions public consts - updated, thank you!

@bobheadxi bobheadxi force-pushed the 07-19-feat_enterpriseportal_all_subscriptions_apis_use_enterprise_portal_db branch from b042f89 to 9ae24a6 Compare August 10, 2024 00:02
Comment on lines +411 to +441
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope(
scopes.PermissionEnterprisePortalSubscription, scopes.ActionWrite)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)

sub := req.Msg.GetSubscription()
if sub == nil {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("subscription details are required"))
}

// Validate required arguments.
if strings.TrimSpace(sub.GetDisplayName()) == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("display_name is required"))
}

// Generate a new ID for the subscription.
if sub.Id != "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("subscription_id can not be set"))
}
sub.Id, err = s.store.GenerateSubscriptionID()
if err != nil {
return nil, connectutil.InternalError(ctx, s.logger, err, "failed to generate new subscription ID")
}

// Check for an existing subscription, just in case.
if _, err := s.store.GetEnterpriseSubscription(ctx, sub.Id); err == nil {
return nil, connect.NewError(connect.CodeAlreadyExists, err)

Check notice

Code scanning / Semgrep OSS

Semgrep Finding: security-semgrep-rules.semgrep-rules.generic.comment-tagging-rule Note

Code that highlight SECURITY in comment has changed. Please review the code for changes. The changes might be sensitive.
Comment on lines +574 to +604
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope(
scopes.PermissionEnterprisePortalSubscription, scopes.ActionWrite)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)

subscriptionID := req.Msg.GetSubscriptionId()
if subscriptionID == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("subscription_id is required"))
}

if _, err := s.store.GetEnterpriseSubscription(ctx, subscriptionID); err != nil {
if errors.Is(err, subscriptions.ErrSubscriptionNotFound) {
return nil, connect.NewError(connect.CodeNotFound, err)
}
return nil, connectutil.InternalError(ctx, logger, err, "failed to find subscription")
}

archivedAt := s.store.Now()

// First, revoke all licenses associated with this subscription
licenses, err := s.store.ListEnterpriseSubscriptionLicenses(ctx, subscriptions.ListLicensesOpts{
SubscriptionID: subscriptionID,
})
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "failed to list licenses for subscription")
}
revokedLicenses := make([]string, 0, len(licenses))

Check notice

Code scanning / Semgrep OSS

Semgrep Finding: security-semgrep-rules.semgrep-rules.generic.comment-tagging-rule Note

Code that highlight SECURITY in comment has changed. Please review the code for changes. The changes might be sensitive.
Comment on lines +658 to +687
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope(
scopes.PermissionEnterprisePortalSubscription, scopes.ActionWrite)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)

create := req.Msg.GetLicense()
if create.GetId() != "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("license.id cannot be set"))
}
subscriptionID := create.GetSubscriptionId()
if subscriptionID == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("license.subscription_id is required"))
}
sub, err := s.store.GetEnterpriseSubscription(ctx, subscriptionID)
if err != nil {
if errors.Is(err, subscriptions.ErrSubscriptionNotFound) {
return nil, connect.NewError(connect.CodeNotFound, err)
}
return nil, connectutil.InternalError(ctx, logger, err, "failed to find subscription")
}
if sub.ArchivedAt != nil {
return nil, connect.NewError(connect.CodeInvalidArgument,
errors.New("target subscription is archived"))
}

createdAt := s.store.Now()

Check notice

Code scanning / Semgrep OSS

Semgrep Finding: security-semgrep-rules.semgrep-rules.generic.comment-tagging-rule Note

Code that highlight SECURITY in comment has changed. Please review the code for changes. The changes might be sensitive.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants