package credentiallease import ( "context" "crypto/ecdh" "crypto/ed25519" "crypto/rand" "google.golang.org/protobuf/proto" "path/filepath" "testing" "time" "iop/apps/control-plane/internal/credentialseal" "iop/apps/control-plane/internal/credentialstore" "iop/packages/go/config" lease "iop/packages/go/credentiallease" iop "iop/proto/gen/iop" ) type acceptingRegistry struct{} func (acceptingRegistry) HasEnvelopeKey(context.Context, string, uint64) (bool, error) { return true, nil } type recordingOpener struct { calls int secret []byte } func (o *recordingOpener) Open(_ context.Context, _ credentialstore.SecretEnvelope, _ credentialseal.Context) ([]byte, error) { o.calls++ return append([]byte(nil), o.secret...), nil } func TestAcquireChecksDurableBindingBeforeOpeningAndIssuesConsumableLease(t *testing.T) { ctx := context.Background() store, err := credentialstore.Open(ctx, filepath.Join(t.TempDir(), "credential.db"), credentialstore.WithEnvelopeKeyRegistry(acceptingRegistry{})) if err != nil { t.Fatal(err) } defer store.Close() principal, err := store.CreatePrincipalWithToken(ctx, credentialstore.CreatePrincipalInput{Alias: "principal"}) if err != nil { t.Fatal(err) } slot, err := store.CreateSlot(ctx, credentialstore.CreateSlotInput{ PrincipalID: principal.Principal.ID, Vendor: "openai", CredentialKind: credentialstore.CredentialKindBearer, Envelope: credentialstore.SecretEnvelope{Algorithm: "AES-256-GCM", KeyID: "at-rest", KeyVersion: 1, Nonce: []byte("123456789012"), Ciphertext: []byte("opaque")}, }) if err != nil { t.Fatal(err) } route, err := store.CreateRoute(ctx, credentialstore.CreateRouteInput{PrincipalID: principal.Principal.ID, SlotID: slot.ID, ProfileID: "openai", UpstreamModel: "gpt-4o", ResourceSelector: "default"}) if err != nil { t.Fatal(err) } slot, err = store.GetSlot(ctx, principal.Principal.ID, slot.ID) if err != nil { t.Fatal(err) } generation, err := store.ProjectionGeneration(ctx) if err != nil { t.Fatal(err) } issuerPublic, issuerPrivate, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } recipient, err := ecdh.X25519().GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } now := time.Unix(1700000000, 0).UTC() opener := &recordingOpener{secret: []byte("provider-secret-sentinel")} service, err := New(store, opener, "issuer-1", issuerPrivate, 30*time.Second, 8, func() time.Time { return now }, rand.Reader) if err != nil { t.Fatal(err) } originalProfile, ok := config.BuiltInProtocolProfiles["openai"] if !ok { t.Fatal("missing built-in openai profile") } delete(config.BuiltInProtocolProfiles, "openai") t.Cleanup(func() { config.BuiltInProtocolProfiles["openai"] = originalProfile }) binding := &iop.CredentialLeaseBinding{ PrincipalRef: principal.Principal.ID, CredentialSlotRef: slot.ID, RouteId: route.ID, ProfileId: route.ProfileID, UpstreamTarget: route.UpstreamModel, NodeId: "node-1", RecipientKeyId: "recipient-1", CredentialRevision: uint64(slot.Revision), RouteRevision: uint64(route.Revision), ProjectionGeneration: generation, } request := &iop.AcquireLeaseRequest{EdgeId: "edge-1", Binding: binding, RecipientPublicKey: recipient.PublicKey().Bytes()} stale := proto.Clone(request).(*iop.AcquireLeaseRequest) stale.Binding.ProjectionGeneration-- response, err := service.Acquire(ctx, stale) if err != nil || response.GetError() == "" || opener.calls != 0 { t.Fatalf("stale acquire response=%v err=%v opener_calls=%d", response, err, opener.calls) } response, err = service.Acquire(ctx, request) if err != nil || response.GetLease() == nil || response.GetError() != "" || opener.calls != 1 { t.Fatalf("valid acquire response=%v err=%v opener_calls=%d", response, err, opener.calls) } consumer, err := lease.NewConsumer("node-1", "recipient-1", recipient.Bytes(), "issuer-1", issuerPublic, 8, func() time.Time { return now }) if err != nil { t.Fatal(err) } envelope, err := lease.FromProto(response.GetLease()) if err != nil { t.Fatal(err) } material, err := consumer.Consume(ctx, envelope, lease.ExpectedFromProto(binding)) if err != nil { t.Fatal(err) } if string(material.Secret) != "provider-secret-sentinel" || material.HeaderName != "Authorization" || material.Scheme != "Bearer" { t.Fatal("unexpected lease material") } material.Zero() } // TestAcquireCanonicalizesAPIKeyProfileHeader proves that a built-in profile // declaring a lowercase API-key header (seulgi_messages -> "x-api-key") is // issued and consumed as the canonical "X-Api-Key" scope with no scheme, so // the managed Messages route no longer fails closed at lease issuance. func TestAcquireCanonicalizesAPIKeyProfileHeader(t *testing.T) { ctx := context.Background() store, err := credentialstore.Open(ctx, filepath.Join(t.TempDir(), "credential.db"), credentialstore.WithEnvelopeKeyRegistry(acceptingRegistry{})) if err != nil { t.Fatal(err) } defer store.Close() principal, err := store.CreatePrincipalWithToken(ctx, credentialstore.CreatePrincipalInput{Alias: "principal"}) if err != nil { t.Fatal(err) } slot, err := store.CreateSlot(ctx, credentialstore.CreateSlotInput{ PrincipalID: principal.Principal.ID, Vendor: "seulgi", CredentialKind: credentialstore.CredentialKindAPIKey, Envelope: credentialstore.SecretEnvelope{Algorithm: "AES-256-GCM", KeyID: "at-rest", KeyVersion: 1, Nonce: []byte("123456789012"), Ciphertext: []byte("opaque")}, }) if err != nil { t.Fatal(err) } route, err := store.CreateRoute(ctx, credentialstore.CreateRouteInput{PrincipalID: principal.Principal.ID, SlotID: slot.ID, ProfileID: "seulgi_messages", UpstreamModel: "seulgi-messages-1", ResourceSelector: "default"}) if err != nil { t.Fatal(err) } slot, err = store.GetSlot(ctx, principal.Principal.ID, slot.ID) if err != nil { t.Fatal(err) } generation, err := store.ProjectionGeneration(ctx) if err != nil { t.Fatal(err) } issuerPublic, issuerPrivate, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } recipient, err := ecdh.X25519().GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } now := time.Unix(1700000000, 0).UTC() opener := &recordingOpener{secret: []byte("api-key-secret-sentinel")} service, err := New(store, opener, "issuer-1", issuerPrivate, 30*time.Second, 8, func() time.Time { return now }, rand.Reader) if err != nil { t.Fatal(err) } binding := &iop.CredentialLeaseBinding{ PrincipalRef: principal.Principal.ID, CredentialSlotRef: slot.ID, RouteId: route.ID, ProfileId: route.ProfileID, UpstreamTarget: route.UpstreamModel, NodeId: "node-1", RecipientKeyId: "recipient-1", CredentialRevision: uint64(slot.Revision), RouteRevision: uint64(route.Revision), ProjectionGeneration: generation, } request := &iop.AcquireLeaseRequest{EdgeId: "edge-1", Binding: binding, RecipientPublicKey: recipient.PublicKey().Bytes()} response, err := service.Acquire(ctx, request) if err != nil || response.GetLease() == nil || response.GetError() != "" || opener.calls != 1 { t.Fatalf("api-key acquire response=%v err=%v opener_calls=%d", response, err, opener.calls) } consumer, err := lease.NewConsumer("node-1", "recipient-1", recipient.Bytes(), "issuer-1", issuerPublic, 8, func() time.Time { return now }) if err != nil { t.Fatal(err) } envelope, err := lease.FromProto(response.GetLease()) if err != nil { t.Fatal(err) } material, err := consumer.Consume(ctx, envelope, lease.ExpectedFromProto(binding)) if err != nil { t.Fatal(err) } if string(material.Secret) != "api-key-secret-sentinel" || material.HeaderName != "X-Api-Key" || material.Scheme != "" { t.Fatalf("unexpected api-key lease material header=%q scheme=%q", material.HeaderName, material.Scheme) } material.Zero() }