Files
summercms/modules/pier/prm_scopes_test.go
Jakub Zych 9094bf9ad9 test(32.1-05): prove MCP call context, both guards, and PRM scopes
- A bare context and a plain request carry no MCP call
- Frontend and backend tool calls record the guard that owns the tool
- PRM uses an advertised scope list and falls back to PRMScopes
2026-10-28 16:09:30 +01:00

59 lines
1.6 KiB
Go

package pier_test
import (
"net/http"
"slices"
"testing"
"git.golem15.com/golem15/summercms/modules/pact"
"git.golem15.com/golem15/summercms/modules/pier"
)
// TestPRMUsesAdvertisedScopes pins D-04: a verifier that implements
// MCPAdvertisedScopes supplies the protected-resource scopes, including a
// declared name.
func TestPRMUsesAdvertisedScopes(t *testing.T) {
declared := []string{"read", "write", "ai", "offline_access", "backend", "acme:read"}
app := newApp(t, appSpec{
verifier: advertisedVerifier{scopes: declared},
guards: []pact.MCPGuard{&acmeGuard{}},
})
in := startInstance(t, app, prmPlugin())
got := prmScopes(t, in.srv.URL)
if !slices.Equal(got, declared) || !slices.Contains(got, "acme:read") {
t.Fatalf("PRM scopes = %v, want %v", got, declared)
}
}
// TestPRMFallsBackToPRMScopes pins D-04: a verifier that does not implement
// MCPAdvertisedScopes leaves the fixed list, which includes backend.
func TestPRMFallsBackToPRMScopes(t *testing.T) {
app := newApp(t, appSpec{
verifier: acmeVerifier{},
guards: []pact.MCPGuard{&acmeGuard{}},
})
in := startInstance(t, app, prmPlugin())
got := prmScopes(t, in.srv.URL)
if !slices.Equal(got, pier.PRMScopes) || !slices.Contains(got, "backend") {
t.Fatalf("PRM scopes = %v, want %v", got, pier.PRMScopes)
}
}
func prmPlugin() routePlugin {
return routePlugin{
id: "test.acme",
routes: []testRoute{{
method: http.MethodGet,
path: "/acme/items",
mw: []string{"acme.auth"},
h: func(http.ResponseWriter, *http.Request) {},
}},
tools: []pact.MCPTool{{
Name: "show",
Method: http.MethodGet,
Path: "/acme/items",
Input: struct{}{},
}},
}
}