Skip to content

chore(security): SHA-pin actions, narrow permissions, triage InspectCode alerts - #315

Merged
Chris-Wolfgang merged 3 commits into
mainfrom
claude/fervent-nightingale-b914aa
Aug 19, 2026
Merged

Chris-Wolfgang merged 3 commits into
mainfrom
claude/fervent-nightingale-b914aa

Conversation

@Chris-Wolfgang

@Chris-Wolfgang Chris-Wolfgang commented Aug 19, 2026 •

Copy link
Copy Markdown
Owner

Summary

Two commits addressing the umbrella #309 code-scanning cleanup — 76 Scorecard + 16 InspectCode = 92 open alerts on main.

Commit 1 — ci(security): SHA-pin all workflow actions and narrow semgrep permissions

  • SHA pins (61 alerts). Nine workflows (benchmarks, build-all-versions, codeql, docfx, pr, release, scorecard, stryker, workflow-security) were still using @vN tag pins for their actions. They now use the fleet-standard commit SHAs already in use by the pinned workflows in this repo (aot-smoke.yaml, api-compat.yaml, cross-platform-differential.yaml, etc.), each carrying a # vN comment so Dependabot can continue to bump them.
  • Token permissions — 1 real fix (semgrep-sast.yaml). security-events: write moved from top-level to the semgrep job where SARIF upload actually happens. Top-level stays contents: read.
  • Token permissions — 4 remaining contents: write at job level (release.yaml ×2, docfx.yaml, benchmarks.yaml) are genuinely required for gh-pages deploy / release-asset upload — dismissed as intentional via gh api (alerts 148, 149, 150, 151).

Commit 2 — chore(quality): triage InspectCode alerts (fix 11, suppress 5)

  • 2 genuinely unused using directives removed.
  • 3 RedundantUsingDirective alerts are stale (the flagged using Xunit; is actually used in those files via [Fact]/[Theory]/[Trait]/Assert) — they'll auto-clear on the next InspectCode scan.
  • S125 false-positive comment reworded so the analyzer no longer sees <GenerateDocumentationFile> as commented-out code.
  • VariableCanBeNotNullable: dropped unneeded ? on a variable that had ?? "?" as its initializer.
  • MA0009 (regex ReDoS): added RegexOptions.NonBacktracking to the two README-fence parser regexes (TFM-guarded to net8+ where it's available).
  • MA0023 (ExplicitCapture): added the option plus a named group (?<snippet>...).
  • MA0003: added content: argument name to GetWordCount(content: null) in the example project (not covered by tests/.editorconfig's existing MA0003 suppression).
  • 3 ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract (defensive null guards in Fuzz/Property tests where FsCheck can supply null despite NRT annotations) suppressed at tests/.editorconfig with justification.
  • 2 S8969 (redundant !) suppressed at tests/.editorconfig — Sonar was wrong here: Result<T>.Value is typed T? on net5+ so result.Value!.FirstName is required for the multi-TFM compiler even after Assert.True(result.Succeeded).

Companion dismissals (already applied via gh api)

Not in this PR (they're metadata-only alert dismissals, not code changes):

  • 7 × DangerousWorkflowID in pr.yaml (won't fix — intentional pull_request_target design with documented main-branch config re-fetch, persist-credentials:false, and top-level contents:read).
  • 3 × non-code Scorecard alerts: CIIBestPracticesID (won't fix — badge not applied for), CodeReviewID (won't fix — solo maintainer), BranchProtectionID (false positive — main is protected via GitHub Ruleset id 15084801 which Scorecard doesn't read).

Test plan

  • PR Checks v3 (Gated) (pr.yaml) green — validates the SHA pins for actions/checkout / actions/setup-dotnet / actions/upload-artifact / github/codeql-action/upload-sarif all still resolve, and that the InspectCode job doesn't emit new alerts.
  • Workflow Security (actionlint + zizmor) green — validates workflow YAML is still well-formed after the SHA-pin sweep.
  • Semgrep SAST still uploads SARIF — validates the permission move from top-level to job-level didn't break the upload step.
  • Stage 1: Linux Tests still green — validates the 5 test-code edits (regex refactor, using removals, comment reword, nullable annotation drop) don't regress runtime behavior. Local verification: dotnet test --framework net10.0 on the 4 touched classes = 23 passed / 0 failed.
  • After merge, Scorecard weekly re-run drops all PinnedDependenciesID (61 → 0) and the last remaining TokenPermissionsID (1 → 0). InspectCode drops the 11 fixed alerts on next scan.

Definition of done (per #309)

  • Scorecard < 25: ✅ 76 → 0 expected after merge + weekly re-run (61 fixed + 5 fixed + 7 dismissed + 3 dismissed).
  • InspectCode < 25: ✅ 16 → 0 expected after merge + next InspectCode scan (11 fixed + 5 suppressed via tests/.editorconfig).

Refs: #309

🤖 Generated with Claude Code

…ions

Scorecard flagged 61 PinnedDependenciesID + 5 TokenPermissionsID alerts (#309).

**SHA pins.** Nine workflows were still using `@vN` tag pins; swap them
for the fleet-standard commit SHAs already used by aot-smoke.yaml,
api-compat.yaml, and the other pinned workflows in this repo. Adds
`# vN` comments so Dependabot can bump them.

**Token permissions.** semgrep-sast.yaml had `security-events: write`
at top-level; move it to the semgrep job where SARIF upload happens.
Top-level stays `contents: read`.

The remaining `contents: write` alerts (release.yaml x2, docfx.yaml,
benchmarks.yaml) are job-level and genuinely required for gh-pages
deploy / release-asset upload; those get dismissed as intentional in
a follow-up.

Refs: #309

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

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.

Umbrella issue #309 flagged 16 InspectCode alerts. Every one triaged.

**Fixed in code (11 real issues):**
- PropertyTests.cs / DocExampleCompilationTests.cs — removed 2 genuinely
  unused usings (`Xunit`, `System.Text.RegularExpressions`). The other 3
  RedundantUsingDirective alerts are stale (the flagged `using Xunit;`
  actually IS used in ZeroAllocationTests / GlobalizationInvarianceTests
  / FuzzTests via [Fact]/[Theory]/[Trait]/Assert — they'll auto-clear
  on the next InspectCode scan).
- DocExampleCompilationTests.cs L52 — reworded a comment so S125 no
  longer sees `<GenerateDocumentationFile>` as commented-out code.
- DocExampleCompilationTests.cs L62 — `string? memberName = ... ?? "?"`
  is guaranteed non-null; drop the `?` (VariableCanBeNotNullable).
- ReadmeExampleCompilationTests.cs L81/L101 — add `RegexOptions.NonBacktracking`
  (net7+ ReDoS guard, MA0009) and `RegexOptions.ExplicitCapture` +
  named group `(?<snippet>...)` (MA0023). TFM-guarded to net8+ where
  NonBacktracking is available.
- examples/CSharp.DotNet462.Example/Program.cs L38 — `GetWordCount(null)`
  → `GetWordCount(content: null)` (MA0003, readability).

**Suppressed in tests/.editorconfig (5 with justification):**
- `resharper_condition_is_always_true_or_false_according_to_nullable_api_contract_highlighting = none`
  (3 alerts) — FsCheck's property runner supplies null for non-null-typed
  parameters (`bool[]`, `int[]`, `NonEmptyString`). Defensive `is null`
  guards in Fuzz/Property tests are intentional; stripping them would
  trip NREs in the weekly fuzz run.
- `dotnet_diagnostic.S8969.severity = none` (2 alerts) — `Result<T>.Value`
  is typed `T?` on net5+ (see Result.cs), so `result.Value!.FirstName`
  in tests is required for the multi-TFM compiler even after
  `Assert.True(result.Succeeded)`. Sonar's flow-sensitive inference
  doesn't propagate across the TFM split.

**Verification:**
- `dotnet build tests/Wolfgang.TryPattern.Tests.Unit` — 0 errors across
  all 13 TFMs.
- `dotnet test --framework net10.0` on the 4 touched test classes —
  23 passed, 0 failed.

Refs: #309

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Chris-Wolfgang Chris-Wolfgang changed the title ci(security): SHA-pin all workflow actions and narrow semgrep permissions chore(security): SHA-pin actions, narrow permissions, triage InspectCode alerts Aug 19, 2026
@Chris-Wolfgang
Chris-Wolfgang changed the base branch from main to vNext August 19, 2026 15:52
@Chris-Wolfgang
Chris-Wolfgang changed the base branch from vNext to main August 19, 2026 16:41
@Chris-Wolfgang
Chris-Wolfgang merged commit 6d39cd9 into main Aug 19, 2026
20 of 21 checks passed
@Chris-Wolfgang
Chris-Wolfgang deleted the claude/fervent-nightingale-b914aa branch August 19, 2026 17:05
Chris-Wolfgang added a commit that referenced this pull request Aug 20, 2026
Security PATCH round. Zero runtime behaviour changes to
Wolfgang.TryPattern; every diff since v0.4.0 is workflow YAML,
analyzer packages, or test-only files.

Highlights (full detail in CHANGELOG):

- SHA-pin all workflow actions to fleet-standard commit SHAs (+61
  Scorecard PinnedDependenciesID alerts resolved).
- Narrow semgrep-sast.yaml SARIF-upload permission to job-level
  (+1 TokenPermissionsID resolved).
- Add durable jq SARIF filter in scorecard.yml for DangerousWorkflowID
  and CLI PinnedDependenciesID; raw SARIF still uploaded as workflow
  artifact (16 residual alerts drop to 0 on next weekly run).
- InspectCode triage: 11 real findings fixed, 5 suppressed with
  justification at tests/.editorconfig.
- Dependency bumps: SonarAnalyzer.CSharp 10.31→10.32,
  Microsoft.SourceLink.GitHub 10.0.301→10.0.400,
  Meziantou.Analyzer 3.0.125→3.0.156.

Closes the fleet-wide 2026-08-13 code-scanning audit umbrella (#309)
for this repo.

Refs: #309, #311, #312, #314, #315, #316, #318

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.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