From fd05f8a1aa91d0502e1223dca000e5d96be2f99f Mon Sep 17 00:00:00 2001 From: "c1-dev-bot[bot]" <2740113+c1-dev-bot[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 19:05:59 +0000 Subject: [PATCH 1/2] fix: gracefully skip databases on PermissionDenied in tableBuilder.List() When a service account can see a database via SHOW DATABASES but lacks SHOW SCHEMAS privilege, ListSchemasInDatabase returns PermissionDenied. Previously this hard-failed the entire sync. Now the connector: 1. Skips the database when GetDatabase returns HTTP 422 (early return before calling ListSchemasInDatabase) 2. Skips the database when ListSchemasInDatabase returns PermissionDenied 3. Skips individual schemas when ListTablesInSchema returns PermissionDenied All three cases log a warning and return empty results instead of propagating the error. --- pkg/connector/tables.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/pkg/connector/tables.go b/pkg/connector/tables.go index 10b93cd6..a15a9321 100644 --- a/pkg/connector/tables.go +++ b/pkg/connector/tables.go @@ -11,6 +11,10 @@ import ( "github.com/conductorone/baton-sdk/pkg/pagination" rs "github.com/conductorone/baton-sdk/pkg/types/resource" "github.com/conductorone/baton-snowflake/pkg/snowflake" + "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" + "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) const ( @@ -149,18 +153,31 @@ func (o *tableBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId // Encoding isSharedOrSystemDB in ResourceTypeID avoids re-querying the // database on every subsequent page. if bag.Current() == nil { + l := ctxzap.Extract(ctx) + parentDB, statusCode, err := o.client.GetDatabase(ctx, databaseName) if err != nil && !snowflake.IsUnprocessableEntity(statusCode, err) { return nil, nil, wrapError(err, "failed to get parent database") } + if snowflake.IsUnprocessableEntity(statusCode, err) { + l.Warn("Skipping database: insufficient privileges for GetDatabase", + zap.String("database", databaseName)) + return nil, &rs.SyncOpResults{}, nil + } + schemas, err := o.client.ListSchemasInDatabase(ctx, databaseName) if err != nil { + if status.Code(err) == codes.PermissionDenied { + l.Warn("Skipping database: insufficient privileges for ListSchemasInDatabase", + zap.String("database", databaseName)) + return nil, &rs.SyncOpResults{}, nil + } return nil, nil, wrapError(err, "failed to list schemas in database") } sharedFlag := "" - if snowflake.IsUnprocessableEntity(statusCode, nil) || (parentDB != nil && parentDB.IsSharedOrSystem()) { + if parentDB != nil && parentDB.IsSharedOrSystem() { sharedFlag = "shared" } @@ -188,6 +205,16 @@ func (o *tableBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId const pageSize = 200 tables, nextTableCursor, err := o.client.ListTablesInSchema(ctx, databaseName, schemaName, tableCursor, pageSize) if err != nil { + if status.Code(err) == codes.PermissionDenied { + l := ctxzap.Extract(ctx) + l.Warn("Skipping schema: insufficient privileges for ListTablesInSchema", + zap.String("database", databaseName), zap.String("schema", schemaName)) + nextToken, tokenErr := bag.NextToken("") + if tokenErr != nil { + return nil, nil, wrapError(tokenErr, "failed to create next page token") + } + return nil, &rs.SyncOpResults{NextPageToken: nextToken}, nil + } return nil, nil, wrapError(err, "failed to list tables in schema") } From d71a15d063fbada5f45075a53c529cf1b8985e4b Mon Sep 17 00:00:00 2001 From: "c1-dev-bot[bot]" <2740113+c1-dev-bot[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 19:16:21 +0000 Subject: [PATCH 2/2] fix: address lint issues in tableBuilder.List() Extract logger and database zap field to function scope to eliminate repeated string literals flagged by goconst. --- pkg/connector/tables.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pkg/connector/tables.go b/pkg/connector/tables.go index a15a9321..34b0d223 100644 --- a/pkg/connector/tables.go +++ b/pkg/connector/tables.go @@ -138,7 +138,9 @@ func (o *tableBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId return nil, nil, wrapError(fmt.Errorf("invalid parent resource type: %s", parentResourceID.ResourceType), "invalid parent resource type") } + l := ctxzap.Extract(ctx) databaseName := parentResourceID.Resource + dbField := zap.String("database_name", databaseName) bag := &pagination.Bag{} if err := bag.Unmarshal(opts.PageToken.Token); err != nil { @@ -153,24 +155,20 @@ func (o *tableBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId // Encoding isSharedOrSystemDB in ResourceTypeID avoids re-querying the // database on every subsequent page. if bag.Current() == nil { - l := ctxzap.Extract(ctx) - parentDB, statusCode, err := o.client.GetDatabase(ctx, databaseName) if err != nil && !snowflake.IsUnprocessableEntity(statusCode, err) { return nil, nil, wrapError(err, "failed to get parent database") } if snowflake.IsUnprocessableEntity(statusCode, err) { - l.Warn("Skipping database: insufficient privileges for GetDatabase", - zap.String("database", databaseName)) + l.Warn("Skipping database: insufficient privileges for GetDatabase", dbField) return nil, &rs.SyncOpResults{}, nil } schemas, err := o.client.ListSchemasInDatabase(ctx, databaseName) if err != nil { if status.Code(err) == codes.PermissionDenied { - l.Warn("Skipping database: insufficient privileges for ListSchemasInDatabase", - zap.String("database", databaseName)) + l.Warn("Skipping database: insufficient privileges for ListSchemasInDatabase", dbField) return nil, &rs.SyncOpResults{}, nil } return nil, nil, wrapError(err, "failed to list schemas in database") @@ -206,9 +204,8 @@ func (o *tableBuilder) List(ctx context.Context, parentResourceID *v2.ResourceId tables, nextTableCursor, err := o.client.ListTablesInSchema(ctx, databaseName, schemaName, tableCursor, pageSize) if err != nil { if status.Code(err) == codes.PermissionDenied { - l := ctxzap.Extract(ctx) l.Warn("Skipping schema: insufficient privileges for ListTablesInSchema", - zap.String("database", databaseName), zap.String("schema", schemaName)) + dbField, zap.String("schema_name", schemaName)) nextToken, tokenErr := bag.NextToken("") if tokenErr != nil { return nil, nil, wrapError(tokenErr, "failed to create next page token")