test(14.1-02): prove oauth-identities migration and secret-leak list
- Migration up/down covers jsonb profile_data, unique indexes, and cascade FK - GET list with Encrypted tokens fails if plaintext, key names, or [redacted] leak Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
88
updates/oauth_identities_test.go
Normal file
88
updates/oauth_identities_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package updates
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.golem15.com/golem15/sm-user-plugin/models"
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
)
|
||||
|
||||
func TestOAuthIdentitiesMigration(t *testing.T) {
|
||||
sqlDB := dedicatedDB(t, "user_oauth_identities")
|
||||
db, err := lagoon.Use(t.Context(), sqlDB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m := gormigrate.New(db, &gormigrate.Options{TableName: "summer_migrations_golem15_user", UseTransaction: true}, All())
|
||||
if err := m.Migrate(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
table := (&models.OAuthIdentity{}).TableName()
|
||||
if table != "golem15_user_oauth_identities" {
|
||||
t.Fatalf("TableName = %q", table)
|
||||
}
|
||||
if !db.Migrator().HasTable(table) {
|
||||
t.Fatal("golem15_user_oauth_identities missing")
|
||||
}
|
||||
for _, column := range []string{
|
||||
"id", "user_id", "provider", "provider_id", "access_token", "refresh_token",
|
||||
"token_expires_at", "profile_data", "linked_at", "created_at", "updated_at",
|
||||
} {
|
||||
if !db.Migrator().HasColumn(&models.OAuthIdentity{}, column) {
|
||||
t.Fatalf("golem15_user_oauth_identities.%s missing", column)
|
||||
}
|
||||
}
|
||||
var udt string
|
||||
if err := db.Raw(`SELECT udt_name FROM information_schema.columns WHERE table_name = 'golem15_user_oauth_identities' AND column_name = 'profile_data'`).Scan(&udt).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if udt != "jsonb" {
|
||||
t.Fatalf("profile_data udt = %q, want jsonb", udt)
|
||||
}
|
||||
var indexes []string
|
||||
if err := db.Raw(`SELECT indexname FROM pg_indexes WHERE tablename = 'golem15_user_oauth_identities'`).Scan(&indexes).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantIdx := map[string]bool{
|
||||
"oauth_identities_user_provider_unique": false,
|
||||
"oauth_identities_provider_identity_unique": false,
|
||||
}
|
||||
for _, name := range indexes {
|
||||
if _, ok := wantIdx[name]; ok {
|
||||
wantIdx[name] = true
|
||||
}
|
||||
}
|
||||
for name, found := range wantIdx {
|
||||
if !found {
|
||||
t.Fatalf("missing unique index %s in %v", name, indexes)
|
||||
}
|
||||
}
|
||||
var fk struct {
|
||||
ForeignTable string
|
||||
DeleteRule string
|
||||
}
|
||||
if err := db.Raw(`
|
||||
SELECT ccu.table_name AS foreign_table, rc.delete_rule
|
||||
FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
||||
JOIN information_schema.constraint_column_usage ccu
|
||||
ON ccu.constraint_name = tc.constraint_name AND ccu.table_schema = tc.table_schema
|
||||
JOIN information_schema.referential_constraints rc
|
||||
ON rc.constraint_name = tc.constraint_name AND rc.constraint_schema = tc.table_schema
|
||||
WHERE tc.table_name = 'golem15_user_oauth_identities'
|
||||
AND tc.constraint_type = 'FOREIGN KEY'
|
||||
AND kcu.column_name = 'user_id'`).Scan(&fk).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fk.ForeignTable != "users" || fk.DeleteRule != "CASCADE" {
|
||||
t.Fatalf("user_id FK = %+v, want users ON DELETE CASCADE", fk)
|
||||
}
|
||||
if err := m.RollbackMigration(oauthIdentityMigrations[0]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if db.Migrator().HasTable(table) {
|
||||
t.Fatal("golem15_user_oauth_identities survived rollback")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user