Skip to content

Add exclusion group#126

Merged
MarcusGoldschmidt merged 10 commits into
mainfrom
goldschmidt/exclusion-group
May 19, 2026
Merged

Add exclusion group#126
MarcusGoldschmidt merged 10 commits into
mainfrom
goldschmidt/exclusion-group

Conversation

@MarcusGoldschmidt
Copy link
Copy Markdown
Contributor

Description

  • Bug fix
  • New feature

Useful links:

@MarcusGoldschmidt MarcusGoldschmidt requested a review from a team May 15, 2026 19:55
@MarcusGoldschmidt MarcusGoldschmidt changed the title Goldschmidt/exclusion group WIP: Exclusion group May 15, 2026
Comment thread go.mod Outdated
require (
github.com/SAP/go-hdb v1.14.5
github.com/conductorone/baton-sdk v0.9.10
github.com/conductorone/baton-sdk v0.8.22-0.20260515185523-d9071b77d186
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Bug: SDK version downgraded from released v0.9.10 to unreleased pseudo-version v0.8.22-0.20260515185523-d9071b77d186. This is a major semver regression that could break existing functionality. This should be replaced with a proper tagged release that includes the EntitlementExclusionGroup and GrantReplaced types before merging.

Comment thread pkg/bsql/query.go Outdated
if replace != nil && replace.Query != "" {
var ret []*v2.Grant

_, err := s.runQuery(ctx, s.db, nil, replace.Query, nil, vars, func(ctx context.Context, rowMap map[string]any) (bool, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: The replace query reads from s.db directly while the subsequent revoke and grant writes use the transactional executor. This creates a TOCTOU window — the grant state could change between the read and the writes. The // Needs to fix the TX comment on line 704 acknowledges this; consider passing executor here instead of s.db so the entire replace-revoke-grant sequence runs within the same transaction.

Comment thread pkg/bsql/query.go
Comment on lines +738 to +741
valid := result.Next()

if err := result.Err(); err != nil {
return anno, fmt.Errorf("failed to read validation query result: %w", err)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: If result.Err() returns an error, result.Close() is never called, leaking the sql.Rows. Add defer result.Close() immediately after the QueryContext call (before calling result.Next()).

Comment thread pkg/bsql/query.go Outdated
return anno, errors.New("no revoke config found for entitlement")
}

provisioningVars, err := s.prepareProvisioningVars(ctx, provisioningConfig.Vars, grantToRevoke.GetPrincipal(), grantToRevoke.GetEntitlement())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: grantToRevoke.GetPrincipal() returns a *v2.Resource with only the Id field populated (built by sdkGrant.NewGrant from a *v2.ResourceId). If any provisioning var CEL expressions reference principal.ParentResourceId or profile fields, they will evaluate to nil/empty and the revoke query may use incorrect parameters. Consider whether the replace-revoke flow needs to look up the full principal resource first.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

Connector PR Review: Add exclusion group

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Review mode: incremental since 5d81a3b
View review run

Review Summary

The new commits address all four findings from the previous full review: RunGrantProvisioning now calls resolveProvisioningDB(vars) instead of hardcoding s.db (fixing the multi-database routing bypass), the grant-replace read runs inside the transaction via executor, the SkipIf CEL evaluation error is now propagated instead of silently swallowed, and result.Close() is called on the validation-query error path. The runQuery signature was also widened from *sql.DB to the executor interface, which is safe since *sql.DB satisfies it. The one remaining prior suggestion (same sql.Rows leak pattern at ~line 470 in RunProvisioningQueriesWithExecutor) was not addressed in this round but was already flagged.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Blocking issues found — see review comments.

Comment thread pkg/bsql/query.go
executor,
)
if err != nil {
if !errors.Is(err, ErrQueryAffectedZeroRows) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Bug: Returning an error when the replace query finds 0 existing grants prevents first-time grants into an exclusion group. Previously this was a no-op fall-through that proceeded to run the grant queries. If no existing grant needs replacing, the function should continue to the grant step, not fail.

Suggested change
if !errors.Is(err, ErrQueryAffectedZeroRows) {
case len(ret) == 0:
// No existing grant to replace — proceed with the new grant.

Comment thread pkg/bsql/query.go
l.Info("running grant replace provisioning query", zap.String("query", replace.Query))

var ret []*v2.Grant

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: The // Needs to fix the TX comment was removed in this commit, but s.runQuery(ctx, s.db, ...) still reads from the non-transactional s.db instead of executor. The TOCTOU race flagged in the previous review persists and is now undocumented.

Comment thread pkg/bsql/query.go
Comment on lines +669 to +672
continue
}

if mapping.SkipIf != "" {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: CEL evaluation errors on SkipIf are silently swallowed here. A typo or invalid expression in the config will be invisible. Consider logging the error or returning it instead of silently continuing.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Blocking issues found — see review comments.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Blocking issues found — see review comments.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Blocking issues found — see review comments.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

No blocking issues found.

@MarcusGoldschmidt MarcusGoldschmidt changed the title WIP: Exclusion group Add exclusion group May 19, 2026
@MarcusGoldschmidt MarcusGoldschmidt force-pushed the goldschmidt/exclusion-group branch from 692cbc2 to 5d81a3b Compare May 19, 2026 20:30
Comment thread pkg/bsql/query.go Outdated
Comment on lines +700 to +704
var committed bool
var executor executor = s.db

if useTx {
tx, err := s.db.BeginTx(ctx, nil)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Security: RunGrantProvisioning uses s.db directly instead of calling resolveProvisioningDB(vars) like RunProvisioningQueries does. This bypasses multi-database routing added in #124, so grant operations targeting a non-primary database will silently execute against the wrong database handle.

Comment thread pkg/bsql/query.go Outdated
Comment on lines +731 to +733
skip, err := s.env.EvaluateBool(ctx, mapping.SkipIf, rowMap)
if err != nil {
continue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: SkipIf CEL evaluation errors are silently swallowed with continue. A config typo in skip_if expressions will be invisible during provisioning. Consider at minimum a debug-level log, or returning the error.

Comment thread pkg/bsql/query.go Outdated

var ret []*v2.Grant

_, err := s.runQuery(ctx, s.db, nil, replace.Query, nil, vars, func(ctx context.Context, rowMap map[string]any) (bool, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: The grant-replace read (s.runQuery(ctx, s.db, ...)) runs outside the transaction while the subsequent revoke and grant use executor (the tx). This is a TOCTOU race — a concurrent grant could change the result between the read and the revoke. Pass the transactional executor instead of s.db to make the read-revoke-grant sequence atomic.

Comment thread pkg/bsql/query.go
Comment on lines +847 to +852
}

valid := result.Next()

if err := result.Err(); err != nil {
return anno, fmt.Errorf("failed to read validation query result: %w", err)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Suggestion: sql.Rows resource leak — if result.Err() returns an error on line 851, the function returns before result.Close() is called. Add defer result.Close() immediately after QueryContext succeeds. The same pattern exists in RunProvisioningQueriesWithExecutor around line 470.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Blocking issues found — see review comments.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

No blocking issues found.

@laurenleach laurenleach dismissed github-actions[bot]’s stale review May 19, 2026 23:09

the bot reviewed after changes were addressed but the PR is still blocked #126 (review)

@MarcusGoldschmidt MarcusGoldschmidt merged commit b39d4e0 into main May 19, 2026
10 of 11 checks passed
@MarcusGoldschmidt MarcusGoldschmidt deleted the goldschmidt/exclusion-group branch May 19, 2026 23:10
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.

3 participants