Add 'aspire certs' command for certificate management#15117
Add 'aspire certs' command for certificate management#15117davidfowl merged 9 commits intorelease/13.2from
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15117Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15117" |
|
The only issue I have with fix is that we can't always fix the problem and agents can do a way better job. |
There was a problem hiding this comment.
Pull request overview
Adds a new aspire doctor fix subcommand to automatically repair environment issues (starting with HTTPS dev certificate problems), and updates aspire doctor output to recommend running these fixes instead of dotnet dev-certs commands.
Changes:
- Introduces
DoctorFixCommandwith dynamic subcommands/actions driven by a newIHealableEnvironmentCheckinterface. - Extends
DevCertsCheckto provide fix actions (clean,trust) and updates doctor output to suggestaspire doctor fix certificates. - Adds certificate clean support to the native certificate runner and expands JSON output models/source-gen support, plus new tests and localized strings.
Reviewed changes
Copilot reviewed 44 out of 46 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Aspire.Cli.Tests/Utils/DevCertsCheckTests.cs | Adds coverage for “no certificates” warning behavior. |
| tests/Aspire.Cli.Tests/Utils/DevCertsCheckHealTests.cs | Adds unit tests for heal action recommendation + heal execution paths. |
| tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs | Registers DevCertsCheck as both IEnvironmentCheck and IHealableEnvironmentCheck; registers DoctorFixCommand. |
| tests/Aspire.Cli.Tests/TestServices/TestCertificateToolRunner.cs | Adds CleanHttpCertificateAsync support to the test runner. |
| tests/Aspire.Cli.Tests/Commands/DoctorFixCommandTests.cs | Verifies help/exit-code behavior for doctor fix command surface. |
| tests/Aspire.Cli.Tests/Certificates/CertificateServiceTests.cs | Updates test stub to satisfy new ICertificateToolRunner API. |
| src/Aspire.Cli/Utils/EnvironmentChecker/IHealableEnvironmentCheck.cs | Introduces healable-check contract (EvaluateAsync/HealAsync) and action/result models. |
| src/Aspire.Cli/Utils/EnvironmentChecker/EnvironmentCheckResult.cs | Adds JSON DTOs for doctor fix output (DoctorFixResponse, etc.). |
| src/Aspire.Cli/Utils/EnvironmentChecker/DevCertsCheck.cs | Implements healing for dev-certs; updates doctor fix suggestions and categorization. |
| src/Aspire.Cli/Commands/DoctorFixCommand.cs | Adds doctor fix command with --all and per-check/action subcommands + JSON output. |
| src/Aspire.Cli/Commands/DoctorCommand.cs | Wires DoctorFixCommand under aspire doctor. |
| src/Aspire.Cli/Certificates/ICertificateToolRunner.cs | Adds CleanHttpCertificateAsync. |
| src/Aspire.Cli/Certificates/NativeCertificateToolRunner.cs | Implements native clean operation via CertificateManager.CleanupHttpsCertificates(). |
| src/Aspire.Cli/JsonSourceGenerationContext.cs | Adds source-gen metadata for new doctor fix JSON types. |
| src/Aspire.Cli/Program.cs | Registers DoctorFixCommand + healable checks and updated DevCertsCheck DI pattern. |
| src/Aspire.Cli/DotNet/DotNetCliRunner.cs | Removes TrustHttpCertificateAsync method (now handled via native runner abstraction). |
| src/Aspire.Cli/Resources/DoctorFixCommandStrings.resx | Adds localizable strings for doctor fix UX. |
| src/Aspire.Cli/Resources/DoctorFixCommandStrings.Designer.cs | Adds resource accessor for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/DoctorCommandStrings.resx | Adds localizable strings for certificate healing messages used by DevCertsCheck. |
| src/Aspire.Cli/Resources/DoctorCommandStrings.Designer.cs | Updates resource designer for new healing strings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.cs.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.de.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.es.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.fr.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.it.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.ja.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.ko.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.pl.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.pt-BR.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.ru.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.tr.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.zh-Hans.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorFixCommandStrings.zh-Hant.xlf | Localization scaffolding for DoctorFixCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.cs.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.de.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.es.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.fr.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.it.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.ja.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.ko.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.pl.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.pt-BR.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.ru.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.tr.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.zh-Hans.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
| src/Aspire.Cli/Resources/xlf/DoctorCommandStrings.zh-Hant.xlf | Localization scaffolding for new healing strings in DoctorCommandStrings. |
Files not reviewed (2)
- src/Aspire.Cli/Resources/DoctorCommandStrings.Designer.cs: Language not supported
- src/Aspire.Cli/Resources/DoctorFixCommandStrings.Designer.cs: Language not supported
You can also share your feedback on Copilot code review. Take the survey.
src/Aspire.Cli/Utils/EnvironmentChecker/IHealableEnvironmentCheck.cs
Outdated
Show resolved
Hide resolved
I tried to balance it by having both a "fix any issues that doctor detects and we're able to fix" flow while keeping CLI commands for the individual fix actions. The alternative approach would be a dedicated |
🎬 CLI E2E Test RecordingsThe following terminal recordings are available for commit
📹 Recordings uploaded automatically from CI run #22991558337 |
| return Task.FromResult<IReadOnlyList<EnvironmentCheckResult>>([new EnvironmentCheckResult | ||
| { | ||
| Category = "sdk", | ||
| Category = "environment", |
There was a problem hiding this comment.
Should category be an enum? I assume we resolve it at some point to a description. It would be better if there was a constrained enum rather than a string
There was a problem hiding this comment.
That's a larger consideration; if we did want to make the change I'd do it in a separate PR as it would change the overall doctor API.
Introduce IHealableEnvironmentCheck interface that environment checks can implement to support automated fix actions. DevCertsCheck is the first implementor, providing 'clean' and 'trust' actions that use the native CertificateManager fork instead of subprocess calls. Key changes: - IHealableEnvironmentCheck with HealAction/HealResult records and smart state-based evaluation via EvaluateAsync - DoctorFixCommand with dynamic sub-commands per healable check, --all flag, --format (table/json) output support - DevCertsCheck heal implementation using ICertificateToolRunner with shared code between check and heal paths - Doctor results updated to suggest 'aspire doctor fix certificates' instead of 'dotnet dev-certs' commands - Localizable resource strings for all user-facing text - Structured JSON output matching aspire doctor response format Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix ProgressDescription doc to say 'status message' not 'spinner' - Align EvaluateHealActions with doctor: multiple all-trusted certs no longer triggers destructive trust action - Route InteractionService output to stderr in dynamic sub-commands when --format json is requested (BaseCommand routing doesn't apply) - Use HealCommandName instead of HealCommandDescription in category header to avoid awkward 'Applying Fix ... fixes' text - Fix category inconsistency: single untrusted cert now uses 'environment' category like all other dev-cert results Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Five E2E tests covering the doctor fix command: - Fix certificates with untrusted cert (evaluates and repairs) - Fix certificates with already trusted cert (reports no issues) - Fix --all with untrusted cert (evaluates all checks) - Explicit clean sub-command (removes certificates) - JSON format output (validates structured response) All tests use Docker terminal automation with SequenceCounter for deterministic prompt detection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…localize strings - Drop async from ICertificateToolRunner: all methods are synchronous (CertificateManager runs in-process, no subprocess needed) - Remove DevCertTrustLevel string constants, use CertificateManager.TrustLevel enum - Remove dead DotNetCliRunner.CheckHttpCertificateMachineReadableAsync - SSL_CERT_DIR fix: detect system OpenSSL cert dir via 'openssl version -d' instead of hardcoding /etc/ssl/certs; always prepend $SSL_CERT_DIR - Localize all DevCertsCheck result strings via DoctorCommandStrings - Keep CLI commands as format args (never localized) - Fix elevation permission strings for consistency - Update all test doubles to match new sync interface Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0ff5aa5 to
564b8a2
Compare
The DoctorFixCertificates_WithTrustedCert_ReportsNoIssues test was searching for 'No issues found' but the actual output is 'No fixable issues were identified.' from DoctorFixCommandStrings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add CertificatesCommand with clean and trust subcommands - Remove DoctorFixCommand and IHealableEnvironmentCheck infrastructure - Remove DoctorFixCommandStrings resources and 13 XLF files - Remove HealCertificates* entries from DoctorCommandStrings - Update DevCertsCheck to recommend 'aspire certificates clean/trust' - Remove ICertificateToolRunner dependency from DevCertsCheck - Add CertificatesCommandStrings resources with XLF files - Replace DoctorFixCommandTests with CertificatesCommandTests - Replace DevCertsCheckHealTests with DevCertsCheckFixRecommendationTests - Update E2E tests to use aspire certificates clean/trust commands - All 1591 CLI tests pass Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Can we call it @JamesNK any thoughts on the ux? |
- Extract CleanCommand and TrustCommand from nested classes to top-level CertificatesCleanCommand and CertificatesTrustCommand, registered in DI following the standard subcommand pattern (matching Secret, Telemetry, etc.) - Rename the CLI command from 'certificates' to 'certs' - Update doctor fix recommendations to reference 'aspire certs' commands - Update all tests and xlf localization notes
- Replace (bool, string?) tuple with CertificateCleanResult class - Add [MemberNotNullWhen(false, nameof(ErrorMessage))] so ErrorMessage is guaranteed non-null on failure - Surface exception details in clean failure output
…ove unused types - Extract CertificateHelpers with shared IsSuccessfulTrustResult and OpenSSL detection - Handle UserCancelledTrustStep in trust command with specific warning message - Detect Windows cert store dialog cancellation (HResult 0x800704C7) in clean command - Add WasCancelled property to CertificateCleanResult - Remove unused DoctorFix types (DoctorFixResponse, DoctorFixActionResult, DoctorFixSummary) - Make CertificateServiceException internal - Add TrustCancelled and CleanCancelled resource strings with localization
|
@danegsta Double check my changes tomorrow when you get online. Merge if it is good to go. |
Looks good (it'd be nice to open a PR on aspnetcore to upstream your cancellation detection improvement). I did a little experimenting to see if we could handle MacOS cancellation, but there cancelling or sending Ctrl+C just results in an InvalidOperationException, so there's not really a way to differentiate cancellation from failure. |
I'm going to open a follow up PR that adds extra certificate metadata to the |
|
Follow up to expose details on identified certificates in |








Description
Adds a new top-level
aspire certscommand withcleanandtrustsubcommands for managing HTTPS development certificates. This provides a user-friendly way to resolve certificate issues without needing to manually rundotnet dev-certscommands, particularly for polyglot users who may not be familiar with .NET tooling.Certificate operations use the local
CertificateManagerdirectly (native calls, no subprocess), so the certificates are functionally identical to those created bydotnet dev-certs.Command Structure
Doctor Integration
aspire doctornow provides context-specific certificate fix recommendations:aspire certs trustaspire certs cleanthenaspire certs trustSSL_CERT_DIRenvironment variable configurationOther Changes
ICertificateToolRunneris now fully synchronous (CheckHttpCertificate,TrustHttpCertificate,CleanHttpCertificate) since all operations use in-processCertificateManagerDevCertsCheckno longer depends onICertificateToolRunner— it only reads certificates for diagnosticsTrustHttpCertificateAsync/CleanHttpCertificateAsyncfromIDotNetCliRunnerFixes #15036
Checklist
<code/>elements on your triple slash comments?aspire.devissue: