File: Utils\DevCertsCheckTests.cs
Web Access
Project: src\tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj (Aspire.Cli.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Cli.Certificates;
using Aspire.Cli.Utils.EnvironmentChecker;
using Microsoft.AspNetCore.Certificates.Generation;
 
namespace Aspire.Cli.Tests.Utils;
 
public class DevCertsCheckTests
{
    private const int MinVersion = CertificateManager.CurrentAspNetCoreCertificateVersion;
 
    private static DevCertInfo CreateDevCertInfo(CertificateManager.TrustLevel trustLevel, string thumbprint, int version)
    {
        var now = DateTimeOffset.UtcNow;
        return new DevCertInfo
        {
            TrustLevel = trustLevel,
            Thumbprint = thumbprint,
            Version = version,
            ValidityNotBefore = now.AddDays(-30),
            ValidityNotAfter = now.AddDays(335),
            Subject = "CN=localhost",
            IsHttpsDevelopmentCertificate = true,
            IsExportable = true
        };
    }
 
    [Fact]
    public void EvaluateCertificateResults_NoCertificates_ReturnsWarning()
    {
        var results = DevCertsCheck.EvaluateCertificateResults([]);
 
        var devCertsResult = Assert.Single(results);
        Assert.Equal("dev-certs", devCertsResult.Name);
        Assert.Equal(EnvironmentCheckStatus.Warning, devCertsResult.Status);
        Assert.Contains("No HTTPS development certificate found", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_MultipleCerts_AllTrusted_ReturnsPass()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "CCCC3333DDDD4444", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Pass, devCertsResult.Status);
        Assert.Contains("trusted", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_MultipleCerts_NoneTrusted_ReturnsWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.None, "AAAA1111BBBB2222", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.None, "CCCC3333DDDD4444", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Warning, devCertsResult.Status);
        Assert.Contains("none are trusted", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_MultipleCerts_SomeUntrusted_ReturnsWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.None, "CCCC3333DDDD4444", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Warning, devCertsResult.Status);
        Assert.Contains("Multiple HTTPS development certificates found", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_SingleCert_Trusted_ReturnsPass()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Pass, devCertsResult.Status);
        Assert.Contains("trusted", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_SingleCert_Untrusted_ReturnsWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.None, "AAAA1111BBBB2222", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Warning, devCertsResult.Status);
        Assert.Contains("not trusted", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_SingleCert_PartiallyTrusted_ReturnsWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Partial, "AAAA1111BBBB2222", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Warning, devCertsResult.Status);
        Assert.Contains("partially trusted", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_OldTrustedCert_ReturnsVersionWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion - 1),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        Assert.Equal(2, results.Count);
        var versionResult = Assert.Single(results, r => r.Name == "dev-certs-version");
        Assert.Equal(EnvironmentCheckStatus.Warning, versionResult.Status);
        Assert.Contains("older version", versionResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_MultipleCerts_AllTrusted_NoVersionWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "CCCC3333DDDD4444", MinVersion + 1),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        // Should only have the pass result, no version warning
        var devCertsResult = Assert.Single(results);
        Assert.Equal("dev-certs", devCertsResult.Name);
        Assert.Equal(EnvironmentCheckStatus.Pass, devCertsResult.Status);
    }
 
    [Fact]
    public void EvaluateCertificateResults_MultipleCerts_AllPartiallyTrusted_ReturnsPass()
    {
        // Partially trusted counts as trusted (not None), so all certs are "trusted"
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Partial, "AAAA1111BBBB2222", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.Partial, "CCCC3333DDDD4444", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        // Should not have a "Multiple certs" warning since all are trusted
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.NotEqual(EnvironmentCheckStatus.Warning, devCertsResult.Status);
    }
 
    [Fact]
    public void EvaluateCertificateResults_ThreeCerts_TwoTrustedOneNot_ReturnsWarning()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "CCCC3333DDDD4444", MinVersion),
            CreateDevCertInfo(CertificateManager.TrustLevel.None, "EEEE5555FFFF6666", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.Equal(EnvironmentCheckStatus.Warning, devCertsResult.Status);
        Assert.Contains("3 certificates", devCertsResult.Message);
    }
 
    [Fact]
    public void EvaluateCertificateResults_PassResult_IncludesMetadata()
    {
        var certs = new List<DevCertInfo>
        {
            CreateDevCertInfo(CertificateManager.TrustLevel.Full, "AAAA1111BBBB2222", MinVersion),
        };
 
        var results = DevCertsCheck.EvaluateCertificateResults(certs);
 
        var devCertsResult = Assert.Single(results, r => r.Name == "dev-certs");
        Assert.NotNull(devCertsResult.Metadata);
        Assert.True(devCertsResult.Metadata.ContainsKey("certificates"));
 
        var certificates = devCertsResult.Metadata["certificates"]!.AsArray();
        Assert.Single(certificates);
 
        var certNode = certificates[0]!.AsObject();
        Assert.Equal("AAAA1111BBBB2222", certNode["thumbprint"]!.GetValue<string>());
        Assert.Equal(MinVersion, certNode["version"]!.GetValue<int>());
        Assert.Equal("full", certNode["trustLevel"]!.GetValue<string>());
        Assert.NotNull(certNode["notBefore"]);
        Assert.NotNull(certNode["notAfter"]);
    }
 
    [Fact]
    public void EvaluateCertificateResults_NoCertificates_DoesNotIncludeMetadata()
    {
        var results = DevCertsCheck.EvaluateCertificateResults([]);
 
        var devCertsResult = Assert.Single(results);
        Assert.Null(devCertsResult.Metadata);
    }
}