- PORTAL_KEY_EXPERIENCE.md: review from pending to approved - KEY_SELF_SERVICE_API.md: review from pending to approved - 0015_user_keys.sql: migration for key_records table - user_keys_repo.go + test: SQLite repo (Create/ListByOwner/GetByID/UpdateStatus) - key_self_service.go: HTTP handlers (POST/GET /api/keys, pause/resume/delete) - key_self_service_svc.go: action wiring (buildUserKeyHandler) - registered in ActionSet + NewAPIHandlerWithAuth Note: full user auth requires host+CRM co-deployment. Current skeleton accepts Bearer token for testing.
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func TestUserKeysRepoCreateListGet(t *testing.T) {
|
|
store := openTestDB(t)
|
|
ctx := context.Background()
|
|
|
|
// Create
|
|
id, err := store.UserKeys().Create(ctx, UserKeyRecord{
|
|
KeyID: "key_test_001",
|
|
OwnerSubjectID: "user_long",
|
|
KeyFingerprint: "sha256:fake_fingerprint",
|
|
MaskedPreview: "sk-****abcd",
|
|
DisplayName: "test key",
|
|
LogicalGroupID: "gpt-shared",
|
|
AllowedModels: []string{"gpt-5.4"},
|
|
AdminStatus: "active",
|
|
QuotaStatus: "ok",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create() error = %v", err)
|
|
}
|
|
if id <= 0 {
|
|
t.Fatalf("Create() id = %d, want >0", id)
|
|
}
|
|
|
|
// List by owner
|
|
keys, err := store.UserKeys().ListByOwner(ctx, "user_long")
|
|
if err != nil {
|
|
t.Fatalf("ListByOwner() error = %v", err)
|
|
}
|
|
if len(keys) != 1 {
|
|
t.Fatalf("ListByOwner() len = %d, want 1", len(keys))
|
|
}
|
|
if keys[0].KeyID != "key_test_001" {
|
|
t.Fatalf("key_id = %q, want %q", keys[0].KeyID, "key_test_001")
|
|
}
|
|
if len(keys[0].AllowedModels) != 1 || keys[0].AllowedModels[0] != "gpt-5.4" {
|
|
t.Fatalf("AllowedModels = %v, want [gpt-5.4]", keys[0].AllowedModels)
|
|
}
|
|
|
|
// Get by ID
|
|
key, err := store.UserKeys().GetByID(ctx, "key_test_001")
|
|
if err != nil {
|
|
t.Fatalf("GetByID() error = %v", err)
|
|
}
|
|
if key.MaskedPreview != "sk-****abcd" {
|
|
t.Fatalf("MaskedPreview = %q, want %q", key.MaskedPreview, "sk-****abcd")
|
|
}
|
|
|
|
// Update status
|
|
if err := store.UserKeys().UpdateStatus(ctx, "key_test_001", "paused"); err != nil {
|
|
t.Fatalf("UpdateStatus() error = %v", err)
|
|
}
|
|
key, _ = store.UserKeys().GetByID(ctx, "key_test_001")
|
|
if key.AdminStatus != "paused" {
|
|
t.Fatalf("After pause: admin_status = %q, want %q", key.AdminStatus, "paused")
|
|
}
|
|
|
|
// Owner isolation: other user sees nothing
|
|
otherKeys, err := store.UserKeys().ListByOwner(ctx, "user_other")
|
|
if err != nil {
|
|
t.Fatalf("ListByOwner(other) error = %v", err)
|
|
}
|
|
if len(otherKeys) != 0 {
|
|
t.Fatalf("other user keys = %d, want 0", len(otherKeys))
|
|
}
|
|
}
|