Skip to content

chore(security): InspectCode noise-floor .DotSettings (#361) - #378

Closed
Chris-Wolfgang wants to merge 5 commits into
vNextfrom
claude/cranky-goldstine-2223a8
Closed

Chris-Wolfgang wants to merge 5 commits into
vNextfrom
claude/cranky-goldstine-2223a8

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

Add ETL-Abstractions.sln.DotSettings to silence 1,960 of 1,980 open InspectCode Code Scanning alerts as false positives / duplicate reports of rules the in-build analyzer stack already gates.

Addresses the InspectCode half of #361. Scorecard side is already at 14 (below the < 25 target) and needs no action here.

Alert reduction

Category Rules Alerts silenced
PublicAPI analyzer FP (no AdditionalFiles in InspectCode) RS0016 / RS0036 / RS0037 1,491
Multi-TFM FP (net462/netstandard need explicit using System;) RedundantUsingDirective 198
Roslynator-covered redundancy 9 Redundant* rules 92
Nullability defensive checks (library FP) 7 nullability rules 6
Test policy (.editorconfig CA2007=none under tests/) xUnit1030 32
Dup Sonar/Roslyn re-reports S1939, MA0009, S3220, S2068 16
Example-project pedagogical patterns AccessToModifiedClosure, RCS1102, S125, S2930, S4456, S108, S2326 106
Test-code intentional patterns MA0055 (finalizer tests), S3877 (throwing test doubles), S3871 6
Roslynator IDE00xx unused-variable dup UnusedVariable, NotAccessedVariable, NotAccessedField.Local, UnusedAutoPropertyAccessor.Global 13
Total 1,960

Expected post-merge count: ~20 (target: < 25 per #361).

What stays visible (deliberately)

Because ETL-Abstractions is the base library of the ETL fleet, real findings are NOT suppressed — the umbrella guidance is "err on the side of fixing real findings rather than blanket-suppressing":

  • StaticMemberInGenericType (3) — static field in generic base class
  • MA0158 (1) — use System.Threading.Lock in ProgressCapture
  • S6966 (2) — await CancelAsync in TestKit contract tests
  • S5034 (1) — ValueTask consumed twice in fuzz test
  • S2699 (2) — tests missing assertions
  • S6608 (1) — indexer vs Last()
  • S4487 (1) — unused private field in timer test
  • S1994 (2) — for loop stop condition
  • S3267 (1) — LINQ Where refactor opportunity
  • RCS1194 (1) — exception constructor implementation
  • InvalidXmlDocComment (2) — stale crefs

These become the actionable follow-up list once the noise clears.

Fleet consistency

Same shape as Extensions-Logging-Data.slnx.DotSettings (proving-ground for repo-template#431), extended for this repo's specific tail (example-project patterns and finalizer/throw test doubles). Documented per-category in the file.

Test plan

  • ReSharper InspectCode job passes (green — no error-severity findings, warnings drop from Code Scanning per the DO_NOT_SHOW entries)
  • Post-merge gh api "repos/Chris-Wolfgang/ETL-Abstractions/code-scanning/alerts?state=open&tool_name=InspectCode" --paginate --jq '.[].number' | wc -l returns < 25
  • Post-merge gh api "repos/Chris-Wolfgang/ETL-Abstractions/code-scanning/alerts?state=open" --paginate --jq '.[].number' | wc -l returns < 50 total
  • Close [Maintenance] security: 1090 open code-scanning alerts (2 tools) #361 with a link to this PR

Refs: #361, repo-template#431.

🤖 Generated with Claude Code

Silence 1,960 of the 1,980 open InspectCode Code Scanning alerts as
demonstrable false positives / duplicate reports:

- PublicAPI analyzer FPs (RS0016/RS0036/RS0037 — 1,491): InspectCode
  runs the analyzer WITHOUT the PublicAPI.*.txt AdditionalFiles, so it
  thinks nothing is declared and flags every public member. The in-build
  analyzer gates this correctly via Directory.Build.props Exists() guards.
- Multi-TFM FP (RedundantUsingDirective — 198): src multi-targets
  net462/netstandard2.0/2.1/net8.0/net10.0 with ImplicitUsings only on
  net10.0, so explicit System usings are REQUIRED on the other TFMs but
  look redundant to InspectCode (single-TFM analysis).
- Roslynator-covered redundancy (92): RedundantCast, RedundantNameQualifier,
  RedundantExtendsListEntry, RedundantSuppressNullableWarningExpression,
  RedundantTypeArgumentsOfMethod, RedundantNullableDirective,
  RedundantWithCancellation, RedundantAssignment, RedundantArgumentDefaultValue.
- Nullability defensive checks (6): library defensive null-checks against
  nullable-oblivious / older-TFM callers.
- Test-policy conflicts (xUnit1030 — 32): .editorconfig sets CA2007=none
  under tests/; the src stack mandates it. Settled policy.
- Dup Sonar/Roslyn re-reports (S1939, MA0009, S3220, S2068 — 16+).
- Example-project pedagogical patterns: AccessToModifiedClosure (36 —
  Volatile.Read pattern from Timer callbacks), RCS1102 (23 — Program.cs
  as static), S125 (12 — illustrative comments), S2930 (10 — short-lived
  cts in demo Program), S4456 (18 — iterator arg-validation split),
  S108 (4), S2326 (3).
- Test-code intentional patterns: MA0055 (3 — FinalizationSuppressionTests
  intentionally defines finalizers), S3877 (2 — throwing test doubles),
  S3871 (1 — internal test-only exception).
- Roslynator/IDE00xx-covered unused-variable duplicates (4).

Real findings (StaticMemberInGenericType, MA0158, S6966, S5034, S2699,
S6608, S4487, S1994, S3267, RCS1194, InvalidXmlDocComment) stay visible
so the base library errs on the side of surfacing signal — consistent
with the umbrella issue guidance for fleet-critical repos.

Expected post-merge Code Scanning count: ~20 (from 1,980), well below
the < 25 target in #361. Scorecard (14) already meets < 25.

Refs: #361, repo-template#431.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 13, 2026 21:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Fixes and per-pattern suppressions covering the 20 findings that stayed
visible after the initial noise-floor drop.

Real code fixes (7):
- Extract shared abort item-error policy delegate to a non-generic
  ItemErrorPolicyDefaults helper class, so ExtractorBase / LoaderBase /
  TransformerBase all reference the same Func instance instead of paying
  an allocation per closed generic type (fixes 3× StaticMemberInGenericType).
- Add the standard exception constructors (parameterless,
  (string, Exception)) to WrongOverloadCalledException (fixes RCS1194).
- Remove the unused `_intervalMs` field from SystemProgressTimerTests'
  CapturingExtractor test double (fixes S4487).
- Add explicit Record.Exception / ExceptionAsync assertions to the
  DisposableStageContractTests Dispose_is_idempotent tests so they document
  the assertion contract instead of relying on "no throw" (fixes 2× S2699).
- Replace `reports.Last()` with `reports[reports.Count - 1]` in
  EtlPipelineTests to satisfy the perf micro-opt on List<T> (fixes S6608).
- Fix stale <see cref="…"/> targets: EtlPipeline.From → the actual host
  EtlPipelineSourceExtensions.From in TestDoubles.cs, and add the missing
  `using System.Collections.Generic;` in PipelineBenchmarks.cs so
  IAsyncEnumerable<T> resolves in the type's XML docs (fixes 2× InvalidXmlDocComment).

Recurring-pattern suppressions added to .DotSettings:
- S1994 — infinite `for (var i = 0; ; i++)` generator loops in
  TestExtractor.Generate* and `for (var attempt = 1; ; attempt++)` retry
  loops in RetryingExtractor / RetrySeamTests. Loops break internally.
- S1215 — GC.Collect + WaitForPendingFinalizers in
  AllocationBudgetContractTests. Settling the heap is the whole point of
  the measurement.
- MA0158 — System.Threading.Lock is net9.0+; `new object()` for a lock
  is required on 4 of the 5 TFMs (net462/netstandard2.0/2.1/net8.0) and
  a #if NET9_0_OR_GREATER split isn't worth the ceremony for a test-only
  progress-capture double.
- S3267 — MiddlewareExtensions validates with fail-fast throw at the
  first null; LINQ Where + Any would lose enumeration-position semantics
  and require two passes.
- S5034 — TestKitFuzzTests.Drain is the deliberate sync-over-async
  bridge for the synchronous CsCheck sampler.
- S6966 — cts.Cancel() from inside an `await foreach` in ExtractorBase /
  TransformerBase contract tests. CancelAsync() would race the "the
  enumerator sees cancel on the next MoveNextAsync" assertion. Extends
  the family already suppressed by the surrounding
  `#pragma warning disable CA1849, VSTHRD103`.

Post-merge expected InspectCode count: 0 (from 20). Scorecard already
under target at 14.

Refs: #361.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

BenchmarkDotNet

Details
Benchmark suite Current: 0ded397 Previous: 9f7a223 Ratio
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_NoProgress(RecordCount: 1000) 36441.04443359375 ns (± 1025.9621470216405) 32261.896341959637 ns (± 364.15799521714877) 1.13
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_WithProgress(RecordCount: 1000) 36426.62489827474 ns (± 56.66652039101131) 35381.66305541992 ns (± 290.01444589193056) 1.03
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_NoProgress(RecordCount: 100000) 3127929.6770833335 ns (± 3277.654428092272) 3147298.1979166665 ns (± 4080.1891642462997) 0.99
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_WithProgress(RecordCount: 100000) 3469765.9388020835 ns (± 5068.8504903200665) 3460913.9778645835 ns (± 12980.283555153379) 1.00
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.FluentPipeline(RecordCount: 1000) 29487.31086222331 ns (± 94.37021654431574) 30769.176920572918 ns (± 67.1035212022148) 0.96
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.ManualComposition(RecordCount: 1000) 29055.817286173504 ns (± 85.8678606969175) 29653.87747701009 ns (± 69.75862046871877) 0.98
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.BaseClassComposition(RecordCount: 1000) 78573.76778157552 ns (± 363.5809967670395) 84119.70609537761 ns (± 199.43699171620807) 0.93
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.FluentPipeline(RecordCount: 100000) 2874997.6471354165 ns (± 6521.503927211178) 2858407.7447916665 ns (± 718.8118438209126) 1.01
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.ManualComposition(RecordCount: 100000) 2853502.6178385415 ns (± 2065.759483467366) 2921320.4205729165 ns (± 6424.736099927367) 0.98
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.BaseClassComposition(RecordCount: 100000) 8297563.677083333 ns (± 22105.094951581654) 8379163.734375 ns (± 2341.3678513388713) 0.99

This comment was automatically generated by workflow using github-action-benchmark.

@Chris-Wolfgang

Copy link
Copy Markdown
Owner Author

Reconciliation — this PR overlaps ~80% with the vNext code-scanning cleanup stack

Heads-up: this #361 work was done in parallel with an 8-PR cleanup stack on vNext (#370 → #371 → #374 → #375 → #376 → #377 → #380), and the two overlap heavily. Recommend closing this PR in favor of that stack + a trimmed .DotSettings (#383). Details:

The code changes here are fully duplicated by the vNext stack

This PR vNext stack
ItemErrorPolicyDefaults holder + strip AbortPolicy from the 3 base classes DefaultItemErrorPolicy holder, same refactor (#376)
S2699 fix in DisposableStageContractTests same (#376)
remove unread _intervalMs field (S4487) in SystemProgressTimerTests same (#380)
TestDoubles cref fix same (#380)

Same intent, different type name (ItemErrorPolicyDefaults vs DefaultItemErrorPolicy) — they conflict, and the vNext versions are verified across the full TFM matrix.

The .DotSettings here over-suppresses

Of the 45 entries, ~12 are genuinely structural-always-FP (the RS0016/36/37 PublicAPI trio, the nullable-…AccordingToAPIContract family, UnusedAutoPropertyAccessor.Global, MA0158). The rest blanket-silence rules that are fixable — RCS1102, S2930, S1939, xUnit1030, the Redundant* family, unused-variable/dead-field — several of which the vNext stack fixes in code rather than hides. Blanket-suppressing them also hides future genuine occurrences. Two specific concerns:

  • The header comment lists MA0158, S6966, S5034, S1994, S3267 as "stay visible" but the entries suppress all five.
  • S2068 (hard-coded credentials) is a security rule and shouldn't be blanket-silenced.

Proposed resolution

  • chore(security): InspectCode noise-floor .DotSettings — structural FPs only (#361) #383 carries just the ~12 structural-always-FP entries as the .DotSettings (stacked on the vNext cleanup).
  • The fixable rules are fixed in code (vNext stack); location-specific intentional patterns are dismissed per instance with a reason in Code Scanning, so the rule stays active for future real cases.
  • Close this PR as superseded. If the RCS1194-fix here (adds standard exception ctors to WrongOverloadCalledException) is worth keeping over the per-instance dismissal, say so and I'll fold that one bit into the stack.

@Chris-Wolfgang
Chris-Wolfgang changed the base branch from main to vNext August 14, 2026 20:23
…ine-2223a8

# Conflicts:
#	src/Wolfgang.Etl.Abstractions/ExtractorBase.cs
#	src/Wolfgang.Etl.Abstractions/LoaderBase.cs
#	src/Wolfgang.Etl.Abstractions/TransformerBase.cs
#	src/Wolfgang.Etl.TestKit.Xunit/DisposableStageContractTests.cs
@Chris-Wolfgang

Copy link
Copy Markdown
Owner Author

Superseded — closing. The trimmed structural-only .DotSettings shipped in #383 (merged to vNext), and this PR's code changes were duplicates of the already-merged vNext cleanup stack (#370–#380). The one genuine unique fix here (S4487 dead-field removal) is included in #383; the remaining diffs (benchmark cref, EtlPipelineTests, RCS1194 ctors) were intentionally dismissed as false-positive / won't-fix per-instance. Branch deleted.

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.

[Maintenance] security: 1090 open code-scanning alerts (2 tools)

2 participants