AI Gateway Go 0.10.0 源码快照 + 旗舰版需求规划报告
M0-M7 已完成:核心网关(身份/RBAC/TOTP/OIDC/SAML/Provider/配额/路由/内容策略/审计/定价)+ 资源市场(MCP/Skills/数字员工)。 含 22 个 PostgreSQL 迁移、管理端/门户端前端源码、OpenAPI 契约、部署 compose。 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package apikey
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBootstrapCompatibilityUsageCounter(t *testing.T) {
|
||||
authenticator := NewAuthenticator(nil, nil, "temporary-bootstrap-key")
|
||||
if err := authenticator.Authenticate(context.Background(), "temporary-bootstrap-key"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if authenticator.BootstrapUses() != 1 {
|
||||
t.Fatalf("unexpected bootstrap usage count %d", authenticator.BootstrapUses())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateAndDigest(t *testing.T) {
|
||||
first, prefix, hash, err := Generate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(first) < 40 || len(prefix) != 16 || prefix != first[:16] {
|
||||
t.Fatal("invalid API key format")
|
||||
}
|
||||
computed, _ := Digest(first)
|
||||
if !bytes.Equal(hash, computed) {
|
||||
t.Fatal("stored digest differs")
|
||||
}
|
||||
second, _, _, err := Generate()
|
||||
if err != nil || second == first {
|
||||
t.Fatal("API keys must be independently random")
|
||||
}
|
||||
}
|
||||
|
||||
func TestScopes(t *testing.T) {
|
||||
if !HasScope([]string{"gateway:invoke"}, "gateway:invoke") || !HasScope([]string{"*"}, "gateway:invoke") {
|
||||
t.Fatal("expected scope is missing")
|
||||
}
|
||||
if HasScope([]string{"gateway:read"}, "gateway:invoke") {
|
||||
t.Fatal("unexpected scope accepted")
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvokeScope pins the regression where portal application runtime
|
||||
// credentials ("application:run") could never reach the gateway: the scope
|
||||
// check only admitted "gateway:invoke", so every hosted application chat
|
||||
// returned 401 even though the credential is legitimate.
|
||||
func TestInvokeScope(t *testing.T) {
|
||||
accept := map[string][]string{
|
||||
"gateway key": {"gateway:invoke"},
|
||||
"admin wildcard": {"*"},
|
||||
"application runtime key": {"application:run"},
|
||||
"runtime + read": {"application:run", "gateway:read"},
|
||||
}
|
||||
for name, scopes := range accept {
|
||||
if !invokeScope(scopes) {
|
||||
t.Fatalf("invokeScope(%v) = false, want true for %s", scopes, name)
|
||||
}
|
||||
}
|
||||
reject := map[string][]string{
|
||||
"read-only": {"gateway:read"},
|
||||
"unrelated scope": {"workbench:run"},
|
||||
"empty": {},
|
||||
"runtime scope missing": {"gateway:read", "workbench:run"},
|
||||
}
|
||||
for name, scopes := range reject {
|
||||
if invokeScope(scopes) {
|
||||
t.Fatalf("invokeScope(%v) = true, want false for %s", scopes, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user