From d3eb3cd3fc80c82653ac3ba8837402b2f7b332f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Tigerstr=C3=B6m?= Date: Thu, 7 Aug 2025 15:04:56 +0200 Subject: [PATCH 1/2] session: sort MacaroonRecipe.caveats in migration In the kvdb to sql migration, if there have been caveats set for the MacaroonRecipe, the order of the postgres db caveats will in very rare cases differ from the kv store caveats. Therefore, we sort both the kv and sql caveats by their ID, so that we can compare them in a deterministic way. --- session/sql_migration.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/session/sql_migration.go b/session/sql_migration.go index 428cc0fce..0f79cd9da 100644 --- a/session/sql_migration.go +++ b/session/sql_migration.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "reflect" + "sort" "time" "github.com/davecgh/go-spew/spew" @@ -380,11 +381,18 @@ func overrideSessionTimeZone(session *Session) { // as nil in the bbolt store. Therefore, we also override the permissions // or caveats to nil for the migrated session in that scenario, so that the // deep equals check does not fail in this scenario either. +// +// Additionally, we sort the caveats of both the kv and sql sessions by +// their ID, so that they are always comparable in a deterministic way with deep +// equals. func overrideMacaroonRecipe(kvSession *Session, migratedSession *Session) { if kvSession.MacaroonRecipe != nil { kvPerms := kvSession.MacaroonRecipe.Permissions kvCaveats := kvSession.MacaroonRecipe.Caveats + // If the kvSession has a MacaroonRecipe with nil set for any + // of the fields, we need to override the migratedSession + // MacaroonRecipe to match that. if kvPerms == nil && kvCaveats == nil { migratedSession.MacaroonRecipe = &MacaroonRecipe{} } else if kvPerms == nil { @@ -392,5 +400,26 @@ func overrideMacaroonRecipe(kvSession *Session, migratedSession *Session) { } else if kvCaveats == nil { migratedSession.MacaroonRecipe.Caveats = nil } + + sqlCaveats := migratedSession.MacaroonRecipe.Caveats + + // If there have been caveats set for the MacaroonRecipe, + // the order of the postgres db caveats will in very rare cases + // differ from the kv store caveats. Therefore, we sort + // both the kv and sql caveats by their ID, so that we can + // compare them in a deterministic way. + if kvCaveats != nil { + sort.Slice(kvCaveats, func(i, j int) bool { + return bytes.Compare( + kvCaveats[i].Id, kvCaveats[j].Id, + ) < 0 + }) + + sort.Slice(sqlCaveats, func(i, j int) bool { + return bytes.Compare( + sqlCaveats[i].Id, sqlCaveats[j].Id, + ) < 0 + }) + } } } From 1af12f4fb9f8c7cbada060f9dfe203a901757db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Tigerstr=C3=B6m?= Date: Fri, 15 Aug 2025 17:18:00 +0200 Subject: [PATCH 2/2] session: sort MacaroonRecipe.Permissions in migration Similar to the previous commit, we also sort the `MacaroonRecipe.Permissions` slice to ensure it can be compared in a deterministic manner during migrations. --- session/sql_migration.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/session/sql_migration.go b/session/sql_migration.go index 0f79cd9da..0288a03cb 100644 --- a/session/sql_migration.go +++ b/session/sql_migration.go @@ -382,9 +382,9 @@ func overrideSessionTimeZone(session *Session) { // or caveats to nil for the migrated session in that scenario, so that the // deep equals check does not fail in this scenario either. // -// Additionally, we sort the caveats of both the kv and sql sessions by -// their ID, so that they are always comparable in a deterministic way with deep -// equals. +// Additionally, we sort the caveats & permissions of both the kv and sql +// sessions by their ID, so that they are always comparable in a deterministic +// way with deep equals. func overrideMacaroonRecipe(kvSession *Session, migratedSession *Session) { if kvSession.MacaroonRecipe != nil { kvPerms := kvSession.MacaroonRecipe.Permissions @@ -402,6 +402,7 @@ func overrideMacaroonRecipe(kvSession *Session, migratedSession *Session) { } sqlCaveats := migratedSession.MacaroonRecipe.Caveats + sqlPerms := migratedSession.MacaroonRecipe.Permissions // If there have been caveats set for the MacaroonRecipe, // the order of the postgres db caveats will in very rare cases @@ -421,5 +422,28 @@ func overrideMacaroonRecipe(kvSession *Session, migratedSession *Session) { ) < 0 }) } + + // Similarly, we sort the macaroon permissions for both the kv + // and sql sessions, so that we can compare them in a + // deterministic way. + if kvPerms != nil { + sort.Slice(kvPerms, func(i, j int) bool { + if kvPerms[i].Entity == kvPerms[j].Entity { + return kvPerms[i].Action < + kvPerms[j].Action + } + + return kvPerms[i].Entity < kvPerms[j].Entity + }) + + sort.Slice(sqlPerms, func(i, j int) bool { + if sqlPerms[i].Entity == sqlPerms[j].Entity { + return sqlPerms[i].Action < + sqlPerms[j].Action + } + + return sqlPerms[i].Entity < sqlPerms[j].Entity + }) + } } }