Skip to content

upgrade to support .Net 10 and System.CommandLine v2#340

Open
aminparsa18 wants to merge 3 commits intoprom3theu5:mainfrom
aminparsa18:net10.0-upgrade
Open

upgrade to support .Net 10 and System.CommandLine v2#340
aminparsa18 wants to merge 3 commits intoprom3theu5:mainfrom
aminparsa18:net10.0-upgrade

Conversation

@aminparsa18
Copy link

@aminparsa18 aminparsa18 commented Jan 27, 2026

User description

This PR upgrades the project to .NET 10.0 and migrates to System.CommandLine v2.0, addressing several deprecation warnings and API breaking changes.

Changes Made

Framework & Dependencies

  • Upgraded target framework from .NET 9.0 to .NET 10.0
  • Updated System.CommandLine to v2.0.2
  • Updated Nuget Packages to latest version compatible with .NET 10

System.CommandLine v2.0 Migration

  • Command API Changes:

    • Migrated from CommandLineBuilder pattern to direct Command.Parse().InvokeAsync() pattern
    • Refactored all BaseOption<T> constructors to follow new API (name is now mandatory, aliases are separate)
    • Updated all option classes (AspireManifestOption, TemplatePathOption, SkipFinalKustomizeGenerationOption, etc.) to use new constructor pattern
    • Removed obsolete Name property assignments as it's now read-only
  • Dependency Injection:

    • Refactored DI middleware from builder pattern to service configuration extension method
    • Removed CommandLineBuilder.AddMiddleware() usage (removed in v2.0)
  • Help Context:

    • Updated UseDefaultMasking to work with new help system (HelpContext is now internal)

Code Cleanup

  • Fixed obsolete Rfc2898DeriveBytes constructor warnings by migrating to static Pbkdf2 method
  • Updated ServiceVolume handling to use Source property instead of string splitting
  • Removed redundant code and simplified implementations where possible

PR Type

Enhancement


Description

  • Upgrade target framework from .NET 9.0 to .NET 10.0

  • Migrate System.CommandLine from v2.0-beta to v2.0.2 stable

  • Refactor command API from CommandLineBuilder pattern to direct Command usage

  • Update all option constructors to new BaseOption API with mandatory name parameter

  • Replace deprecated Rfc2898DeriveBytes constructor with static Pbkdf2 method

  • Update dependency injection middleware from builder pattern to service configuration

  • Modernize help system integration and volume handling in Docker Compose


Diagram Walkthrough

flowchart LR
  A["Framework & Dependencies"] --> B["Target .NET 10.0"]
  A --> C["System.CommandLine v2.0.2"]
  A --> D["Update NuGet Packages"]
  E["Command API Migration"] --> F["Remove CommandLineBuilder"]
  E --> G["Direct Command.Parse().InvokeAsync()"]
  E --> H["Refactor BaseOption Constructors"]
  I["Code Cleanup"] --> J["Pbkdf2 Static Method"]
  I --> K["ServiceVolume Source Property"]
  I --> L["Help System Updates"]
Loading

File Walkthrough

Relevant files
Enhancement
52 files
AspirateCli.cs
Migrate to System.CommandLine v2 API patterns                       
+16/-15 
GlobalUsings.cs
Remove obsolete CommandLineBuilder using directive             
+0/-1     
DependencyInjectionMiddleware.cs
Refactor DI from builder pattern to service configuration
+13/-13 
Program.cs
Simplify command invocation with new v2 API                           
+5/-6     
GenerateDockerComposeManifestAction.cs
Update volume handling to use Source property                       
+5/-1     
ApplyCommand.cs
Replace AddOption with Options.Add collection                       
+4/-4     
BaseCommand.cs
Update command handler and option registration patterns   
+5/-5     
BuildCommand.cs
Replace AddOption with Options.Add collection                       
+11/-11 
DestroyCommand.cs
Replace AddOption with Options.Add collection                       
+2/-2     
GenerateCommand.cs
Replace AddOption with Options.Add collection                       
+27/-27 
GenericCommand.cs
Update handler property to Action for v2 API                         
+2/-2     
InitCommand.cs
Replace AddOption with Options.Add collection                       
+8/-8     
RunCommand.cs
Replace AddOption with Options.Add collection                       
+21/-21 
SettingsCommand.cs
Replace AddCommand with Subcommands.Add collection             
+7/-7     
BaseOption.cs
Refactor constructor to match System.CommandLine v2 API   
+12/-10 
AllowClearNamespaceOption.cs
Update constructor signature and remove Name assignment   
+2/-6     
AspireManifestOption.cs
Update constructor signature and remove Name assignment   
+3/-5     
ComponentsOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ComposeBuildsOption.cs
Update constructor signature and remove Name assignment   
+2/-5     
ContainerBuildArgsOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ContainerBuildContextOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ContainerBuilderOption.cs
Update constructor and replace AddValidator with Validators.Add
+4/-13   
ContainerImageTagOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ContainerRegistryOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ContainerRepositoryPrefixOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
DisableSecretsOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
DisableStateOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ImagePullPolicyOption.cs
Update constructor and replace AddValidator with Validators.Add
+3/-4     
IncludeDashboardOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
InputPathOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
KubernetesContextOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
LaunchProfileOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
NamespaceOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
NonInteractiveOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
OutputFormatOption.cs
Update constructor and replace AddValidator with Validators.Add
+3/-4     
OutputPathOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ParameterResourceValueOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
PreferDockerfileOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
PrivateRegistryEmailOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
PrivateRegistryOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
PrivateRegistryPasswordOption.cs
Update constructor signature and remove Name assignment   
+2/-8     
PrivateRegistryUrlOption.cs
Update constructor signature and remove Name assignment   
+2/-7     
PrivateRegistryUsernameOption.cs
Update constructor signature and remove Name assignment   
+2/-8     
ProjectPathOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
ReplaceSecretsOption.cs
Update constructor signature and remove Name assignment   
+2/-5     
RollingRestartOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
RuntimeIdentifierOption.cs
Update constructor signature and remove Name assignment   
+2/-5     
SecretPasswordOption.cs
Update constructor signature and remove Name assignment   
+2/-10   
SkipBuildOption.cs
Update constructor signature and remove Name assignment   
+2/-6     
SkipFinalKustomizeGenerationOption.cs
Update constructor signature and remove Name assignment   
+2/-3     
TemplatePathOption.cs
Update constructor signature and remove Name assignment   
+4/-4     
ComposeServiceBuilder.cs
Update collection types for Secrets and Volumes                   
+2/-2     
Bug fix
1 files
SecretProvider.cs
Replace Rfc2898DeriveBytes constructor with static Pbkdf2 method
+4/-7     
Configuration changes
8 files
main.yaml
Update dotnet version from 9.0 to 10.0                                     
+1/-1     
pull-requests.yaml
Update dotnet version from 9.0 to 10.0                                     
+1/-1     
Aspirate.Cli.csproj
Update target framework to net10.0                                             
+5/-2     
Aspirate.Commands.csproj
Update target framework to net10.0                                             
+1/-1     
Aspirate.Processors.csproj
Update target framework to net10.0                                             
+1/-1     
Aspirate.Secrets.csproj
Update target framework to net10.0                                             
+1/-1     
Aspirate.Services.csproj
Update target framework to net10.0                                             
+1/-1     
Aspirate.Shared.csproj
Update target framework to net10.0                                             
+1/-1     
Dependencies
1 files
Directory.Packages.props
Update NuGet package versions for .NET 10 compatibility   
+11/-11 

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 27, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🔴
Authentication bypass

Description: CheckPassword(string password) ignores its password parameter and derives the hash from
_password instead, which can allow password verification to succeed regardless of the
provided input (authentication bypass) once _password is set.
SecretProvider.cs [30-36]

Referred Code
public bool CheckPassword(string password)
{
    var passwordToCheckHash = Convert.ToBase64String(Rfc2898DeriveBytes.Pbkdf2(_password, _salt, 1000000, HashAlgorithmName.SHA256, 32));

    return passwordToCheckHash == State.Hash;
}
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Null service provider: GetService<T>() dereferences _serviceProvider without a null-check, which can cause
a runtime null reference instead of a controlled error when services were not configured.

Referred Code
public static T GetService<T>() where T : notnull
{
    return _serviceProvider.GetRequiredService<T>()
        ?? throw new InvalidOperationException("Service provider not configured");
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Password check bug: CheckPassword(string password) derives the hash from _password instead of the password
parameter, breaking password verification and risking incorrect authentication behavior.

Referred Code
public bool CheckPassword(string password)
{
    var passwordToCheckHash = Convert.ToBase64String(Rfc2898DeriveBytes.Pbkdf2(_password, _salt, 1000000, HashAlgorithmName.SHA256, 32));

    return passwordToCheckHash == State.Hash;
}

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

qodo-code-review bot commented Jan 27, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect password verification logic
Suggestion Impact:Updated the PBKDF2 call in CheckPassword to use the method argument `password` rather than `_password`, correcting the verification logic.

code diff:

     public bool CheckPassword(string password)
     {
-        var passwordToCheckHash = Convert.ToBase64String(Rfc2898DeriveBytes.Pbkdf2(_password, _salt, 1000000, HashAlgorithmName.SHA256, 32));
+        var passwordToCheckHash = Convert.ToBase64String(Rfc2898DeriveBytes.Pbkdf2(password, _salt, 1000000, HashAlgorithmName.SHA256, 32));

Fix the CheckPassword method to use the password parameter for hash generation
instead of the stored _password. This corrects the password verification logic.

src/Aspirate.Secrets/SecretProvider.cs [31-36]

 public bool CheckPassword(string password)
 {
-    using var pbkdf2ToCheck = new Rfc2898DeriveBytes(password, salt: _salt, iterations: 1000000, HashAlgorithmName.SHA256);
-    var passwordToCheckHash = Convert.ToBase64String(pbkdf2ToCheck.GetBytes(32));
+    var passwordToCheckHash = Convert.ToBase64String(Rfc2898DeriveBytes.Pbkdf2(password, _salt, 1000000, HashAlgorithmName.SHA256, 32));
 
     return passwordToCheckHash == State.Hash;
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 10

__

Why: This suggestion identifies a critical bug in the password verification logic introduced by the PR, where the wrong variable is used, making the check always fail. This is a severe correctness issue.

High
Refactor DI to avoid static service provider

Refactor the dependency injection setup to avoid using a static
_serviceProvider. Instead, use System.CommandLine middleware to manage the
service provider's lifecycle via the binding context.

src/Aspirate.Cli/Middleware/DependencyInjectionMiddleware.cs [3-20]

 internal static class DependencyInjectionMiddleware
 {
-    private static IServiceProvider? _serviceProvider;
-
     public static RootCommand ConfigureServices(this RootCommand rootCommand, Action<ServiceCollection> configureServices)
     {
         var services = new ServiceCollection();
         configureServices(services);
-        _serviceProvider = services.BuildServiceProvider();
+        var serviceProvider = services.BuildServiceProvider();
+
+        rootCommand.AddMiddleware(async (context, next) =>
+        {
+            context.BindingContext.AddService(_ => serviceProvider);
+            await next(context);
+        });
+
         return rootCommand;
-    }
-
-    public static T GetService<T>() where T : notnull
-    {
-        return _serviceProvider.GetRequiredService<T>()
-            ?? throw new InvalidOperationException("Service provider not configured");
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that the PR introduces a static _serviceProvider, which is an anti-pattern, and proposes a much better implementation using System.CommandLine middleware, improving the design and robustness of the dependency injection setup.

Medium
General
Guard volume name splitting

Prevent a potential NullReferenceException when creating volumes. Add a null
check before splitting volume.ShortSyntax to safely extract the volume name.

src/Aspirate.Commands.Actions.Manifests/GenerateDockerComposeManifestAction.cs [95-98]

 foreach (var volume in service.Volumes)
 {
-    volumes.Add(new Volume { Name = volume.Source ?? volume.ShortSyntax?.Split(':')[0] });
+    var name = volume.Source
+        ?? volume.ShortSyntax?.Split(':').FirstOrDefault()
+        ?? throw new InvalidOperationException("Unable to determine volume name");
+    volumes.Add(new Volume { Name = name });
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a potential NullReferenceException if volume.ShortSyntax is null and adds a necessary null-conditional operator, preventing a runtime crash.

Medium
  • Update

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant