- TestMemberTokenScopes walks E-2's acceptance list item by item, plus the per-application catalog and the legacy MintAPIToken fallback; TestMemberTokenScopesBoot (no Docker) the boot refusals - TestBackendLinkAuthTime (C-CR-02), TestBackendLinkShowPost (C-WR-01, C-IN-06), TestAccessRevocation (C-CR-01), TestUserMCPGuardClientIP (C-IN-04), TestAPITokenRevokeEvent (C-IN-02), TestOrganisationLogo (E-1) - README Testing section names them
62 lines
2.1 KiB
Go
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:
|
|
// under -short nothing runs.
|
|
func TestUserMCPGuardClientIP(t *testing.T) {
|
|
if testing.Short() {
|
|
return
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|