CosmosDB preview emulator: HTTPS endpoint switch ignores certificate availability, breaks CI

Open Beginner friendly
#15,620 3 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
azure, csharp
Domain
cloud, databases

Research direction

Start in AzureCosmosDBExtensions.cs, then trace SubscribeHttpsEndpointsUpdate and HttpsCertificateExecutionConfigurationGatherer.GatherAsync to compare endpoint selection with certificate configuration. Reproduce the DistributedApplicationTestingBuilder scenario without a trusted developer certificate. Done means the preview emulator and resolved connection string use compatible HTTP or HTTPS settings on CI.

Written by the indexing model from the issue text.

Description

area-integrations internal-customer-impact

Description

After upgrading from Aspire.Hosting.Azure.CosmosDB 13.1.x to 13.2.0, integration tests that use RunAsPreviewEmulator started failing on CI (Azure DevOps) with SSL errors, while working fine on developer machines.

The root cause is a logic mismatch introduced in #14663 (267e787) — the endpoint scheme is switched to HTTPS unconditionally, but the certificate environment variables are only configured when a dev cert is actually available.

Root Cause

In AzureCosmosDBExtensions.cs, RunAsPreviewEmulator does two things:

1. Adds an HttpsCertificateAnnotation with UseDeveloperCertificate = true:

emulatorSurrogateBuilder.WithHttpsDeveloperCertificate(password: ...);

Since AzureCosmosDBEmulatorResource.Annotations delegates to the inner AzureCosmosDBResource, this annotation ends up on the main resource.

2. Subscribes to BeforeStartEvent to switch the endpoint to HTTPS:

builder.SubscribeHttpsEndpointsUpdate(ctx =>
{
    builder.WithEndpoint("emulator", ep => { ep.UriScheme = "https"; });
});

Inside SubscribeHttpsEndpointsUpdate, the check is:

else if (annotation.UseDeveloperCertificate.GetValueOrDefault(developerCertificateService.UseForHttps) || ...)
{
    addHttps = true;
}

Because UseDeveloperCertificate is explicitly true (not null), GetValueOrDefault returns true regardless of developerCertificateService.UseForHttps. The endpoint always switches to HTTPS.

Meanwhile, the certificate env var setter (HttpsCertificateExecutionConfigurationGatherer.GatherAsync) does the right thing:

if (certificate is null)
{
    return; // No dev cert → exit early, no PROTOCOL/CERT_PATH/CERT_SECRET set
}

So on CI (no trusted dev cert):

  • SubscribeHttpsEndpointsUpdate → endpoint becomes https://
  • GatherAsync → no cert found → exits early → no PROTOCOL=https env var
  • Emulator starts with HTTP
  • Connection string resolves to AccountEndpoint=https://host:port (via EndpointProperty.Url)
  • Aspire's internal CosmosClient.ReadAccountAsync() in OnResourceReady tries HTTPS against an HTTP server → HttpRequestException: The SSL connection could not be established / Cannot determine the frame size or a corrupted frame was received

On dev machines it works because the dev cert exists, so both the endpoint switch and the env var configuration happen together.

Steps to Reproduce

  1. Create an Aspire AppHost with a CosmosDB preview emulator:
var cosmosDb = builder.AddAzureCosmosDB("cosmos");
cosmosDb.RunAsPreviewEmulator(emulator =>
{
    emulator.WithDataExplorer();
});
  1. Create an integration test using DistributedApplicationTestingBuilder:
var builder = await DistributedApplicationTestingBuilder
    .CreateAsync<Projects.MyAppHost>([], (options, _) =>
    {
        options.AllowUnsecuredTransport = true;
    });

var app = await builder.BuildAsync();
await app.StartAsync();

// This will timeout on CI — OnResourceReady fails with SSL error
await app.ResourceNotifications.WaitForResourceHealthyAsync("cosmos", cts.Token);
  1. Run on a CI agent that has no trusted ASP.NET Core developer certificate (standard Azure DevOps / GitHub Actions Linux agent).

Expected: Emulator starts with HTTP, endpoint uses HTTP, tests pass.
Actual: Endpoint switches to HTTPS, emulator stays HTTP, SSL handshake fails.

Suggested Fix

In WithHttpsDeveloperCertificate, set UseDeveloperCertificate = null instead of true:

var annotation = new HttpsCertificateAnnotation
{
    UseDeveloperCertificate = null,  // was: true
    Password = password?.Resource,
};

This way, SubscribeHttpsEndpointsUpdate falls back to developerCertificateService.UseForHttps — which properly checks whether a cert actually exists — and the endpoint only switches to HTTPS when the full HTTPS chain can actually work.

Alternatively, SubscribeHttpsEndpointsUpdate could be changed to verify cert availability before switching the scheme, not just check the annotation's intent.

Workaround

For anyone hitting this in the meantime — in the AppHost, after RunAsPreviewEmulator, remove the cert config callbacks and force the endpoint back to HTTP for the testing environment:

if (builder.Environment.EnvironmentName == "Testing")
{
    foreach (var annotation in cosmosDb.Resource.Annotations.ToList())
    {
        var typeName = annotation.GetType().Name;
        if (typeName.Contains("HttpsCertificateConfiguration") ||
            typeName.Contains("CertificateTrust"))
        {
            cosmosDb.Resource.Annotations.Remove(annotation);
        }
    }

    builder.Eventing.Subscribe<BeforeStartEvent>((@event, _) =>
    {
        cosmosDb.WithEndpoint("emulator", e => e.UriScheme = "http");
        return Task.CompletedTask;
    });
}

Environment

  • Aspire.Hosting.Azure.CosmosDB: 13.2.0
  • .NET SDK: 10.0
  • CI: Azure DevOps (Linux agent, no trusted ASP.NET Core dev cert)
  • Emulator image tag: vnext-EN20260227 (also reproducible with default vnext-preview)
Dominant language
C#
Stars
6.3k
Forks
992
Avg merge
2d 16h
Merged PRs (30d)
176

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/aspire

All issues in microsoft/aspire

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.