Skip to content

Commit d121fc0

Browse files
authored
Merge pull request #10 from ApplauseOSS/fix/filter-out-ownership-grants
fix: Filter out OWNERSHIP grants from toRevoke map
2 parents c797072 + 1d84728 commit d121fc0

1 file changed

Lines changed: 53 additions & 43 deletions

File tree

internal/role/role.go

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func LoadRolesConfig(filePath string) (*RolesConfig, error) {
110110
}
111111
defer func() {
112112
if cerr := file.Close(); cerr != nil {
113-
logger.Error("failed to close file", "error", cerr)
113+
logger.ErrorContext(context.Background(), "failed to close file", "error", cerr)
114114
}
115115
}()
116116

@@ -128,7 +128,7 @@ func FetchShowRoles(db *sql.DB) (map[string]struct{}, error) {
128128
ctx := context.Background()
129129
rows, err := db.QueryContext(ctx, "SHOW ROLES")
130130
if err != nil {
131-
logger.Error("query SHOW ROLES failed", "error", err)
131+
logger.ErrorContext(context.Background(), "query SHOW ROLES failed", "error", err)
132132
return nil, fmt.Errorf("error querying SHOW ROLES: %w", err)
133133
}
134134
defer rows.Close()
@@ -159,7 +159,7 @@ func FetchShowRoles(db *sql.DB) (map[string]struct{}, error) {
159159
roles := make(map[string]struct{})
160160
for rows.Next() {
161161
if err := rows.Scan(vals...); err != nil {
162-
logger.Error("scanning SHOW ROLES row failed", "error", err)
162+
logger.ErrorContext(context.Background(), "scanning SHOW ROLES row failed", "error", err)
163163
return nil, fmt.Errorf("error scanning SHOW ROLES: %w", err)
164164
}
165165
if raw[nameIdx].Valid {
@@ -178,7 +178,7 @@ func FetchShowUsers(db *sql.DB) (map[string]string, error) {
178178
ctx := context.Background()
179179
rows, err := db.QueryContext(ctx, "SHOW USERS")
180180
if err != nil {
181-
logger.Error("query SHOW USERS failed", "error", err)
181+
logger.ErrorContext(context.Background(), "query SHOW USERS failed", "error", err)
182182
return nil, fmt.Errorf("error querying SHOW USERS: %w", err)
183183
}
184184
defer rows.Close()
@@ -211,7 +211,7 @@ func FetchShowUsers(db *sql.DB) (map[string]string, error) {
211211
users := make(map[string]string)
212212
for rows.Next() {
213213
if err := rows.Scan(vals...); err != nil {
214-
logger.Error("scanning SHOW USERS row failed", "error", err)
214+
logger.ErrorContext(context.Background(), "scanning SHOW USERS row failed", "error", err)
215215
return nil, fmt.Errorf("error scanning SHOW USERS: %w", err)
216216
}
217217
login := raw[loginIdx]
@@ -232,7 +232,7 @@ func FetchShowWarehouses(db *sql.DB) (map[string]string, error) {
232232
ctx := context.Background()
233233
rows, err := db.QueryContext(ctx, "SHOW WAREHOUSES")
234234
if err != nil {
235-
logger.Error("query SHOW WAREHOUSES failed", "error", err)
235+
logger.ErrorContext(context.Background(), "query SHOW WAREHOUSES failed", "error", err)
236236
return nil, fmt.Errorf("error querying SHOW WAREHOUSES: %w", err)
237237
}
238238
defer rows.Close()
@@ -261,7 +261,7 @@ func FetchShowWarehouses(db *sql.DB) (map[string]string, error) {
261261
warehouses := make(map[string]string)
262262
for rows.Next() {
263263
if err := rows.Scan(vals...); err != nil {
264-
logger.Error("scanning SHOW WAREHOUSES row failed", "error", err)
264+
logger.ErrorContext(context.Background(), "scanning SHOW WAREHOUSES row failed", "error", err)
265265
return nil, fmt.Errorf("error scanning SHOW WAREHOUSES: %w", err)
266266
}
267267
if raw[nameIdx].Valid {
@@ -314,25 +314,25 @@ func (rp *RoleProcessor) Init() error {
314314
if !rp.dryRun {
315315
return errors.New("database connection is nil")
316316
}
317-
rp.logger.Warn("Dry run enabled with nil DB — skipping role/user fetch")
317+
rp.logger.WarnContext(context.Background(), "Dry run enabled with nil DB — skipping role/user fetch")
318318
rp.existingRoles = make(map[string]struct{})
319319
rp.existingUsers = make(map[string]string)
320320
return nil
321321
}
322322
var err error
323323
rp.existingRoles, err = FetchShowRoles(rp.db)
324324
if err != nil {
325-
rp.logger.Error("Failed to fetch roles from Snowflake", "error", err)
325+
rp.logger.ErrorContext(context.Background(), "Failed to fetch roles from Snowflake", "error", err)
326326
return err
327327
}
328328
rp.existingUsers, err = FetchShowUsers(rp.db)
329329
if err != nil {
330-
rp.logger.Error("Failed to fetch users from Snowflake", "error", err)
330+
rp.logger.ErrorContext(context.Background(), "Failed to fetch users from Snowflake", "error", err)
331331
return err
332332
}
333333
rp.existingWarehouses, err = FetchShowWarehouses(rp.db)
334334
if err != nil {
335-
rp.logger.Error("Failed to fetch warehouses from Snowflake", "error", err)
335+
rp.logger.ErrorContext(context.Background(), "Failed to fetch warehouses from Snowflake", "error", err)
336336
return err
337337
}
338338
return nil
@@ -359,18 +359,18 @@ func (rp *RoleProcessor) createWarehouseIfNotExists() (string, error) {
359359

360360
// Use cached warehouses instead of fetching every time
361361
if _, exists := rp.existingWarehouses[warehouseName]; exists {
362-
rp.logger.Info("Warehouse already exists", "warehouse", warehouseName)
362+
rp.logger.InfoContext(context.Background(), "Warehouse already exists", "warehouse", warehouseName)
363363
return warehouseName, nil
364364
}
365365

366366
createWarehouseQuery := fmt.Sprintf(
367367
`CREATE WAREHOUSE IF NOT EXISTS %s
368-
WITH
369-
WAREHOUSE_SIZE = XSMALL
370-
WAREHOUSE_TYPE = STANDARD
371-
AUTO_SUSPEND = 60
372-
AUTO_RESUME = TRUE
373-
INITIALLY_SUSPENDED = TRUE`,
368+
WITH
369+
WAREHOUSE_SIZE = XSMALL
370+
WAREHOUSE_TYPE = STANDARD
371+
AUTO_SUSPEND = 60
372+
AUTO_RESUME = TRUE
373+
INITIALLY_SUSPENDED = TRUE`,
374374
qWarehouse,
375375
)
376376
if err := rp.execQuery(createWarehouseQuery); err != nil {
@@ -398,7 +398,7 @@ func (rp *RoleProcessor) grantWarehouseToRole(warehouseName string) error {
398398
}
399399
// Check if the grant already exists
400400
if _, exists := rp.currentGrants[grantKey]; exists {
401-
rp.logger.Info("Warehouse usage already granted to role", "warehouse", warehouseName, "role", rp.roleName)
401+
rp.logger.InfoContext(context.Background(), "Warehouse usage already granted to role", "warehouse", warehouseName, "role", rp.roleName)
402402
return nil
403403
}
404404

@@ -447,7 +447,7 @@ func (rp *RoleProcessor) memberProcess(role Role) (usersSkipped int, err error)
447447
memberName, ok := rp.existingUsers[upperMemberKey]
448448
if !ok {
449449
usersSkipped++
450-
rp.logger.Warn("Skipping non-existent member", "member", member.Email)
450+
rp.logger.WarnContext(context.Background(), "Skipping non-existent member", "member", member.Email)
451451
continue
452452
}
453453
rp.qUser = quoteIdentifier(memberName)
@@ -474,10 +474,10 @@ func (rp *RoleProcessor) memberProcess(role Role) (usersSkipped int, err error)
474474
func (rp *RoleProcessor) execQuery(query string) error {
475475
ctx := context.Background()
476476
if rp.dryRun {
477-
rp.logger.Info("[DryRun]", "query", query)
477+
rp.logger.InfoContext(context.Background(), "[DryRun]", "query", query)
478478
return nil
479479
}
480-
rp.logger.Info("[Executing]", "query", query)
480+
rp.logger.InfoContext(context.Background(), "[Executing]", "query", query)
481481
_, err := rp.db.ExecContext(ctx, query)
482482
return err
483483
}
@@ -492,7 +492,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
492492
grantUsageOnAllSchemas := func(dbName string) error {
493493
schemas, err := rp.GetSchemasInDatabase(dbName)
494494
if err != nil {
495-
rp.logger.Error("Could not fetch schemas for USAGE grant", "database", dbName, "error", err)
495+
rp.logger.ErrorContext(context.Background(), "Could not fetch schemas for USAGE grant", "database", dbName, "error", err)
496496
return fmt.Errorf("failed to fetch schemas for USAGE grant on database %s: %w", dbName, err)
497497
}
498498
qDB := quoteIdentifier(dbName)
@@ -503,7 +503,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
503503
if err := rp.execQuery(query); err != nil {
504504
errStr := strings.ToLower(err.Error())
505505
if strings.Contains(errStr, "does not exist") || strings.Contains(errStr, "not authorized") {
506-
rp.logger.Warn("Schema does not exist or not authorized for USAGE grant, skipping", "schema", objectName, "error", err)
506+
rp.logger.WarnContext(context.Background(), "Schema does not exist or not authorized for USAGE grant, skipping", "schema", objectName, "error", err)
507507
continue
508508
}
509509
return fmt.Errorf("failed to grant USAGE on schema %s to role %s: %w", objectName, rp.roleName, err)
@@ -516,7 +516,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
516516
for _, tbl := range role.Permissions.Tables {
517517
nameParts := strings.SplitN(tbl.Name, ".", 3)
518518
if len(nameParts) < 3 {
519-
rp.logger.Warn("Table permission name must be in format DATABASE.SCHEMA.TABLE, DATABASE.SCHEMA.*, DATABASE.*.*", "name", tbl.Name)
519+
rp.logger.WarnContext(context.Background(), "Table permission name must be in format DATABASE.SCHEMA.TABLE, DATABASE.SCHEMA.*, DATABASE.*.*", "name", tbl.Name)
520520
continue
521521
}
522522
dbName, schemaPattern, tablePattern := strings.ToUpper(nameParts[0]), nameParts[1], nameParts[2]
@@ -530,7 +530,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
530530
if tablePattern == "*" {
531531
schemas, err := rp.GetSchemasInDatabase(dbName)
532532
if err != nil {
533-
rp.logger.Error("Could not fetch schemas for future grants", "database", dbName, "error", err)
533+
rp.logger.ErrorContext(context.Background(), "Could not fetch schemas for future grants", "database", dbName, "error", err)
534534
continue
535535
}
536536
qDB := quoteIdentifier(dbName)
@@ -544,7 +544,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
544544
privilege = strings.ToUpper(privilege)
545545
query := fmt.Sprintf("GRANT %s ON FUTURE TABLES IN SCHEMA %s.%s TO ROLE %s", privilege, qDB, qSchema, rp.qRole)
546546
if err := rp.execQuery(query); err != nil {
547-
rp.logger.Warn("Failed to grant future privilege on tables", "schema", objectName, "privilege", privilege, "error", err)
547+
rp.logger.WarnContext(context.Background(), "Failed to grant future privilege on tables", "schema", objectName, "privilege", privilege, "error", err)
548548
}
549549
}
550550
}
@@ -555,7 +555,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
555555
for _, vw := range role.Permissions.Views {
556556
nameParts := strings.SplitN(vw.Name, ".", 3)
557557
if len(nameParts) < 3 {
558-
rp.logger.Warn("View permission name must be in format DATABASE.SCHEMA.VIEW, DATABASE.SCHEMA.*, DATABASE.*.*", "name", vw.Name)
558+
rp.logger.WarnContext(context.Background(), "View permission name must be in format DATABASE.SCHEMA.VIEW, DATABASE.SCHEMA.*, DATABASE.*.*", "name", vw.Name)
559559
continue
560560
}
561561
dbName, schemaPattern, viewPattern := strings.ToUpper(nameParts[0]), nameParts[1], nameParts[2]
@@ -569,7 +569,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
569569
if viewPattern == "*" {
570570
schemas, err := rp.GetSchemasInDatabase(dbName)
571571
if err != nil {
572-
rp.logger.Error("Could not fetch schemas for future grants (views)", "database", dbName, "error", err)
572+
rp.logger.ErrorContext(context.Background(), "Could not fetch schemas for future grants (views)", "database", dbName, "error", err)
573573
continue
574574
}
575575
qDB := quoteIdentifier(dbName)
@@ -583,7 +583,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
583583
privilege = strings.ToUpper(privilege)
584584
query := fmt.Sprintf("GRANT %s ON FUTURE VIEWS IN SCHEMA %s.%s TO ROLE %s", privilege, qDB, qSchema, rp.qRole)
585585
if err := rp.execQuery(query); err != nil {
586-
rp.logger.Warn("Failed to grant future privilege on views", "schema", objectName, "privilege", privilege, "error", err)
586+
rp.logger.WarnContext(context.Background(), "Failed to grant future privilege on views", "schema", objectName, "privilege", privilege, "error", err)
587587
}
588588
}
589589
}
@@ -635,7 +635,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
635635
for db := range dbSet {
636636
schemas, err := rp.GetSchemasInDatabase(db)
637637
if err != nil {
638-
rp.logger.Warn("Could not enumerate schemas for explicit future grant revoke", "database", db, "error", err)
638+
rp.logger.WarnContext(context.Background(), "Could not enumerate schemas for explicit future grant revoke", "database", db, "error", err)
639639
continue
640640
}
641641
for _, schema := range schemas {
@@ -647,7 +647,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
647647
query := rp.buildRevokeQuery(gk)
648648
err := rp.execQuery(query)
649649
if err != nil {
650-
rp.logger.Warn("Explicitly revoked future table grant", "query", query, "error", err)
650+
rp.logger.WarnContext(context.Background(), "Explicitly revoked future table grant", "query", query, "error", err)
651651
}
652652
}
653653
}
@@ -659,7 +659,7 @@ func (rp *RoleProcessor) applySpecialGrants(role Role) error {
659659
query := rp.buildRevokeQuery(gk)
660660
err := rp.execQuery(query)
661661
if err != nil {
662-
rp.logger.Warn("Explicitly revoked future view grant", "query", query, "error", err)
662+
rp.logger.WarnContext(context.Background(), "Explicitly revoked future view grant", "query", query, "error", err)
663663
}
664664
}
665665
}
@@ -691,9 +691,9 @@ func (rp *RoleProcessor) Process() error {
691691
if _, exists := rp.existingRoles[upperRole]; exists {
692692
dropRoleQuery := "DROP ROLE IF EXISTS " + rp.qRole
693693
if rp.dryRun {
694-
rp.logger.Info("[DryRun] Would drop role", "query", dropRoleQuery)
694+
rp.logger.InfoContext(context.Background(), "[DryRun] Would drop role", "query", dropRoleQuery)
695695
} else {
696-
rp.logger.Info("Dropping role", "query", dropRoleQuery, "role", rp.roleName)
696+
rp.logger.InfoContext(context.Background(), "Dropping role", "query", dropRoleQuery, "role", rp.roleName)
697697
if _, err := rp.db.ExecContext(ctx, dropRoleQuery); err != nil {
698698
return fmt.Errorf("failed to drop role %s: %w", rp.roleName, err)
699699
}
@@ -743,7 +743,7 @@ func (rp *RoleProcessor) Process() error {
743743
}
744744
}
745745

746-
rp.logger.Info("Grant summary",
746+
rp.logger.InfoContext(context.Background(), "Grant summary",
747747
"rolesConsidered", rolesConsidered,
748748
"usersSkipped", usersSkipped,
749749
"rolesCreated", rolesCreated,
@@ -772,7 +772,7 @@ func (rp *RoleProcessor) GetSchemasInDatabase(dbName string) ([]string, error) {
772772
query := "SHOW SCHEMAS IN DATABASE " + quoteIdentifier(dbName)
773773
rows, err := rp.db.QueryContext(ctx, query)
774774
if err != nil {
775-
rp.logger.Error("SHOW SCHEMAS failed", "database", dbName, "error", err)
775+
rp.logger.ErrorContext(context.Background(), "SHOW SCHEMAS failed", "database", dbName, "error", err)
776776
return nil, fmt.Errorf("SHOW SCHEMAS failed for database %s: %w", dbName, err)
777777
}
778778
defer rows.Close()
@@ -964,7 +964,7 @@ func (rp *RoleProcessor) FetchRoleGrants(roleName string) ([]FetchedRoleGrant, e
964964
query := "SHOW GRANTS TO ROLE " + qRole
965965
rows, err := rp.db.QueryContext(ctx, query)
966966
if err != nil {
967-
logger.Error("query SHOW GRANTS TO ROLE failed", "error", err, "role", roleName)
967+
logger.ErrorContext(context.Background(), "query SHOW GRANTS TO ROLE failed", "error", err, "role", roleName)
968968
return nil, fmt.Errorf("error querying SHOW GRANTS TO ROLE %s: %w", roleName, err)
969969
}
970970
defer rows.Close()
@@ -982,7 +982,7 @@ func (rp *RoleProcessor) FetchRoleGrants(roleName string) ([]FetchedRoleGrant, e
982982
vals[i] = &raw[i]
983983
}
984984
if err := rows.Scan(vals...); err != nil {
985-
logger.Error("scanning SHOW GRANTS TO ROLE row failed", "error", err)
985+
logger.ErrorContext(context.Background(), "scanning SHOW GRANTS TO ROLE row failed", "error", err)
986986
return nil, fmt.Errorf("error scanning SHOW GRANTS TO ROLE: %w", err)
987987
}
988988
var grant FetchedRoleGrant
@@ -1033,7 +1033,7 @@ func difference(a, b map[GrantKey]struct{}) map[GrantKey]struct{} {
10331033

10341034
// Build GrantKey set from config, expanding wildcards for tables/views
10351035
func (rp *RoleProcessor) buildDesiredGrantsFromConfig(role Role) map[GrantKey]struct{} {
1036-
rp.logger.Info("Building desired grants from config", "role", role.Name)
1036+
rp.logger.InfoContext(context.Background(), "Building desired grants from config", "role", role.Name)
10371037
grants := make(map[GrantKey]struct{})
10381038
if role.Permissions == nil {
10391039
return grants
@@ -1141,7 +1141,7 @@ func (rp *RoleProcessor) fetchCurrentGrants() map[GrantKey]struct{} {
11411141
result := make(map[GrantKey]struct{})
11421142
grantRows, err := rp.FetchRoleGrants(rp.roleName)
11431143
if err != nil {
1144-
rp.logger.Error("Failed to fetch current grants", "role", rp.roleName, "error", err)
1144+
rp.logger.ErrorContext(context.Background(), "Failed to fetch current grants", "role", rp.roleName, "error", err)
11451145
return result
11461146
}
11471147
for _, g := range grantRows {
@@ -1178,19 +1178,29 @@ func (rp *RoleProcessor) syncRoleGrants(role Role) error {
11781178
toAdd := difference(desired, current)
11791179
toRevoke := difference(current, desired)
11801180

1181+
// Filter out OWNERSHIP grants (cannot be revoked, only transferred)
1182+
filteredToRevoke := make(map[GrantKey]struct{})
1183+
for gk := range toRevoke {
1184+
if strings.ToUpper(gk.Privilege) == "OWNERSHIP" {
1185+
continue
1186+
}
1187+
filteredToRevoke[gk] = struct{}{}
1188+
}
1189+
toRevoke = filteredToRevoke
1190+
11811191
for gk := range toAdd {
11821192
stmt := rp.buildGrantStatement(gk)
11831193
err := rp.execQuery(stmt)
11841194
if err != nil {
1185-
rp.logger.Warn("Failed to grant", "stmt", stmt, "error", err)
1195+
rp.logger.WarnContext(context.Background(), "Failed to grant", "stmt", stmt, "error", err)
11861196
return err
11871197
}
11881198
}
11891199
for gk := range toRevoke {
11901200
stmt := rp.buildRevokeQuery(gk)
11911201
err := rp.execQuery(stmt)
11921202
if err != nil {
1193-
rp.logger.Warn("Failed to revoke", "stmt", stmt, "error", err)
1203+
rp.logger.WarnContext(context.Background(), "Failed to revoke", "stmt", stmt, "error", err)
11941204
return err
11951205
}
11961206
}

0 commit comments

Comments
 (0)