Files
sm-user-plugin/mcp_guard_client_ip_test.go
Jakub Zych ebe408f542 test: an organisation delete removes the blobs, Postgres tests skip under -short
TestOrganisationLogo asserted only that the system_files rows go; it now
also waits for the commit and asserts the logo's and avatar's originals and
thumbnails are gone from the bucket. The Postgres tests of the gap closure
call t.Skip under -short instead of returning, so -short runs report them
as skipped, not passed.
2026-10-23 21:14:37 +02:00

62 lines
2.1 KiB
Go

package user
import (
"context"
"testing"
"git.golem15.com/golem15/sm-user-plugin/models"
"git.golem15.com/golem15/summercms/modules/pact"
"git.golem15.com/golem15/summercms/modules/towel"
)
// TestUserMCPGuardClientIP pins plan 08's client address on the MCP
// personal-token path (C-IN-04): MCPResolvePersonalToken stamps
// last_used_ip from towel.ClientIP, as the api_token guard does, and leaves
// the column as it was when the context carries no address. Postgres only:
// skipped under -short.
func TestUserMCPGuardClientIP(t *testing.T) {
if testing.Short() {
t.Skip("Postgres")
}
env := newAdminEnv(t)
resolver, ok := env.app.Lookup[pact.MCPPersonalTokenResolver]()
if !ok {
t.Fatal("no personal token resolver published")
}
user := env.seedUser(t, "mcp-ip", nil)
secret, token := env.mintUserToken(t, user, "read")
lastIP := func(t *testing.T) *string {
t.Helper()
var row models.APIToken
if err := env.gdb.Where("id = ?", token.ID).First(&row).Error; err != nil {
t.Fatal(err)
}
return row.LastUsedIP
}
t.Run("an address on the context is stamped", func(t *testing.T) {
subject, matched, err := resolver.MCPResolvePersonalToken(towel.WithClientIP(context.Background(), "203.0.113.44"), secret)
if err != nil || !matched || subject.TokenID != token.ID {
t.Fatalf("resolve = %+v, %v, %v", subject, matched, err)
}
if ip := lastIP(t); ip == nil || *ip != "203.0.113.44" {
t.Fatalf("last_used_ip = %v, want 203.0.113.44", ip)
}
})
t.Run("no address leaves the column as it was", func(t *testing.T) {
if _, matched, err := resolver.MCPResolvePersonalToken(context.Background(), secret); err != nil || !matched {
t.Fatalf("resolve = %v, %v", matched, err)
}
if ip := lastIP(t); ip == nil || *ip != "203.0.113.44" {
t.Fatalf("last_used_ip after a resolve without an address = %v, want it unchanged", ip)
}
if _, _, err := resolver.MCPResolvePersonalToken(towel.WithClientIP(context.Background(), " "), secret); err != nil {
t.Fatal(err)
}
if ip := lastIP(t); ip == nil || *ip != "203.0.113.44" {
t.Fatalf("last_used_ip after a blank address = %v, want it unchanged", ip)
}
})
}