Skip to content

Default telemetry API to disabled when frontend has auth#14990

Closed
mitchdenny wants to merge 1 commit intorelease/13.2from
fix/api-telemetry-default-disabled
Closed

Default telemetry API to disabled when frontend has auth#14990
mitchdenny wants to merge 1 commit intorelease/13.2from
fix/api-telemetry-default-disabled

Conversation

@mitchdenny
Copy link
Copy Markdown
Member

Description

Default Dashboard:Api:Enabled to false when frontend requires authentication and no API key is configured.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 6, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14990

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14990"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts Aspire Dashboard configuration so the Telemetry HTTP API defaults to disabled when the frontend is authenticated but the API would otherwise run unsecured (no API key), reducing the risk of exposing telemetry on the dashboard port.

Changes:

  • Added post-configure logic to default Dashboard:Api:Enabled to false when frontend auth is enabled and API auth would be Unsecured.
  • Expanded integration test coverage for the new default/override behaviors.
  • Updated API option XML docs and the dashboard HTTP API spec to document the new default behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
tests/Aspire.Dashboard.Tests/Integration/TelemetryApiTests.cs Adds configuration-focused integration tests for API enabled/disabled defaults and overrides.
src/Aspire.Dashboard/Configuration/PostConfigureDashboardOptions.cs Implements the new default-disable behavior for the telemetry API in authenticated frontend scenarios.
src/Aspire.Dashboard/Configuration/DashboardOptions.cs Updates XML docs for ApiOptions.Enabled to describe the new defaults.
docs/specs/dashboard-http-api.md Documents the updated default behavior for Dashboard:Api:Enabled and adds guidance on overriding it.

// to prevent unauthenticated access to telemetry data on the same port.
if (options.Api.Enabled is null &&
options.Frontend.AuthMode is not FrontendAuthMode.Unsecured &&
options.Api.AuthMode is ApiAuthMode.Unsecured)
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new default-disable condition is based on options.Api.AuthMode is ApiAuthMode.Unsecured, but the comment/doc say this should happen specifically when no API key is configured. As written, this can also disable the API when a key is configured but Api:AuthMode is explicitly set to Unsecured, which contradicts the intended rule and the updated docs. Consider checking key presence directly (e.g., string.IsNullOrEmpty(options.Api.PrimaryApiKey) (and/or secondary) in addition to Enabled is null and frontend auth mode) rather than relying on AuthMode alone.

Suggested change
options.Api.AuthMode is ApiAuthMode.Unsecured)
string.IsNullOrEmpty(options.Api.PrimaryApiKey) &&
string.IsNullOrEmpty(options.Api.SecondaryApiKey))

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +99
// Assert - API should default to disabled when frontend has auth but no API key
var options = app.Services.GetRequiredService<IOptionsMonitor<DashboardOptions>>().CurrentValue;
Assert.False(options.Api.Enabled);
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DashboardOptions.Api.Enabled is a nullable bool?, so using Assert.False(options.Api.Enabled) is ambiguous (and may not compile depending on Assert overloads) and can unintentionally treat null the same as false. Since this test is validating the new behavior of explicitly defaulting the API to disabled, assert the exact nullable value (e.g., that it is false).

Copilot uses AI. Check for mistakes.

// Assert - API should be enabled because explicitly configured
var options = app.Services.GetRequiredService<IOptionsMonitor<DashboardOptions>>().CurrentValue;
Assert.True(options.Api.Enabled);
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DashboardOptions.Api.Enabled is bool?. Assert.True(options.Api.Enabled) can be brittle/unclear for nullable values and may not be asserting what you intend if Enabled is ever null. Since this case sets Dashboard:Api:Enabled explicitly, assert that the value is exactly true (nullable comparison) to ensure the test is validating the explicit override behavior.

Suggested change
Assert.True(options.Api.Enabled);
Assert.Equal(true, options.Api.Enabled);

Copilot uses AI. Check for mistakes.
- The API shares the same port as the Dashboard frontend (default: 18888).
- Hosters may set `Enabled: false` to disable the API for security.
- When the frontend requires authentication (e.g., OpenID Connect) and no API key is configured, the API is disabled by default. Set `Enabled: true` explicitly to override.
- API keys are shared with MCP configuration—setting either configures both.
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The note "API keys are shared with MCP configuration—setting either configures both" doesn’t match the current implementation in PostConfigureDashboardOptions (it only copies Api -> Mcp, not the other direction). With the updated defaulting rules for Api:Enabled, this doc can further confuse hosters who set only MCP keys and expect the API to be treated as keyed. Update the note to reflect the one-way fallback (or implement bidirectional behavior).

Suggested change
- API keys are shared with MCP configuration—setting either configures both.
- MCP configuration falls back to the Dashboard API keys when MCP keys are not set; configuring MCP keys does not configure Dashboard API keys or affect `Api:Enabled`.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 6, 2026

🎬 CLI E2E Test Recordings

The following terminal recordings are available for commit 25e69b2:

Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AgentInitCommand_WithMalformedMcpJson_ShowsErrorAndExitsNonZero ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateEmptyAppHostProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateStartWaitAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
TypeScriptAppHostWithProjectReferenceIntegration ▶️ View Recording

📹 Recordings uploaded automatically from CI run #22746216176

@JamesNK
Copy link
Copy Markdown
Member

JamesNK commented Mar 12, 2026

Replaced by #15154

@JamesNK JamesNK closed this Mar 12, 2026
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants