Conversation
|
@copilot Please fully understand the content submitted in this PR and check if there are any areas in the code that need improvement. If not, generate a README/usage instruction Markdown document and place it in the doc directory. |
|
@JusterZhu I've opened a new pull request, #139, to work on those changes. Once the pull request is ready, I'll request review from you. |
* Initial plan * Add comprehensive README documentation for GeneralUpdate.Drivelution Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
|
@copilot Write test cases based on the core content of GeneralUpdate.Drivelution. |
|
@JusterZhu I've opened a new pull request, #140, to work on those changes. Once the pull request is ready, I'll request review from you. |
* Initial plan * Add comprehensive test cases for GeneralUpdate.Drivelution Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> * Address code review feedback: improve test quality and cleanup Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
|
@copilot Replace all instances of "DriverUpdate" with "Drivelution". |
|
@JusterZhu I've opened a new pull request, #141, to work on those changes. Once the pull request is ready, I'll request review from you. |
* Initial plan * Replace all instances of DriverUpdate with Drivelution Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> * Update error code prefixes from DU_ to DR_ Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
The filename has not been modified. |
|
@copilot Add a method in GeneralDrivelution.cs to read the driver information from the local directory and return a list of DriverInfo to the caller. If this has already been implemented, please let me know where the code is located. |
|
@JusterZhu I've opened a new pull request, #142, to work on those changes. Once the pull request is ready, I'll request review from you. |
* Initial plan * Add GetDriversFromDirectoryAsync method to read driver information from local directory Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> * Add tests for GetDriversFromDirectoryAsync method Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> * Fix security issues: prevent command injection and improve certificate parsing Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> * Translate all Chinese annotations to English Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new GeneralUpdate.Drivelution .NET 8 library intended to provide cross-platform (Windows/Linux; macOS placeholder) driver update workflows including validation, backup/rollback, logging, and supporting utilities, plus a new xUnit test project and documentation.
Changes:
- Introduces
GeneralUpdate.Drivelutionproject with abstractions (models/interfaces/exceptions) and factory/entry-point APIs. - Adds Windows/Linux implementations (permission checks, validation helpers, backup, install scaffolding, driver discovery) and shared utilities (hashing, SemVer compare, compatibility, restart helper).
- Adds
DrivelutionTesttest project and a large usage/feature documentation page.
Reviewed changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| src/c#/GeneralUpdate.sln | Adds GeneralUpdate.Drivelution project to the solution. |
| src/c#/GeneralUpdate.Drivelution/GeneralUpdate.Drivelution.csproj | New library project definition (net8.0 + Serilog deps + trimming/AOT flags). |
| src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs | Public static entry point + convenience APIs + platform info wrapper. |
| src/c#/GeneralUpdate.Drivelution/Core/DriverUpdaterFactory.cs | Platform detection and creation of OS-specific implementations. |
| src/c#/GeneralUpdate.Drivelution/Core/Logging/LoggerConfigurator.cs | Serilog configuration factory based on options. |
| src/c#/GeneralUpdate.Drivelution/Core/Utilities/VersionComparer.cs | SemVer 2.0 parsing/comparison helper. |
| src/c#/GeneralUpdate.Drivelution/Core/Utilities/RestartHelper.cs | Cross-platform restart helper (shutdown invocation + prompt stub). |
| src/c#/GeneralUpdate.Drivelution/Core/Utilities/HashValidator.cs | Async file hashing and hash validation utility. |
| src/c#/GeneralUpdate.Drivelution/Core/Utilities/CompatibilityChecker.cs | OS/arch compatibility checks + report model. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/IGeneralDrivelution.cs | Core updater interface contract. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/IDriverValidator.cs | Validator interface (integrity/signature/compatibility). |
| src/c#/GeneralUpdate.Drivelution/Abstractions/IDriverBackup.cs | Backup/restore/delete abstraction. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/INetworkDownloader.cs | Placeholder download interface for future extension. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/Models/DriverInfo.cs | Driver metadata model (hash/signature/compat fields). |
| src/c#/GeneralUpdate.Drivelution/Abstractions/Models/UpdateStrategy.cs | Update strategy model (retry/restart/skip flags etc.). |
| src/c#/GeneralUpdate.Drivelution/Abstractions/Models/UpdateResult.cs | Update result model + status enum. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/Models/ErrorInfo.cs | Error model + error type enum. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/Exceptions/DriverUpdateExceptions.cs | Exception hierarchy for driver update operations. |
| src/c#/GeneralUpdate.Drivelution/Abstractions/Configuration/DriverUpdateOptions.cs | Library configuration options model. |
| src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs | Windows updater implementation (permission/validate/backup/install/verify/rollback/discovery). |
| src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverValidator.cs | Windows validator (hash/signature/compat). |
| src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverBackup.cs | Windows file backup/restore/delete implementation. |
| src/c#/GeneralUpdate.Drivelution/Windows/Helpers/WindowsSignatureHelper.cs | Windows Authenticode signature validation helper. |
| src/c#/GeneralUpdate.Drivelution/Windows/Helpers/WindowsPermissionHelper.cs | Windows admin check + UAC elevation helpers. |
| src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs | Linux updater implementation (sudo check, validate/backup/install/rollback/discovery). |
| src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverValidator.cs | Linux validator (hash/signature via GPG/compat). |
| src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverBackup.cs | Linux file backup/restore/delete implementation. |
| src/c#/GeneralUpdate.Drivelution/Linux/Helpers/LinuxSignatureHelper.cs | GPG signature validation helper. |
| src/c#/GeneralUpdate.Drivelution/Linux/Helpers/LinuxPermissionHelper.cs | Root/sudo detection + sudo execution helper. |
| src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs | macOS placeholder implementations throwing PlatformNotSupportedException. |
| src/c#/DrivelutionTest/DrivelutionTest.csproj | New xUnit test project referencing the new library. |
| src/c#/DrivelutionTest/Core/DriverUpdaterFactoryTests.cs | Tests for platform factory behavior. |
| src/c#/DrivelutionTest/GeneralDrivelutionTests.cs | Tests for the public static entrypoint API. |
| src/c#/DrivelutionTest/Models/ModelTests.cs | Tests for models/enums defaulting and setters. |
| src/c#/DrivelutionTest/Utilities/CompatibilityCheckerTests.cs | Tests for compatibility checker utility behavior. |
| src/c#/DrivelutionTest/Utilities/HashValidatorTests.cs | Tests for hashing utility behavior and cancellation. |
| src/c#/DrivelutionTest/Utilities/VersionComparerAndRestartHelperTests.cs | Tests for SemVer comparer and restart helper basic behavior. |
| doc/GeneralUpdate.Drivelution.md | New long-form library documentation and examples. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Import trusted keys if provided | ||
| if (trustedKeys.Any()) | ||
| { | ||
| foreach (var key in trustedKeys) | ||
| { | ||
| await ImportGpgKeyAsync(key); | ||
| } | ||
| } |
There was a problem hiding this comment.
Importing trustedKeys via gpg --import/--recv-keys modifies the user's/system keyring as a side effect of validation. For library code this is risky operationally/security-wise; consider verifying against a temporary keyring (GNUPGHOME to a temp dir) or requiring callers to manage key import separately.
| // Permission check | ||
| await LinuxPermissionHelper.EnsureSudoAsync(); | ||
|
|
||
| // Validation |
There was a problem hiding this comment.
EnsureSudoAsync() only checks sudo availability, but the subsequent install/rollback commands (insmod, modprobe, dpkg, rpm, shutdown, etc.) are executed without sudo. On a typical Linux system this means updates will fail unless the entire process is already running as root. Either require root explicitly (EnsureRoot) or route privileged operations through ExecuteWithSudoAsync/sudo execution.
| /// 是否跳过签名验证(仅调试模式) | ||
| /// Skip signature validation (debug mode only) | ||
| /// </summary> | ||
| public bool SkipSignatureValidation { get; set; } = false; | ||
|
|
||
| /// <summary> | ||
| /// 是否跳过哈希验证(仅调试模式) | ||
| /// Skip hash validation (debug mode only) | ||
| /// </summary> | ||
| public bool SkipHashValidation { get; set; } = false; | ||
|
|
||
| /// <summary> |
There was a problem hiding this comment.
SkipSignatureValidation and SkipHashValidation are defined in UpdateStrategy, but the current platform implementations don’t consult them (validation is based only on whether DriverInfo.Hash/TrustedPublishers are set). This makes the API misleading; either wire these flags into ValidateAsync/UpdateAsync or remove/relocate them until supported.
| /// 是否跳过签名验证(仅调试模式) | |
| /// Skip signature validation (debug mode only) | |
| /// </summary> | |
| public bool SkipSignatureValidation { get; set; } = false; | |
| /// <summary> | |
| /// 是否跳过哈希验证(仅调试模式) | |
| /// Skip hash validation (debug mode only) | |
| /// </summary> | |
| public bool SkipHashValidation { get; set; } = false; | |
| /// <summary> |
| ```csharp | ||
| if (!result.Success && result.Error != null) | ||
| { | ||
| Console.WriteLine($"Error Type: {result.Error.Type}"); | ||
| Console.WriteLine($"Message: {result.Error.Message}"); | ||
| Console.WriteLine($"Details: {result.Error.Details}"); | ||
| Console.WriteLine($"Can Retry: {result.Error.CanRetry}"); | ||
| Console.WriteLine($"Error Code: {result.Error.ErrorCode}"); | ||
| Console.WriteLine($"Timestamp: {result.Error.Timestamp}"); | ||
| } | ||
| ``` | ||
|
|
||
| ### Error Types | ||
|
|
||
| ```csharp | ||
| public enum ErrorType | ||
| { | ||
| PermissionDenied, // Insufficient privileges | ||
| HashValidationFailed, // Hash mismatch | ||
| SignatureValidationFailed, // Invalid signature | ||
| CompatibilityCheckFailed, // Incompatible driver | ||
| InstallationFailed, // Installation error | ||
| BackupFailed, // Backup creation failed | ||
| RollbackFailed, // Rollback failed | ||
| NetworkError, // Download/network issue | ||
| TimeoutError, // Operation timed out | ||
| UnknownError // Unexpected error | ||
| } |
There was a problem hiding this comment.
The documentation references result.Error.ErrorCode and defines an ErrorType enum with values (CompatibilityCheckFailed, TimeoutError, UnknownError, etc.) that don’t match the actual code (ErrorInfo.Code and ErrorType.CompatibilityValidationFailed, Timeout, Unknown, ...). Please update the doc snippets/enums to match the implemented API so consumers don’t copy/paste broken code.
| public static async Task<bool> CanUseSudoAsync() | ||
| { | ||
| try | ||
| { | ||
| var startInfo = new ProcessStartInfo | ||
| { | ||
| FileName = "sudo", | ||
| Arguments = "-n true", | ||
| UseShellExecute = false, | ||
| RedirectStandardOutput = true, | ||
| RedirectStandardError = true, | ||
| CreateNoWindow = true | ||
| }; | ||
|
|
||
| using var process = Process.Start(startInfo); | ||
| if (process != null) | ||
| { | ||
| await process.WaitForExitAsync(); | ||
| return process.ExitCode == 0; |
There was a problem hiding this comment.
CanUseSudoAsync uses sudo -n true, which only succeeds for passwordless sudo. Users who can sudo with a password will be treated as not having sudo privileges, causing false permission failures. If interactive prompting is acceptable, drop -n; if not, adjust the error message to explicitly require passwordless sudo or running as root.
| catch (DriverValidationException ex) | ||
| { | ||
| _logger.Error(ex, "Validation failed during driver update"); | ||
| result.Success = false; | ||
| result.Status = UpdateStatus.Failed; | ||
| result.Error = CreateErrorInfo(ex, ErrorType.HashValidationFailed, false); | ||
| result.StepLogs.Add($"[{DateTime.Now:HH:mm:ss}] ERROR: {ex.Message}"); |
There was a problem hiding this comment.
DriverValidationException is always being mapped to ErrorType.HashValidationFailed, even though validation failures can also be signature/compatibility/file-not-found. This will misreport the error type to callers; set ErrorType based on ex.ValidationType (or extend the exception to carry a more specific ErrorType).
| var backupPath = GenerateBackupPath(driverInfo, strategy.BackupPath); | ||
| if (await BackupAsync(driverInfo, backupPath, cancellationToken)) | ||
| { | ||
| result.BackupPath = backupPath; | ||
| _logger.Information("Backup created at: {BackupPath}", backupPath); | ||
| } |
There was a problem hiding this comment.
BackupAsync returns only a boolean and WindowsDriverBackup appends a timestamp to the actual backup filename, but UpdateResult.BackupPath is set to the pre-timestamp path. This makes the reported backup path incorrect and breaks later rollback logic; return/store the real backup file path from the backup layer.
| if (strategy.RequireBackup) | ||
| { | ||
| result.Status = UpdateStatus.BackingUp; | ||
| var backupPath = GenerateBackupPath(driverInfo, strategy.BackupPath); | ||
| if (await BackupAsync(driverInfo, backupPath, cancellationToken)) | ||
| { | ||
| result.BackupPath = backupPath; | ||
| } |
There was a problem hiding this comment.
Like the Windows implementation, BackupAsync sets result.BackupPath to the pre-timestamp path, but LinuxDriverBackup writes a timestamped file and rollback expects backupPath to be a directory. This makes rollback impossible; store the actual backup file path (or change backup to create a directory-based backup compatible with rollback).
| _logger.Information("Rolling back driver from backup: {BackupPath}", backupPath); | ||
|
|
||
| if (!Directory.Exists(backupPath)) | ||
| { | ||
| _logger.Error("Backup directory not found: {BackupPath}", backupPath); | ||
| return false; | ||
| } | ||
|
|
||
| // Find backed up kernel modules (.ko files) | ||
| var koFiles = Directory.GetFiles(backupPath, "*.ko", SearchOption.AllDirectories); | ||
|
|
||
| if (!koFiles.Any()) | ||
| { | ||
| _logger.Warning("No kernel module backups found in: {BackupPath}", backupPath); | ||
| return false; | ||
| } |
There was a problem hiding this comment.
RollbackAsync requires backupPath to be an existing directory and searches for *.ko, but backups are created as individual timestamped files (see LinuxDriverBackup). As a result, rollback will always fail the Directory.Exists(backupPath) check; adjust rollback to restore from the backup file or change backup format to a directory containing restored artifacts.
| // Try to get package info using dpkg-deb command | ||
| // Use proper argument passing to avoid injection issues | ||
| var escapedPath = debPath.Replace("'", "'\\''"); | ||
| var output = await ExecuteCommandAsync("dpkg-deb", $"-I '{escapedPath}'", cancellationToken); | ||
| var lines = output.Split('\n'); |
There was a problem hiding this comment.
ParseDebPackageAsync/ParseRpmPackageAsync wrap the path in single quotes inside the argument string (e.g., -I '{escapedPath}'). Since UseShellExecute=false, these quotes are passed literally to dpkg-deb/rpm, so the commands may fail to locate the file. Use ArgumentList (preferred) or quote the path in a way appropriate for direct argv passing (typically no extra quoting needed if using ArgumentList).
No description provided.