/**
 * Tests for KMS-backed Signing
 */
import { describe, it, expect, beforeEach, vi } from "vitest";
import { generateKeyPairSync } from "crypto";
import { AWSKMSClient, GCPKMSClient, VaultClient, LocalKeyClient, KMSClient, createKMSClient, createAWSKMSClient, createGCPKMSClient, createVaultClient, createLocalKeyClient, } from "./kms.js";
// Mock fetch
const mockFetch = vi.fn();
global.fetch = mockFetch;
// Generate test key pair
const { privateKey, publicKey } = generateKeyPairSync("rsa", {
    modulusLength: 2048,
    publicKeyEncoding: { type: "spki", format: "pem" },
    privateKeyEncoding: { type: "pkcs8", format: "pem" },
});
describe("LocalKeyClient", () => {
    let client;
    beforeEach(() => {
        client = new LocalKeyClient({
            provider: "local",
            keyId: "test-key",
            local: {
                privateKeyPem: privateKey,
                publicKeyPem: publicKey,
            },
        });
    });
    describe("constructor", () => {
        it("creates client with valid config", () => {
            expect(client).toBeInstanceOf(LocalKeyClient);
        });
        it("throws on wrong provider", () => {
            expect(() => new LocalKeyClient({
                provider: "aws",
                keyId: "test",
            })).toThrow("LocalKeyClient requires provider: 'local'");
        });
        it("throws without keys", () => {
            expect(() => new LocalKeyClient({
                provider: "local",
                keyId: "test",
            })).toThrow("LocalKeyClient requires privateKeyPem and publicKeyPem");
        });
    });
    describe("sign", () => {
        it("signs content with RSA-SHA256", async () => {
            const content = "Hello, World!";
            const artifact = await client.sign(content);
            expect(artifact.content).toBe(content);
            expect(artifact.digest).toBeDefined();
            expect(artifact.signature).toBeDefined();
            expect(artifact.provider).toBe("local");
            expect(artifact.keyId).toBe("test-key");
            expect(artifact.algorithm).toBe("RSA-SHA256");
            expect(artifact.signedAt).toBeDefined();
        });
        it("generates correct digest", async () => {
            const content = "Test content";
            const artifact = await client.sign(content);
            expect(artifact.digest).toMatch(/^[a-f0-9]{64}$/); // SHA256 hex
        });
    });
    describe("verify", () => {
        it("verifies valid signature", async () => {
            const content = "Test content";
            const artifact = await client.sign(content);
            const result = await client.verify(artifact);
            expect(result.valid).toBe(true);
            expect(result.keyId).toBe("test-key");
            expect(result.verifiedAt).toBeDefined();
        });
        it("rejects tampered content", async () => {
            const artifact = await client.sign("Original");
            artifact.content = "Tampered";
            const result = await client.verify(artifact);
            expect(result.valid).toBe(false);
        });
        it("rejects invalid signature", async () => {
            const artifact = await client.sign("Test");
            artifact.signature = "invalid-signature";
            const result = await client.verify(artifact);
            // Invalid signatures will either return valid=false or throw an error
            // depending on how malformed the signature is
            expect(result.valid).toBe(false);
        });
    });
});
describe("AWSKMSClient", () => {
    let client;
    beforeEach(() => {
        vi.clearAllMocks();
        client = new AWSKMSClient({
            provider: "aws",
            keyId: "arn:aws:kms:us-east-1:123456789:key/test-key",
            aws: {
                region: "us-east-1",
                accessKeyId: "AKIAIOSFODNN7EXAMPLE",
                secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
            },
        });
    });
    describe("constructor", () => {
        it("throws on wrong provider", () => {
            expect(() => new AWSKMSClient({
                provider: "gcp",
                keyId: "test",
            })).toThrow("AWSKMSClient requires provider: 'aws'");
        });
    });
    describe("sign", () => {
        it("calls AWS KMS Sign API", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    Signature: "base64-signature",
                    KeyId: "arn:aws:kms:us-east-1:123456789:key/test-key",
                }),
            });
            const artifact = await client.sign("Test content");
            expect(artifact.signature).toBe("base64-signature");
            expect(artifact.provider).toBe("aws");
            expect(artifact.algorithm).toBe("RSASSA_PKCS1_V1_5_SHA_256");
            expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("kms.us-east-1.amazonaws.com"), expect.objectContaining({
                method: "POST",
                headers: expect.objectContaining({
                    "X-Amz-Target": "TrentService.Sign",
                }),
            }));
        });
        it("throws on missing region", async () => {
            const clientNoRegion = new AWSKMSClient({
                provider: "aws",
                keyId: "test-key",
                aws: {},
            });
            await expect(clientNoRegion.sign("Test")).rejects.toThrow("AWS region required");
        });
        it("throws on API error", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: false,
                text: async () => "AccessDeniedException",
            });
            await expect(client.sign("Test")).rejects.toThrow("AWS KMS error");
        });
    });
    describe("verify", () => {
        it("calls AWS KMS Verify API", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    SignatureValid: true,
                }),
            });
            const artifact = {
                content: "Test",
                digest: "digest",
                signature: "signature",
                provider: "aws",
                keyId: "test-key",
                signedAt: new Date().toISOString(),
                algorithm: "RSASSA_PKCS1_V1_5_SHA_256",
            };
            const result = await client.verify(artifact);
            expect(result.valid).toBe(true);
            expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
                headers: expect.objectContaining({
                    "X-Amz-Target": "TrentService.Verify",
                }),
            }));
        });
        it("handles verification failure", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    SignatureValid: false,
                }),
            });
            const artifact = {
                content: "Test",
                digest: "digest",
                signature: "invalid",
                provider: "aws",
                keyId: "test-key",
                signedAt: new Date().toISOString(),
                algorithm: "RSASSA_PKCS1_V1_5_SHA_256",
            };
            const result = await client.verify(artifact);
            expect(result.valid).toBe(false);
        });
        it("handles API errors gracefully", async () => {
            mockFetch.mockRejectedValueOnce(new Error("Network error"));
            const artifact = {
                content: "Test",
                digest: "digest",
                signature: "signature",
                provider: "aws",
                keyId: "test-key",
                signedAt: new Date().toISOString(),
                algorithm: "RSASSA_PKCS1_V1_5_SHA_256",
            };
            const result = await client.verify(artifact);
            expect(result.valid).toBe(false);
            expect(result.error).toContain("Network error");
        });
    });
});
describe("GCPKMSClient", () => {
    let client;
    beforeEach(() => {
        vi.clearAllMocks();
        client = new GCPKMSClient({
            provider: "gcp",
            keyId: "my-key",
            gcp: {
                projectId: "my-project",
                locationId: "us-central1",
                keyRingId: "my-keyring",
            },
        });
    });
    describe("constructor", () => {
        it("throws on wrong provider", () => {
            expect(() => new GCPKMSClient({
                provider: "aws",
                keyId: "test",
            })).toThrow("GCPKMSClient requires provider: 'gcp'");
        });
    });
    describe("sign", () => {
        it("calls GCP KMS API", async () => {
            // Mock metadata server for auth
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({ access_token: "test-token" }),
            });
            // Mock sign request
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({ signature: "gcp-signature" }),
            });
            const artifact = await client.sign("Test content");
            expect(artifact.signature).toBe("gcp-signature");
            expect(artifact.provider).toBe("gcp");
            expect(artifact.algorithm).toBe("RSA_SIGN_PKCS1_256");
        });
        it("handles authentication failure", async () => {
            mockFetch.mockRejectedValueOnce(new Error("No credentials"));
            await expect(client.sign("Test")).rejects.toThrow();
        });
    });
    describe("verify", () => {
        it("calls GCP KMS verify API", async () => {
            // Mock metadata server for auth
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({ access_token: "test-token" }),
            });
            // Mock verify request
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({ success: true }),
            });
            const artifact = {
                content: "Test",
                digest: "digest",
                signature: "signature",
                provider: "gcp",
                keyId: "projects/my-project/locations/us-central1/keyRings/my-keyring/cryptoKeys/my-key/cryptoKeyVersions/1",
                signedAt: new Date().toISOString(),
                algorithm: "RSA_SIGN_PKCS1_256",
            };
            const result = await client.verify(artifact);
            expect(result.valid).toBe(true);
        });
    });
});
describe("VaultClient", () => {
    let client;
    beforeEach(() => {
        vi.clearAllMocks();
        client = new VaultClient({
            provider: "vault",
            keyId: "my-signing-key",
            vault: {
                address: "https://vault.example.com",
                token: "s.xxxxxxxxxxxxx",
                namespace: "admin",
            },
        });
    });
    describe("constructor", () => {
        it("throws on wrong provider", () => {
            expect(() => new VaultClient({
                provider: "aws",
                keyId: "test",
            })).toThrow("VaultClient requires provider: 'vault'");
        });
    });
    describe("sign", () => {
        it("calls Vault Transit sign API", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    data: {
                        signature: "vault:v1:signature-data",
                        key_version: 1,
                    },
                }),
            });
            const artifact = await client.sign("Test content");
            expect(artifact.signature).toBe("vault:v1:signature-data");
            expect(artifact.provider).toBe("vault");
            expect(artifact.keyVersion).toBe("1");
            expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining("vault.example.com/v1/transit/sign/my-signing-key"), expect.objectContaining({
                headers: expect.objectContaining({
                    "X-Vault-Token": "s.xxxxxxxxxxxxx",
                    "X-Vault-Namespace": "admin",
                }),
            }));
        });
        it("handles Vault errors", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: false,
                text: async () => "permission denied",
            });
            await expect(client.sign("Test")).rejects.toThrow("Vault error");
        });
    });
    describe("verify", () => {
        it("calls Vault Transit verify API", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    data: { valid: true },
                }),
            });
            const artifact = {
                content: "Test",
                digest: "digest",
                signature: "vault:v1:signature",
                provider: "vault",
                keyId: "my-signing-key",
                signedAt: new Date().toISOString(),
                algorithm: "sha2-256",
            };
            const result = await client.verify(artifact);
            expect(result.valid).toBe(true);
        });
        it("handles verification failure", async () => {
            mockFetch.mockResolvedValueOnce({
                ok: false,
                text: async () => "verification failed",
            });
            const artifact = {
                content: "Test",
                digest: "digest",
                signature: "invalid",
                provider: "vault",
                keyId: "my-signing-key",
                signedAt: new Date().toISOString(),
                algorithm: "sha2-256",
            };
            const result = await client.verify(artifact);
            expect(result.valid).toBe(false);
            expect(result.error).toBeDefined();
        });
    });
});
describe("KMSClient", () => {
    describe("constructor", () => {
        it("creates AWS client for aws provider", () => {
            const client = new KMSClient({
                provider: "aws",
                keyId: "test-key",
                aws: { region: "us-east-1" },
            });
            expect(client.getProvider()).toBe("aws");
        });
        it("creates GCP client for gcp provider", () => {
            const client = new KMSClient({
                provider: "gcp",
                keyId: "test-key",
                gcp: {
                    projectId: "project",
                    locationId: "us-central1",
                    keyRingId: "keyring",
                },
            });
            expect(client.getProvider()).toBe("gcp");
        });
        it("creates Vault client for vault provider", () => {
            const client = new KMSClient({
                provider: "vault",
                keyId: "test-key",
                vault: {
                    address: "https://vault.example.com",
                    token: "token",
                },
            });
            expect(client.getProvider()).toBe("vault");
        });
        it("creates local client for local provider", () => {
            const client = new KMSClient({
                provider: "local",
                keyId: "test-key",
                local: {
                    privateKeyPem: privateKey,
                    publicKeyPem: publicKey,
                },
            });
            expect(client.getProvider()).toBe("local");
        });
        it("throws for unsupported provider", () => {
            expect(() => new KMSClient({
                provider: "unsupported",
                keyId: "test",
            })).toThrow("Unsupported KMS provider");
        });
    });
    describe("sign and verify", () => {
        it("delegates to underlying client", async () => {
            const client = new KMSClient({
                provider: "local",
                keyId: "test-key",
                local: {
                    privateKeyPem: privateKey,
                    publicKeyPem: publicKey,
                },
            });
            const artifact = await client.sign("Test content");
            const result = await client.verify(artifact);
            expect(result.valid).toBe(true);
        });
    });
});
describe("Factory Functions", () => {
    describe("createKMSClient", () => {
        it("creates unified KMS client", () => {
            const client = createKMSClient({
                provider: "local",
                keyId: "test",
                local: {
                    privateKeyPem: privateKey,
                    publicKeyPem: publicKey,
                },
            });
            expect(client).toBeInstanceOf(KMSClient);
        });
    });
    describe("createAWSKMSClient", () => {
        it("creates AWS KMS client", () => {
            const client = createAWSKMSClient("key-arn", { region: "us-east-1" });
            expect(client).toBeInstanceOf(AWSKMSClient);
        });
    });
    describe("createGCPKMSClient", () => {
        it("creates GCP KMS client", () => {
            const client = createGCPKMSClient("key-id", {
                projectId: "project",
                locationId: "location",
                keyRingId: "keyring",
            });
            expect(client).toBeInstanceOf(GCPKMSClient);
        });
    });
    describe("createVaultClient", () => {
        it("creates Vault client", () => {
            const client = createVaultClient("key-name", {
                address: "https://vault.example.com",
                token: "token",
            });
            expect(client).toBeInstanceOf(VaultClient);
        });
    });
    describe("createLocalKeyClient", () => {
        it("creates local key client", () => {
            const client = createLocalKeyClient("key-id", privateKey, publicKey);
            expect(client).toBeInstanceOf(LocalKeyClient);
        });
    });
});
describe("End-to-end signing flow", () => {
    it("signs and verifies with local keys", async () => {
        const client = new KMSClient({
            provider: "local",
            keyId: "e2e-test-key",
            local: {
                privateKeyPem: privateKey,
                publicKeyPem: publicKey,
            },
        });
        const content = JSON.stringify({
            certificationId: "cert-123",
            findings: ["f1", "f2"],
            timestamp: new Date().toISOString(),
        });
        // Sign
        const artifact = await client.sign(content);
        expect(artifact.content).toBe(content);
        expect(artifact.digest).toBeDefined();
        expect(artifact.signature).toBeDefined();
        // Verify
        const result = await client.verify(artifact);
        expect(result.valid).toBe(true);
        // Tamper and verify fails
        artifact.content = JSON.stringify({ tampered: true });
        const tamperedResult = await client.verify(artifact);
        expect(tamperedResult.valid).toBe(false);
    });
});
//# sourceMappingURL=kms.test.js.map