Reset access source name sync on connection change
Once the source-name worker sets name_synced_at, nothing cleared it, so a source that hit a terminal failure (Brex 403, wrong Sentry org slug) kept its generic name forever — even after the user reconnected with the right scope or picked the correct org, contradicting the Brex guidance to reconnect. Clear name_synced_at whenever the connection changes: on UpdateSource when a connector is (re)set, inside ConfigureAccessReviewSource when the org is (re)selected, and on the OAuth reconnect path via the new ResetSourceNameSyncForConnector service method. The worker then re-claims the row and re-resolves the display name. Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
This commit is contained in:
@@ -184,6 +184,11 @@ func (s *Service) UpdateSource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
source.ConnectorID = *req.ConnectorID
|
source.ConnectorID = *req.ConnectorID
|
||||||
|
|
||||||
|
// A (re)linked connector may resolve to a different instance
|
||||||
|
// name; clear the synced flag so the source-name worker picks
|
||||||
|
// the row up and re-resolves it.
|
||||||
|
source.NameSyncedAt = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.CsvData != nil {
|
if req.CsvData != nil {
|
||||||
@@ -444,6 +449,16 @@ func (s *Service) ConfigureAccessReviewSource(
|
|||||||
return fmt.Errorf("cannot update connector: %w", err)
|
return fmt.Errorf("cannot update connector: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The selected org changed, so the resolvable instance name may
|
||||||
|
// have too; clear the synced flag so the source-name worker
|
||||||
|
// re-resolves the display name.
|
||||||
|
source.NameSyncedAt = nil
|
||||||
|
source.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := source.Update(ctx, conn, scope); err != nil {
|
||||||
|
return fmt.Errorf("cannot reset access source name sync: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -453,3 +468,22 @@ func (s *Service) ConfigureAccessReviewSource(
|
|||||||
|
|
||||||
return source, nil
|
return source, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResetSourceNameSyncForConnector clears the synced-name flag on every access
|
||||||
|
// source backed by connectorID so the source-name worker re-resolves the
|
||||||
|
// display name. Called after a connector is reconnected — the new grant may
|
||||||
|
// scope a different org/workspace, changing the resolvable name.
|
||||||
|
func (s *Service) ResetSourceNameSyncForConnector(
|
||||||
|
ctx context.Context,
|
||||||
|
scope coredata.Scoper,
|
||||||
|
connectorID gid.GID,
|
||||||
|
) error {
|
||||||
|
return s.pg.WithTx(
|
||||||
|
ctx,
|
||||||
|
func(ctx context.Context, conn pg.Tx) error {
|
||||||
|
sources := &coredata.AccessReviewSources{}
|
||||||
|
|
||||||
|
return sources.ClearNameSyncedAtByConnectorID(ctx, conn, scope, connectorID)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -359,6 +359,43 @@ WHERE
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearNameSyncedAtByConnectorID resets name_synced_at to NULL for every
|
||||||
|
// access source backed by connectorID so the source-name worker re-resolves
|
||||||
|
// the display name. A reconnect (possibly with a new scope/org) or a manual
|
||||||
|
// org (re)configuration can change the resolvable instance name; without this
|
||||||
|
// a source that was terminal-marked keeps its generic name forever. It is a
|
||||||
|
// no-op when no source references the connector.
|
||||||
|
func (sources *AccessReviewSources) ClearNameSyncedAtByConnectorID(
|
||||||
|
ctx context.Context,
|
||||||
|
conn pg.Tx,
|
||||||
|
scope Scoper,
|
||||||
|
connectorID gid.GID,
|
||||||
|
) error {
|
||||||
|
q := `
|
||||||
|
UPDATE access_review_sources
|
||||||
|
SET
|
||||||
|
name_synced_at = NULL,
|
||||||
|
updated_at = @updated_at
|
||||||
|
WHERE
|
||||||
|
%s
|
||||||
|
AND connector_id = @connector_id
|
||||||
|
AND name_synced_at IS NOT NULL
|
||||||
|
`
|
||||||
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
|
args := pgx.StrictNamedArgs{
|
||||||
|
"connector_id": connectorID,
|
||||||
|
"updated_at": time.Now(),
|
||||||
|
}
|
||||||
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
|
if _, err := conn.Exec(ctx, q, args); err != nil {
|
||||||
|
return fmt.Errorf("cannot clear access source name sync: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ErrNoAccessReviewSourceNameSyncAvailable is returned when no access source
|
// ErrNoAccessReviewSourceNameSyncAvailable is returned when no access source
|
||||||
// needs its name synced from its connector.
|
// needs its name synced from its connector.
|
||||||
var ErrNoAccessReviewSourceNameSyncAvailable = fmt.Errorf("no access source name sync available")
|
var ErrNoAccessReviewSourceNameSyncAvailable = fmt.Errorf("no access source name sync available")
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ func NewMux(
|
|||||||
logger,
|
logger,
|
||||||
baseURL,
|
baseURL,
|
||||||
proboSvc,
|
proboSvc,
|
||||||
|
accessReviewSvc,
|
||||||
connectorRegistry,
|
connectorRegistry,
|
||||||
safeRedirect,
|
safeRedirect,
|
||||||
),
|
),
|
||||||
@@ -174,6 +175,7 @@ func handleConnectorComplete(
|
|||||||
logger *log.Logger,
|
logger *log.Logger,
|
||||||
baseURL *baseurl.BaseURL,
|
baseURL *baseurl.BaseURL,
|
||||||
proboSvc *probo.Service,
|
proboSvc *probo.Service,
|
||||||
|
accessReviewSvc *accessreview.Service,
|
||||||
connectorRegistry *connector.ConnectorRegistry,
|
connectorRegistry *connector.ConnectorRegistry,
|
||||||
safeRedirect *saferedirect.SafeRedirect,
|
safeRedirect *saferedirect.SafeRedirect,
|
||||||
) http.HandlerFunc {
|
) http.HandlerFunc {
|
||||||
@@ -309,6 +311,14 @@ func handleConnectorComplete(
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The reconnect may carry a different scope/org, changing the
|
||||||
|
// resolvable instance name. Clear the synced-name flag so the
|
||||||
|
// source-name worker re-resolves it. Best-effort: a failure here
|
||||||
|
// must not fail the OAuth callback redirect.
|
||||||
|
if err := accessReviewSvc.ResetSourceNameSyncForConnector(r.Context(), scope, cnnctr.ID); err != nil {
|
||||||
|
logger.WarnCtx(r.Context(), "cannot reset access source name sync after reconnect", log.Error(err))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
createReq := probo.CreateConnectorRequest{
|
createReq := probo.CreateConnectorRequest{
|
||||||
OrganizationID: organizationID,
|
OrganizationID: organizationID,
|
||||||
|
|||||||
Reference in New Issue
Block a user