From 6527bd7c87840a7080031f8e242cb97178ae329b Mon Sep 17 00:00:00 2001 From: Chris Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> Date: Sat, 9 May 2026 14:14:51 -0400 Subject: [PATCH 1/2] pr.yaml: write protected config files as UTF-8 without BOM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of repo-template PR #339. The 'Fetch trusted configuration files from main branch' step writes .editorconfig / Directory.Build.props / BannedSymbols.txt back via 'Out-File -Encoding UTF8' which writes UTF-8 *with* BOM. The .NET analyzer engine appears to ignore .editorconfig files prefixed by a BOM, so project-level severity overrides don't apply on CI even though they apply locally — analyzers fire at default severity and TreatWarningsAsErrors then escalates them to errors. Switch to 'Out-File -Encoding UTF8NoBOM' (PS 6+; the runner uses pwsh). Diagnosed against Chris-Wolfgang/In-memory-Logger PR #32 / run 24996715587. See Chris-Wolfgang/repo-template#339 for the full write-up. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/pr.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index e19b28cf..70ee71d7 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -636,7 +636,7 @@ jobs: $exists = git cat-file -e "main-branch:$configFile" 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host " ✓ Copying $configFile from main branch" - git show "main-branch:$configFile" | Out-File -FilePath $configFile -Encoding UTF8 -NoNewline + git show "main-branch:$configFile" | Out-File -FilePath $configFile -Encoding UTF8NoBOM -NoNewline } else { Write-Host " ℹ️ $configFile not found in main branch, skipping" } @@ -651,7 +651,7 @@ jobs: Write-Host " ✓ Copying $file from main branch" $dir = Split-Path -Parent $file if ($dir) { New-Item -ItemType Directory -Force -Path $dir | Out-Null } - git show "main-branch:$file" | Out-File -FilePath $file -Encoding UTF8 -NoNewline + git show "main-branch:$file" | Out-File -FilePath $file -Encoding UTF8NoBOM -NoNewline } } } @@ -681,7 +681,7 @@ jobs: $exists = git cat-file -e "main-branch:$configFile" 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host " ✓ Copying $configFile from main branch" - git show "main-branch:$configFile" | Out-File -FilePath $configFile -Encoding UTF8 -NoNewline + git show "main-branch:$configFile" | Out-File -FilePath $configFile -Encoding UTF8NoBOM -NoNewline } else { Write-Host " ℹ️ $configFile not found in main branch, skipping" } @@ -696,7 +696,7 @@ jobs: Write-Host " ✓ Copying $file from main branch" $dir = Split-Path -Parent $file if ($dir) { New-Item -ItemType Directory -Force -Path $dir | Out-Null } - git show "main-branch:$file" | Out-File -FilePath $file -Encoding UTF8 -NoNewline + git show "main-branch:$file" | Out-File -FilePath $file -Encoding UTF8NoBOM -NoNewline } } } From a047f7f31efcad9952294ec4d8bb863a70e9379c Mon Sep 17 00:00:00 2001 From: Chris Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> Date: Mon, 11 May 2026 21:57:23 -0400 Subject: [PATCH 2/2] Dedupe Stage 2 fetch-trusted-config step and add Dependabot guard The Windows test job had two identical "Fetch trusted configuration files from main branch" steps back-to-back, neither of which carried the `github.event.pull_request.user.login != 'dependabot[bot]'` condition that every other job in this workflow uses. - Removes the duplicate copy so the step runs once per job. - Adds the same Dependabot guard so analyzer/config-file bumps from Dependabot can actually flow through (otherwise main's protected files unconditionally overwrite the Dependabot diff and the bump silently no-ops on the Windows leg). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/pr.yaml | 46 +-------------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 70ee71d7..6c4781f4 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -616,51 +616,7 @@ jobs: - name: Fetch trusted configuration files from main branch shell: pwsh - run: | - Write-Host "Fetching configuration files from main branch to prevent malicious overrides..." - - # Fetch the main branch - git fetch origin main:main-branch - - # List of configuration files that should come from trusted main branch - $configFiles = @( - ".editorconfig", - "Directory.Build.props", - "Directory.Build.targets", - "BannedSymbols.txt" - ) - - # Copy each configuration file from main branch if it exists - foreach ($configFile in $configFiles) { - # Check if file exists in main branch - $exists = git cat-file -e "main-branch:$configFile" 2>&1 - if ($LASTEXITCODE -eq 0) { - Write-Host " ✓ Copying $configFile from main branch" - git show "main-branch:$configFile" | Out-File -FilePath $configFile -Encoding UTF8NoBOM -NoNewline - } else { - Write-Host " ℹ️ $configFile not found in main branch, skipping" - } - } - - # Handle glob patterns for .globalconfig, .ruleset, and workflow files - $globPatterns = @("*.globalconfig", "*.ruleset", ".github/workflows/*.yml", ".github/workflows/*.yaml") - foreach ($pattern in $globPatterns) { - $files = git ls-tree -r --name-only main-branch | Select-String -Pattern $pattern.Replace("*", ".*") - foreach ($file in $files) { - if ($file) { - Write-Host " ✓ Copying $file from main branch" - $dir = Split-Path -Parent $file - if ($dir) { New-Item -ItemType Directory -Force -Path $dir | Out-Null } - git show "main-branch:$file" | Out-File -FilePath $file -Encoding UTF8NoBOM -NoNewline - } - } - } - - Write-Host "" - Write-Host "✅ Configuration files secured - using versions from main branch" - - - name: Fetch trusted configuration files from main branch - shell: pwsh + if: github.event.pull_request.user.login != 'dependabot[bot]' run: | Write-Host "Fetching configuration files from main branch to prevent malicious overrides..."