Files
Serge Zaitsev 694b9dfe50 Chore: Replace xorm.io/xorm imports (#104458)
* replace xorm.io/xorm imports

* replace xorm from other go.mod files

* clean up workspace

* nolint does not make sense anymore as it is not a module

* try if nolint directive helps

* use nolint:all for xorm

* add more nolints

* try to skip xorm in linter config

* exclude xorm differently

* retrigger ci
2025-05-02 17:13:01 +02:00

103 lines
2.7 KiB
Go

package accesscontrol
import (
"fmt"
"strconv"
"strings"
"github.com/grafana/grafana/pkg/util/xorm"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
const (
orphanedServiceAccountsPermissions = "delete orphaned service account permissions"
)
func AddOrphanedMigrations(mg *migrator.Migrator) {
mg.AddMigration(orphanedServiceAccountsPermissions, &orphanedServiceAccountPermissions{})
}
var _ migrator.CodeMigration = new(alertingScopeRemovalMigrator)
type orphanedServiceAccountPermissions struct {
migrator.MigrationBase
}
func (m *orphanedServiceAccountPermissions) SQL(dialect migrator.Dialect) string {
return CodeMigrationSQL
}
func (m *orphanedServiceAccountPermissions) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
var idents []string
// find all permissions that are scopes directly to a service account
err := sess.SQL("SELECT DISTINCT p.identifier FROM permission AS p WHERE p.kind = 'serviceaccounts' AND NOT p.identifier = '*'").Find(&idents)
if err != nil {
return fmt.Errorf("failed to fetch permissinos scoped to service accounts: %w", err)
}
ids := make([]int64, 0, len(idents))
for _, id := range idents {
id, err := strconv.ParseInt(id, 10, 64)
if err == nil {
ids = append(ids, id)
}
}
if len(ids) == 0 {
return nil
}
return batch(len(ids), batchSize, func(start, end int) error {
return m.exec(sess, mg, ids[start:end])
})
}
func (m *orphanedServiceAccountPermissions) exec(sess *xorm.Session, mg *migrator.Migrator, ids []int64) error {
// get all service accounts from batch
raw := "SELECT u.id FROM " + mg.Dialect.Quote("user") + " AS u WHERE u.is_service_account AND u.id IN(?" + strings.Repeat(",?", len(ids)-1) + ")"
args := make([]any, 0, len(ids))
for _, id := range ids {
args = append(args, id)
}
var existingIDs []int64
err := sess.SQL(raw, args...).Find(&existingIDs)
if err != nil {
return fmt.Errorf("failed to fetch existing service accounts: %w", err)
}
existing := make(map[int64]struct{}, len(existingIDs))
for _, id := range existingIDs {
existing[id] = struct{}{}
}
// filter out orphaned permissions
var orphaned []string
for _, id := range ids {
if _, ok := existing[id]; !ok {
orphaned = append(orphaned, strconv.FormatInt(id, 10))
}
}
if len(orphaned) == 0 {
return nil
}
// delete all orphaned permissions
rawDelete := "DELETE FROM permission WHERE kind = 'serviceaccounts' AND identifier IN(?" + strings.Repeat(",?", len(orphaned)-1) + ")"
deleteArgs := make([]any, 0, len(orphaned)+1)
deleteArgs = append(deleteArgs, rawDelete)
for _, id := range orphaned {
deleteArgs = append(deleteArgs, id)
}
_, err = sess.Exec(deleteArgs...)
if err != nil {
return fmt.Errorf("failed to delete orphaned service accounts: %w", err)
}
return nil
}