Skip to content

fix: resolve 5 CodeQL source alerts and suppress 1 intentional obsolete call#428

Merged
laurentiu021 merged 1 commit into
mainfrom
fix/codeql-source-alerts
May 18, 2026
Merged

fix: resolve 5 CodeQL source alerts and suppress 1 intentional obsolete call#428
laurentiu021 merged 1 commit into
mainfrom
fix/codeql-source-alerts

Conversation

@laurentiu021

@laurentiu021 laurentiu021 commented May 18, 2026

Copy link
Copy Markdown
Owner

Summary

Resolves all 6 remaining CodeQL source code alerts (24 obj/ alerts pending auto-dismiss from codeql-config exclusion).

Changes

  • ViewModelBase.cs — replaced generic catch (Exception) with specific types (InvalidOperationException, UnauthorizedAccessException, IOException, HttpRequestException, TimeoutException)
  • UninstallerService.cs — converted foreach+if to LINQ .Any() (cs/linq/missed-where)
  • WindowsFeaturesService.cs — converted foreach to .Select().Where() pipeline (cs/linq/missed-select)
  • ProcessManagerViewModel.cs — extracted complex condition into 3 helper methods (cs/complex-condition)
  • UpdateService.cs — replaced Path.Combine with Path.Join (cs/path-combine)
  • codeql-config.yml — added query filter to suppress cs/call-to-obsolete-method for intentional CreateFromSignedFile usage (no modern .NET replacement)

CodeQL Alerts Addressed

Also in this PR

  • CHANGELOG alignment fix: corrected version numbering for v0.48.31 and v0.48.32 entries

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling with more detailed error messages for better troubleshooting
    • Enhanced performance in console and logs views with optimized buffer management and batching
  • Chores

    • Code refactoring and quality improvements across services and view models
    • Updated build configuration and tooling

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR resolves CodeQL alerts and improves code maintainability through targeted refactoring. Configuration suppresses an intentional obsolete-method call, while six files are updated: loops converted to LINQ, filter logic extracted into helpers, exception handling made specific, and Path.Combine standardized to Path.Join.

Changes

CodeQL Cleanup and Refactoring

Layer / File(s) Summary
CodeQL Configuration and Release Documentation
.github/codeql-config.yml, CHANGELOG.md
CodeQL configuration adds a query filter excluding cs/call-to-obsolete-method check for UpdateService.VerifyAuthenticode, and CHANGELOG documents CodeQL resolutions across versions 0.48.30–0.48.33 including exception type tightening, loop-to-LINQ conversions, and Path.Join standardization.
Service-Layer Loop-to-LINQ and Path API Updates
SysManager/SysManager/Services/UninstallerService.cs, SysManager/SysManager/Services/UpdateService.cs, SysManager/SysManager/Services/WindowsFeaturesService.cs
IsUnderTrustedDirectory replaces foreach with Any() using case-insensitive prefix check; DownloadAsync switches from Path.Combine to Path.Join; ParseFeatureList converts imperative loop-and-accumulate to LINQ Where/Select/OrderBy pipeline with null filtering.
ViewModel Filter Extraction and Exception Handling
SysManager/SysManager/ViewModels/ProcessManagerViewModel.cs, SysManager/SysManager/ViewModels/ViewModelBase.cs
MatchesFilter delegates to three dedicated helpers (MatchesName, MatchesDescription, MatchesPid) for case-insensitive and null-safe matching. InitializeAsync replaces single generic exception handler with five specific catch blocks (InvalidOperationException, UnauthorizedAccessException, IOException, HttpRequestException, TimeoutException), each with targeted logging.

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly Related PRs

  • laurentiu021/SystemManager#413: Overlaps on multiple CodeQL-driven changes—Path.Join migration, UninstallerService trusted-directory refactoring, and ProcessManagerViewModel filter extraction.
  • laurentiu021/SystemManager#416: Modifies ViewModelBase.InitializeAsync exception handling and centralizes safe async initialization logic.
  • laurentiu021/SystemManager#401: Introduces UpdateService.VerifyAuthenticode Authenticode logic, which this PR's CodeQL config directly suppresses.

Poem

🐰 Loops to pipelines, exceptions split clear,
Path standards aligned, CodeQL squeaks cheer—
Refactoring ripples through services and views,
Each helper extracted, each handler renews!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main objective: resolving 5 CodeQL alerts and suppressing 1 intentional obsolete call, which matches the changes across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/codeql-source-alerts

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/codeql-config.yml:
- Around line 11-13: Remove the unsupported "path" field from the
query-filters.exclude entry so the exclusion is not applied globally: delete the
entire exclude block that contains id: cs/call-to-obsolete-method (the one
attempting to target SysManager/SysManager/Services/UpdateService.cs), leaving
CodeQL to rely on the local pragmas already present (the existing "`#pragma`
warning disable SYSLIB0057" usages in UpdateService.cs and SpeedTestService.cs)
instead of a repository-wide suppression.

In `@SysManager/SysManager/Services/UninstallerService.cs`:
- Around line 405-407: The current trusted-directory check in UninstallerService
(the lambda returning trustedDirs.Any(...)) uses StartsWith and can be bypassed
by sibling paths; change it to compare normalized full paths with
directory-boundary checks by normalizing both fullPath and each trusted dir via
Path.GetFullPath, ensuring each trusted dir has a trailing directory separator
(e.g., append Path.DirectorySeparatorChar if missing) and then use
fullPathNormalized.StartsWith(trustedDirNormalized,
StringComparison.OrdinalIgnoreCase) so only paths under that directory (or the
directory itself) match; update the Any(...) predicate to perform these
normalizations and the separator-aware comparison.

In `@SysManager/SysManager/ViewModels/ViewModelBase.cs`:
- Around line 34-53: The narrow exception handlers in
ViewModelBase.InitializeAsync leave unhandled exceptions from its async void
path; add a final catch (Exception ex) at the end of the try/catch chain inside
InitializeAsync to log the unexpected exception (using Log.Error with context
including callerName) and swallow or handle it to preserve the documented safety
guarantee for async void initialization; ensure the new catch comes after the
existing specific catches in the InitializeAsync method of ViewModelBase so no
unexpected exception can escape.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d0707758-a032-42ad-ba8a-ca9b7093c3a8

📥 Commits

Reviewing files that changed from the base of the PR and between b472eda and cc43f82.

📒 Files selected for processing (7)
  • .github/codeql-config.yml
  • CHANGELOG.md
  • SysManager/SysManager/Services/UninstallerService.cs
  • SysManager/SysManager/Services/UpdateService.cs
  • SysManager/SysManager/Services/WindowsFeaturesService.cs
  • SysManager/SysManager/ViewModels/ProcessManagerViewModel.cs
  • SysManager/SysManager/ViewModels/ViewModelBase.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build & unit tests
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (4)
SysManager/SysManager/ViewModels/ProcessManagerViewModel.cs (1)

162-174: LGTM!

SysManager/SysManager/Services/UpdateService.cs (1)

144-144: LGTM!

SysManager/SysManager/Services/WindowsFeaturesService.cs (1)

117-142: LGTM!

CHANGELOG.md (1)

11-31: LGTM!

Also applies to: 39-39

Comment thread .github/codeql-config.yml
Comment on lines +11 to +13
- exclude:
id: cs/call-to-obsolete-method
path: SysManager/SysManager/Services/UpdateService.cs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In GitHub CodeQL codeql-config.yml, does query-filters.excludesupport apathfield? Please list the officially supported fields forquery-filters and whether unsupported keys are ignored or rejected.

💡 Result:

In GitHub CodeQL configuration files (codeql-config.yml), the query-filters.exclude block does not support a path field [1][2]. The query-filters mechanism is designed to filter queries based on their metadata properties (such as id, tags, or severity) rather than file paths [1][2]. To exclude specific files or directories from CodeQL analysis, you should use the top-level paths-ignore field in your codeql-config.yml file instead [3][2][4]. Officially supported fields for query-filters The query-filters section supports include and exclude blocks [2]. Within these blocks, you can filter queries using any valid CodeQL query metadata property [1]. Common examples include: - id: The unique identifier of the query [5][1][2]. - tags: The tags associated with the query [2]. - kind: The kind of query (e.g., problem, path-problem, table) [5][2]. - problem.severity: The severity level of the query (e.g., warning, recommendation) [2]. Handling of unsupported keys In GitHub Actions, providing unsupported keys in the codeql-config.yml file typically results in a warning or the key being ignored by the CodeQL action [6]. If you provide an invalid property at the top level of the configuration file or within specific blocks, the action may log a warning indicating that the property is not a valid input or is being ignored [6]. It is recommended to strictly follow the documented schema to ensure your configuration is applied correctly [2].

Citations:


🏁 Script executed:

#!/bin/bash
# Verify whether obsolete-call usage is truly isolated to the intended call site.
rg -n --type=cs 'CreateFromSignedFile|SYSLIB0057|`#pragma` warning disable SYSLIB0057'

Repository: laurentiu021/SystemManager

Length of output: 822


Remove path from query-filters.exclude—it's unsupported and causes the suppression to be global

query-filters.exclude does not support a path field. Unsupported fields are ignored, so the id: cs/call-to-obsolete-method exclusion will suppress this rule across the entire repository, not just UpdateService.cs. Since both UpdateService.cs and SpeedTestService.cs already use local #pragma warning disable SYSLIB0057 pragmas at the call sites (which is the correct approach), remove the ineffective CodeQL config line entirely.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/codeql-config.yml around lines 11 - 13, Remove the unsupported
"path" field from the query-filters.exclude entry so the exclusion is not
applied globally: delete the entire exclude block that contains id:
cs/call-to-obsolete-method (the one attempting to target
SysManager/SysManager/Services/UpdateService.cs), leaving CodeQL to rely on the
local pragmas already present (the existing "`#pragma` warning disable SYSLIB0057"
usages in UpdateService.cs and SpeedTestService.cs) instead of a repository-wide
suppression.

Comment on lines +405 to +407
return trustedDirs.Any(dir =>
!string.IsNullOrEmpty(dir) &&
fullPath.StartsWith(dir, StringComparison.OrdinalIgnoreCase));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Harden trusted-directory matching to avoid prefix bypass.

This check trusts paths that only start with a trusted prefix, which can be bypassed by sibling paths (for example, C:\Program Files Evil\...). Since this guards execution of registry-sourced uninstall commands, it should enforce a directory-boundary match.

Proposed fix
-        return trustedDirs.Any(dir =>
-            !string.IsNullOrEmpty(dir) &&
-            fullPath.StartsWith(dir, StringComparison.OrdinalIgnoreCase));
+        var normalizedPath = System.IO.Path.GetFullPath(fullPath)
+            .TrimEnd(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar);
+
+        return trustedDirs.Any(dir =>
+        {
+            if (string.IsNullOrWhiteSpace(dir)) return false;
+            var normalizedDir = System.IO.Path.GetFullPath(dir)
+                .TrimEnd(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar);
+
+            return normalizedPath.Equals(normalizedDir, StringComparison.OrdinalIgnoreCase)
+                || normalizedPath.StartsWith(
+                    normalizedDir + System.IO.Path.DirectorySeparatorChar,
+                    StringComparison.OrdinalIgnoreCase)
+                || normalizedPath.StartsWith(
+                    normalizedDir + System.IO.Path.AltDirectorySeparatorChar,
+                    StringComparison.OrdinalIgnoreCase);
+        });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/Services/UninstallerService.cs` around lines 405 - 407,
The current trusted-directory check in UninstallerService (the lambda returning
trustedDirs.Any(...)) uses StartsWith and can be bypassed by sibling paths;
change it to compare normalized full paths with directory-boundary checks by
normalizing both fullPath and each trusted dir via Path.GetFullPath, ensuring
each trusted dir has a trailing directory separator (e.g., append
Path.DirectorySeparatorChar if missing) and then use
fullPathNormalized.StartsWith(trustedDirNormalized,
StringComparison.OrdinalIgnoreCase) so only paths under that directory (or the
directory itself) match; update the Any(...) predicate to perform these
normalizations and the separator-aware comparison.

Comment on lines +34 to 53
catch (InvalidOperationException ex)
{
Log.Error(ex, "Unhandled exception in async initialization of {Caller}", callerName);
Log.Error(ex, "Invalid operation in async initialization of {Caller}", callerName);
}
catch (UnauthorizedAccessException ex)
{
Log.Error(ex, "Access denied in async initialization of {Caller}", callerName);
}
catch (System.IO.IOException ex)
{
Log.Error(ex, "I/O error in async initialization of {Caller}", callerName);
}
catch (System.Net.Http.HttpRequestException ex)
{
Log.Error(ex, "Network error in async initialization of {Caller}", callerName);
}
catch (TimeoutException ex)
{
Log.Error(ex, "Timeout in async initialization of {Caller}", callerName);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unhandled exception gap reintroduced in InitializeAsync

Line 34 onward narrows catches, but without a final fallback, async void can crash the app for unexpected exceptions. This breaks the safety guarantee documented for InitializeAsync.

Suggested patch
         catch (TimeoutException ex)
         {
             Log.Error(ex, "Timeout in async initialization of {Caller}", callerName);
         }
+        catch (Exception ex)
+        {
+            Log.Error(ex, "Unexpected error in async initialization of {Caller}", callerName);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
catch (InvalidOperationException ex)
{
Log.Error(ex, "Unhandled exception in async initialization of {Caller}", callerName);
Log.Error(ex, "Invalid operation in async initialization of {Caller}", callerName);
}
catch (UnauthorizedAccessException ex)
{
Log.Error(ex, "Access denied in async initialization of {Caller}", callerName);
}
catch (System.IO.IOException ex)
{
Log.Error(ex, "I/O error in async initialization of {Caller}", callerName);
}
catch (System.Net.Http.HttpRequestException ex)
{
Log.Error(ex, "Network error in async initialization of {Caller}", callerName);
}
catch (TimeoutException ex)
{
Log.Error(ex, "Timeout in async initialization of {Caller}", callerName);
}
catch (InvalidOperationException ex)
{
Log.Error(ex, "Invalid operation in async initialization of {Caller}", callerName);
}
catch (UnauthorizedAccessException ex)
{
Log.Error(ex, "Access denied in async initialization of {Caller}", callerName);
}
catch (System.IO.IOException ex)
{
Log.Error(ex, "I/O error in async initialization of {Caller}", callerName);
}
catch (System.Net.Http.HttpRequestException ex)
{
Log.Error(ex, "Network error in async initialization of {Caller}", callerName);
}
catch (TimeoutException ex)
{
Log.Error(ex, "Timeout in async initialization of {Caller}", callerName);
}
catch (Exception ex)
{
Log.Error(ex, "Unexpected error in async initialization of {Caller}", callerName);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/ViewModels/ViewModelBase.cs` around lines 34 - 53, The
narrow exception handlers in ViewModelBase.InitializeAsync leave unhandled
exceptions from its async void path; add a final catch (Exception ex) at the end
of the try/catch chain inside InitializeAsync to log the unexpected exception
(using Log.Error with context including callerName) and swallow or handle it to
preserve the documented safety guarantee for async void initialization; ensure
the new catch comes after the existing specific catches in the InitializeAsync
method of ViewModelBase so no unexpected exception can escape.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 65.85366% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
SysManager/SysManager/ViewModels/ViewModelBase.cs 0.00% 9 Missing ⚠️
...sManager/SysManager/Services/UninstallerService.cs 0.00% 3 Missing ⚠️
SysManager/SysManager/Services/UpdateService.cs 0.00% 1 Missing ⚠️
...r/SysManager/ViewModels/ProcessManagerViewModel.cs 66.66% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@laurentiu021
laurentiu021 merged commit 3835062 into main May 18, 2026
5 checks passed
@laurentiu021
laurentiu021 deleted the fix/codeql-source-alerts branch May 18, 2026 13:41
laurentiu021 added a commit that referenced this pull request May 22, 2026
## Summary

**Batch 8** of the QA bug fix series.

### Issue #408 — Update download no SHA256 verification
Added \VerifyHashAsync\ method to \UpdateService\:
- Downloads the \.sha256\ file from the same GitHub release
- Computes SHA256 of the local downloaded file
- Compares and returns \(Verified, ExpectedHash, ActualHash)\
- Best-effort: if \.sha256\ file is unavailable (network error), returns
verified=true to not block install
- Logs hash match/mismatch via Serilog

### Issue #409 — Ookla CLI no hash verification
Added integrity verification to \SpeedTestService.EnsureOoklaAsync\:
- Computes SHA256 of downloaded zip and logs it for audit trail
- Validates the zip is not corrupt (\ZipFile.OpenRead\)
- Verifies the zip contains \speedtest.exe\
- Rejects corrupt/tampered downloads with descriptive error

### Testing
- Build: 0 errors

Closes #408, Closes #409

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
laurentiu021 added a commit that referenced this pull request May 22, 2026
…te call (#301, #300, #299, #298, #295, #290) (#428)

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
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.

2 participants