Skip to content

chore: buildless CodeQL and genuine fixes for the dismissed alerts (Standards §4.4) - #33

Merged
StuartMeeks merged 1 commit into
mainfrom
chore/codeql-buildless-and-genuine-fixes
Aug 22, 2026
Merged

chore: buildless CodeQL and genuine fixes for the dismissed alerts (Standards §4.4)#33
StuartMeeks merged 1 commit into
mainfrom
chore/codeql-buildless-and-genuine-fixes

Conversation

@StuartMeeks

Copy link
Copy Markdown
Owner

Adopts the new §4.4 (build-mode: none) and replaces every alert dismissal made earlier with a real code change.

§4.4 / §3.0.1 — buildless analysis

GitHub applies paths-ignore to a compiled language only when it is analysed without a build. Under the explicit dotnet build this workflow used to run, the mandated **/obj/** exclusion was silently inert — which is exactly why the xUnit auto-generated entry point was flagged despite being excluded. build-mode: none makes the exclusion take effect, and buildless extraction reads source across every TFM at once, which is what the explicit build existed to guarantee. Setup .NET / Restore / Build steps removed.

This genuinely resolves the two cs/missed-ternary-operator alerts rather than dismissing them as generated-code noise.

Alerts: dismissals → fixes

Rule Was Now
cs/catch-of-all-exceptions (19) dismissed "won't fix" each catch narrowed to what its operation can produce
cs/local-not-disposed (3) dismissed "false positive" fixture owns and disposes the consoles
cs/missed-ternary-operator (2) dismissed "generated" excluded for real by build-mode: none
cs/useless-upcast (1) dismissed "won't fix" typed locals, no upcast expression

The catches

  • filesystem best-effort → IOException, UnauthorizedAccessException
  • cache file → adds JsonException
  • archive extraction → adds InvalidDataException, NotSupportedException
  • HTTP sources / checker → HttpRequestException, JsonException, IOException, OperationCanceledException
  • gh source → GhProcessException in place of the HTTP pair
  • process kill → InvalidOperationException, Win32Exception, NotSupportedException
  • UpdateCheckCommand → now identical to UpdateCommand's existing when (ex is not OperationCanceledException). A command boundary should turn any failure into a message and an exit code; the fix was that it swallowed Ctrl-C too. CodeQL already accepted this pattern on the sibling command.

The two UpdateInstaller catches that catch broadly and rethrow are unchanged — they roll back state rather than swallow, and CodeQL correctly never flagged them.

This is a deliberate behaviour change

A defect anywhere in the update path used to be reported as "no update available", "already up to date", or nothing at all, and could persist indefinitely. It now surfaces.

Narrowing immediately proved the point by breaking two tests that encoded the old contract. GetLatestAsync_when_runner_throws_returns_null threw InvalidOperationException — something the real gh transport never produces, since GhProcess wraps every real failure in GhProcessException. It now throws GhProcessException, and a new companion test asserts that an unexpected exception propagates instead of being reported as "no release available".

Verification

Release build: 0 warnings, 0 errors. dotnet test --configuration Release: 410 passed, 0 failed (205 × net8.0/net10.0), up from 408.

CHANGELOG entries land under the unpublished [1.0.0] section, whose date moves to 2026-08-22. No tag exists and nothing has been published, so these ship as part of 1.0.0 rather than needing a version of their own.

🤖 Generated with Claude Code

Adopts NextIteration.Standards §4.4 (build-mode: none) and replaces every
alert dismissal made earlier with a real code change.

§4.4 / §3.0.1 — codeql.yml now analyses C# buildless. GitHub applies
paths-ignore to a compiled language only when it is analysed without a build,
so the mandated **/obj/** exclusion was silently inert and the xUnit
auto-generated entry point was analysed and flagged anyway. build-mode: none
makes the exclusion effective and reads source across every TFM at once, so
the Setup .NET / Restore / Build steps are removed. This genuinely resolves
the two cs/missed-ternary-operator alerts rather than dismissing them.

cs/catch-of-all-exceptions (19) — each catch now takes only what its operation
can produce:
- filesystem best-effort: IOException, UnauthorizedAccessException
- cache file: + JsonException
- archive extraction: + InvalidDataException, NotSupportedException
- HTTP sources / checker: HttpRequestException, JsonException, IOException,
  OperationCanceledException
- gh source: GhProcessException in place of the HTTP pair
- process kill: InvalidOperationException, Win32Exception, NotSupportedException
- UpdateCheckCommand: now identical to UpdateCommand's already-accepted
  `when (ex is not OperationCanceledException)` — a command boundary still
  turns any failure into a message and exit code, but lets Ctrl-C through

The two UpdateInstaller catches that catch broadly and rethrow are unchanged:
they roll back state rather than swallow, and CodeQL does not flag them.

cs/local-not-disposed (3) — the command harnesses hand their TestConsole to
the caller, which reads console.Output after the harness returns, so it cannot
be disposed at the creation site. Each test class now implements IDisposable
and disposes every console it handed out at teardown.

cs/useless-upcast (1) — typed locals pin which UpdateCleanup.Run overload each
null-argument test targets, with no upcast expression at the call site.

Narrowing surfaced two tests that encoded the old swallow-everything contract.
GetLatestAsync_when_runner_throws_returns_null threw InvalidOperationException,
which the real gh transport never produces; it now throws GhProcessException
(what GhProcess actually wraps failures in) and a companion test asserts an
unexpected exception propagates instead of being reported as "no release".

This is a deliberate behaviour change: a defect that used to be masked as
"no update available" now surfaces.

Release build: 0 warnings. 410 tests (205 × net8.0/net10.0) pass, up from 408.
CHANGELOG entries land under the unpublished [1.0.0] section, whose date moves
to 2026-08-22; no tag exists and nothing has been published.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@StuartMeeks
StuartMeeks merged commit 94e7f94 into main Aug 22, 2026
9 checks passed
@StuartMeeks
StuartMeeks deleted the chore/codeql-buildless-and-genuine-fixes branch August 22, 2026 01:58
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.

1 participant