Guard scope grant emission behind WillSyncResourceType - #35
Conversation
Gates cross-type grant emission from the user syncer on the customer's sync filter, so grants aren't emitted for a resource type the sync excludes. Reference: ConductorOne/baton-linear#55. Each target is guarded individually in Grants(); when every target is excluded the user resource type is annotated SkipEntitlementsAndGrants so the SDK skips the pass entirely. Flags are named skip<Type>ResourceType and stored inverted so the zero value means "sync everything" — main.go registers a zero-value Connector{} as the capabilities factory, bypassing New. Build, tests, and golangci-lint (0 issues) pass. **No resource-type annotation here, deliberately.** `teammateBuilder` has entitlements of its own (`access`, grantable to subuser) and emits subuser grants alongside the scope grants, so `SkipEntitlements` / `SkipEntitlementsAndGrants` would suppress real data. Only the scope emission is gated, and the guard sits before the per-teammate scope lookup so the extra API call is skipped too.
|
|
||
| // New returns a new instance of the connector. | ||
| func New(ctx context.Context, sgClient SendGridClient, ignoreSubusers bool) (*Connector, error) { | ||
| func New(ctx context.Context, sgClient SendGridClient, ignoreSubusers bool, skipScopeResourceType bool) (*Connector, error) { |
There was a problem hiding this comment.
🟡 Suggestion: New now takes two adjacent, same-typed bool params (ignoreSubusers, skipScopeResourceType). Callers can silently swap them with no compile error, and this list will keep growing as more resource types get gated. Consider a small options struct (or variadic Opt funcs) so each flag is named at the call site.
| if opts.PageToken.Token == "" { | ||
| // Scope grants — only on the first (and only) page to avoid duplicate API | ||
| // calls, and only when scope is in the sync filter. | ||
| if opts.PageToken.Token == "" && !u.skipScopeResourceType { |
There was a problem hiding this comment.
🟡 Suggestion: the scope target is now gated, but the other cross-type emission in this same method — GetTeammatesSubAccess + createGrantSubuserFromTeammate (lines 231–247), whose grant principal is a subuser resource — is not. If subuser is excluded from the sync filter (or ignore_subusers is set, where subuserBuilder.List returns nothing), those grants still reference principals that were never synced. Pre-existing for the ignore_subusers path, but the same WillSyncResourceType(subuserResourceType.Id) guard would make this method internally consistent and skip the per-teammate subuser-access call too.
| inScope := &scopeCallRecorder{} | ||
| tb = newTeammateBuilder(inScope, false) | ||
| _, _, err = tb.Grants(ctx, res, rs.SyncOpAttrs{}) | ||
| require.NoError(t, err) | ||
| require.True(t, inScope.called, "scope lookup must run when scope is in the sync filter") |
There was a problem hiding this comment.
🟡 Suggestion: the positive branch discards grants and only asserts inScope.called. That passes even if the emission loop stopped producing scope grants entirely (e.g. a regression in the SendGridScopes lookup or scopeResource). Capture the grants and assert at least one has GetEntitlement().GetResource().GetId().GetResourceType() == scopeResourceType.Id — "mail.send" is a real entry in SendGridScopes, so exactly one scope grant is expected here.
Connector PR Review: Guard scope grant emission behind WillSyncResourceTypeBlocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0 Review SummaryScanned the full PR diff ( Security IssuesNone found. Correctness IssuesNone found. Suggestions
Prompt for AI agents |
Gates cross-type grant emission from the user syncer on the customer's sync
filter, so grants aren't emitted for a resource type the sync excludes.
Reference: ConductorOne/baton-linear#55.
Each target is guarded individually in Grants(); when every target is excluded
the user resource type is annotated SkipEntitlementsAndGrants so the SDK skips
the pass entirely.
Flags are named skipResourceType and stored inverted so the zero value
means "sync everything" — main.go registers a zero-value Connector{} as the
capabilities factory, bypassing New.
Build, tests, and golangci-lint (0 issues) pass.
No resource-type annotation here, deliberately.
teammateBuilderhasentitlements of its own (
access, grantable to subuser) and emits subuser grantsalongside the scope grants, so
SkipEntitlements/SkipEntitlementsAndGrantswould suppress real data. Only the scope emission isgated, and the guard sits before the per-teammate scope lookup so the extra API
call is skipped too.