package accesscontrol import ( "fmt" "time" "github.com/grafana/grafana/pkg/util/xorm" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" ) func AddAlertingPermissionsMigrator(mg *migrator.Migrator) { mg.AddMigration("alerting notification permissions", &alertingMigrator{}) } type alertingMigrator struct { sess *xorm.Session migrator *migrator.Migrator migrator.MigrationBase } var _ migrator.CodeMigration = new(alertingMigrator) func (m *alertingMigrator) SQL(migrator.Dialect) string { return "code migration" } func (m *alertingMigrator) Exec(sess *xorm.Session, migrator *migrator.Migrator) error { m.sess = sess m.migrator = migrator return m.migrateNotificationActions() } func (m *alertingMigrator) migrateNotificationActions() error { var results []accesscontrol.Permission err := m.sess.Table(&accesscontrol.Permission{}).In("action", "alert.notifications:update", "alert.notifications:create", "alert.notifications:delete", accesscontrol.ActionAlertingNotificationsWrite).Find(&results) if err != nil { return fmt.Errorf("failed to query permission table: %w", err) } groupByRoleID := make(map[int64]bool) toDelete := make([]interface{}, 0, len(results)) for _, result := range results { if result.Action == accesscontrol.ActionAlertingNotificationsWrite { groupByRoleID[result.RoleID] = false continue // do not delete this permission } if _, ok := groupByRoleID[result.RoleID]; !ok { groupByRoleID[result.RoleID] = true } toDelete = append(toDelete, result.ID) } toAdd := make([]accesscontrol.Permission, 0, len(groupByRoleID)) now := time.Now() for roleID, add := range groupByRoleID { if !add { m.migrator.Logger.Info(fmt.Sprintf("skip adding action %s to role ID %d because it is already there", accesscontrol.ActionAlertingNotificationsWrite, roleID)) continue } toAdd = append(toAdd, accesscontrol.Permission{ RoleID: roleID, Action: accesscontrol.ActionAlertingNotificationsWrite, Scope: "", Created: now, Updated: now, }) } if len(toAdd) > 0 { added, err := m.sess.Table(&accesscontrol.Permission{}).InsertMulti(toAdd) if err != nil { return fmt.Errorf("failed to insert new permissions:%w", err) } m.migrator.Logger.Debug(fmt.Sprintf("updated %d of %d roles with new permission %s", added, len(toAdd), accesscontrol.ActionAlertingNotificationsWrite)) } if len(toDelete) > 0 { _, err = m.sess.Table(&accesscontrol.Permission{}).In("id", toDelete...).Delete(accesscontrol.Permission{}) if err != nil { return fmt.Errorf("failed to delete deprecated permissions [alert.notifications:update, alert.notifications:create, alert.notifications:delete]:%w", err) } } return nil } type receiverCreateScopeMigration struct { migrator.MigrationBase } var _ migrator.CodeMigration = new(alertingMigrator) func (m *receiverCreateScopeMigration) SQL(migrator.Dialect) string { return "code migration" } func (m *receiverCreateScopeMigration) Exec(sess *xorm.Session, mg *migrator.Migrator) error { result, err := sess.Exec(`UPDATE permission SET scope = '', kind = '', attribute='', identifier='' WHERE action = 'alert.notifications.receivers:create' AND (scope <> '' OR kind <> '' OR attribute <> '' OR identifier <> '');`) if result != nil { aff, _ := result.RowsAffected() if aff > 0 { mg.Logger.Info("Removed scope from permission 'alert.notifications.receivers:create'", "affectedRows", aff) } } return err } func AddReceiverCreateScopeMigration(mg *migrator.Migrator) { mg.AddMigration("remove scope from alert.notifications.receivers:create", &receiverCreateScopeMigration{}) }