KeyVaultCommandTests.cs•9.54 kB
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using Azure.Security.KeyVault.Keys;
using AzureMcp.Tests;
using AzureMcp.Tests.Client;
using AzureMcp.Tests.Client.Helpers;
using Xunit;
namespace AzureMcp.KeyVault.LiveTests;
public class KeyVaultCommandTests(LiveTestFixture liveTestFixture, ITestOutputHelper output)
    : CommandTestsBase(liveTestFixture, output),
    IClassFixture<LiveTestFixture>
{
    [Fact]
    public async Task Should_list_keys()
    {
        var result = await CallToolAsync(
            "azmcp_keyvault_key_list",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName }
            });
        var keys = result.AssertProperty("keys");
        Assert.Equal(JsonValueKind.Array, keys.ValueKind);
        Assert.NotEmpty(keys.EnumerateArray());
    }
    [Fact(Skip = "Test temporarily disabled")]
    public async Task Should_get_key()
    {
        // Created in keyvault.bicep.
        var knownKeyName = "foo-bar";
        var result = await CallToolAsync(
            "azmcp_keyvault_key_get",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName },
                { "key", knownKeyName}
            });
        var keyName = result.AssertProperty("name");
        Assert.Equal(JsonValueKind.String, keyName.ValueKind);
        Assert.Equal(knownKeyName, keyName.GetString());
        var keyType = result.AssertProperty("keyType");
        Assert.Equal(JsonValueKind.String, keyType.ValueKind);
        Assert.Equal(KeyType.Rsa.ToString(), keyType.GetString());
    }
    [Fact]
    public async Task Should_create_key()
    {
        var keyName = Settings.ResourceBaseName + Random.Shared.NextInt64();
        var result = await CallToolAsync(
            "azmcp_keyvault_key_create",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName },
                { "key", keyName},
                { "key-type", KeyType.Rsa.ToString() }
            });
        var createdKeyName = result.AssertProperty("name");
        Assert.Equal(JsonValueKind.String, createdKeyName.ValueKind);
        Assert.Equal(keyName, createdKeyName.GetString());
        var keyType = result.AssertProperty("keyType");
        Assert.Equal(JsonValueKind.String, keyType.ValueKind);
        Assert.Equal(KeyType.Rsa.ToString(), keyType.GetString());
    }
    [Fact]
    public async Task Should_list_secrets()
    {
        var result = await CallToolAsync(
            "azmcp_keyvault_secret_list",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName }
            });
        var secrets = result.AssertProperty("secrets");
        Assert.Equal(JsonValueKind.Array, secrets.ValueKind);
        Assert.NotEmpty(secrets.EnumerateArray());
    }
    [Fact(Skip = "Test temporarily disabled")]
    public async Task Should_get_secret()
    {
        // Created in keyvault.bicep.
        var secretName = "foo-bar-secret";
        var result = await CallToolAsync(
            "azmcp_keyvault_secret_get",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName },
                { "secret", secretName }
            });
        var name = result.AssertProperty("name");
        Assert.Equal(JsonValueKind.String, name.ValueKind);
        Assert.Equal(secretName, name.GetString());
        var value = result.AssertProperty("value");
        Assert.Equal(JsonValueKind.String, value.ValueKind);
        Assert.NotNull(value.GetString());
    }
    [Fact]
    public async Task Should_create_secret()
    {
        var secretName = Settings.ResourceBaseName + Random.Shared.NextInt64();
        var secretValue = "test-value-" + Random.Shared.NextInt64();
        var result = await CallToolAsync(
            "azmcp_keyvault_secret_create",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName },
                { "secret", secretName},
                { "value", secretValue }
            });
        var createdSecretName = result.AssertProperty("name");
        Assert.Equal(JsonValueKind.String, createdSecretName.ValueKind);
        Assert.Equal(secretName, createdSecretName.GetString());
        var returnedValue = result.AssertProperty("value");
        Assert.Equal(JsonValueKind.String, returnedValue.ValueKind);
        Assert.Equal(secretValue, returnedValue.GetString());
    }
    [Fact]
    public async Task Should_list_certificates()
    {
        var result = await CallToolAsync(
            "azmcp_keyvault_certificate_list",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName }
            });
        var certificates = result.AssertProperty("certificates");
        Assert.Equal(JsonValueKind.Array, certificates.ValueKind);
        // Certificates might be empty if the test certificate creation has not yet completed, so we won't assert non-empty
    }
    [Fact]
    public async Task Should_get_certificate()
    {
        // Created in keyvault.bicep.
        var certificateName = "foo-bar-certificate";
        var result = await CallToolAsync(
            "azmcp_keyvault_certificate_get",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName },
                { "certificate", certificateName }
            });
        var name = result.AssertProperty("name");
        Assert.Equal(JsonValueKind.String, name.ValueKind);
        Assert.Equal(certificateName, name.GetString());
        // Verify that the certificate has some expected properties
        ValidateCertificate(result);
    }
    [Fact]
    public async Task Should_create_certificate()
    {
        var certificateName = Settings.ResourceBaseName + Random.Shared.NextInt64();
        var result = await CallToolAsync(
            "azmcp_keyvault_certificate_create",
            new()
            {
                { "subscription", Settings.SubscriptionId },
                { "vault", Settings.ResourceBaseName },
                { "certificate", certificateName}
            });
        var createdCertificateName = result.AssertProperty("name");
        Assert.Equal(JsonValueKind.String, createdCertificateName.ValueKind);
        Assert.Equal(certificateName, createdCertificateName.GetString());
        // Verify that the certificate has some expected properties
        ValidateCertificate(result);
    }
    [Fact]
    public async Task Should_import_certificate()
    {
        // Generate a self-signed certificate and export to a temporary PFX file with a password
        var fakePassword = "fakePassword";
        using var rsa = RSA.Create(2048);
        var subject = $"CN=Imported-{Guid.NewGuid()}";
        var request = new CertificateRequest(subject, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
        request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
        using var generated = request.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow.AddYears(1));
        var pfxBytes = generated.Export(X509ContentType.Pkcs12, fakePassword);
        var tempPath = Path.Combine(Path.GetTempPath(), $"import-{Guid.NewGuid()}.pfx");
        try
        {
            await File.WriteAllBytesAsync(tempPath, pfxBytes, TestContext.Current.CancellationToken);
            var certificateName = Settings.ResourceBaseName + "import" + Random.Shared.NextInt64();
            var result = await CallToolAsync(
                "azmcp_keyvault_certificate_import",
                new()
                {
                    { "subscription", Settings.SubscriptionId },
                    { "vault", Settings.ResourceBaseName },
                    { "certificate", certificateName },
                    { "certificate-data", tempPath },
                    { "password", fakePassword }
                });
            var createdCertificateName = result.AssertProperty("name");
            Assert.Equal(JsonValueKind.String, createdCertificateName.ValueKind);
            Assert.Equal(certificateName, createdCertificateName.GetString());
            // Validate basic certificate properties
            ValidateCertificate(result);
        }
        finally
        {
            if (File.Exists(tempPath))
            {
                File.Delete(tempPath);
            }
        }
    }
    private void ValidateCertificate(JsonElement? result)
    {
        Assert.NotNull(result);
        var requiredProperties = new[] { "name", "thumbprint", "cer" };
        foreach (var propertyName in requiredProperties)
        {
            var property = result.AssertProperty(propertyName);
            Assert.Equal(JsonValueKind.String, property.ValueKind);
            Assert.NotNull(property.GetString());
        }
    }
}