Skip to content

feat(build): enforce strict warnings across all linters#392

Open
WilliamBerryiii wants to merge 7 commits intomainfrom
feature/enforce-strict-warnings
Open

feat(build): enforce strict warnings across all linters#392
WilliamBerryiii wants to merge 7 commits intomainfrom
feature/enforce-strict-warnings

Conversation

@WilliamBerryiii
Copy link
Copy Markdown
Member

@WilliamBerryiii WilliamBerryiii commented Apr 5, 2026

This PR established a warnings-as-errors policy across all CI linters and fixed a critical bug where Pester test failures were silently masked in CI. ShellCheck was added as a new linter with full CI integration, YamlLint was promoted to strict mode, and all remaining soft-fail linter jobs were switched to hard-fail.

Closes #6

Description

Critical Bug Fix

The Pester test workflow contained a $global:LASTEXITCODE = 0 reset that silently swallowed all test failures, allowing broken builds to pass CI. This was removed and replaced with explicit exit 1 calls when Pester reports failures or throws exceptions. Two test files also had stale dot-source paths referencing the scripts/lib/ symlink target instead of the canonical shared/lib/ location — these were corrected.

ShellCheck Integration

A complete ShellCheck linting pipeline was added to the repository:

  • Added .shellcheckrc at the repository root with shell=bash, severity=warning, and external-sources=true
  • Added a reusable GitHub Actions workflow (shellcheck.yml) that installs ShellCheck, runs the wrapper, and uploads results as a CI artifact
  • Added Invoke-ShellCheck.ps1 (218 lines), a PowerShell wrapper that discovers .sh files, runs ShellCheck with JSON output, classifies findings, writes structured results to logs/, and emits CI annotations — treating warnings as failures
  • Added Invoke-ShellCheck.Tests.ps1 (334 lines) with 10 Pester test contexts covering tool availability, changed-files-only mode, error/warning classification, JSON export structure, and directory exclusion
  • Integrated ShellCheck into both main.yml and pr-validation.yml workflows with soft-fail: false

YamlLint Strict Mode

Invoke-YamlLint.ps1 was updated to treat warnings as failures by broadening the failure condition to include $warningCount -gt 0. The corresponding Pester tests in Invoke-YamlLint.Tests.ps1 were updated to reflect strict mode expectations.

Soft-Fail Policy

Linting jobs enforce strict failures (soft-fail: false):

Job main.yml pr-validation.yml
Terraform Validation soft-fail: false soft-fail: false
Go Lint soft-fail: false soft-fail: false
ShellCheck soft-fail: false soft-fail: false

Test and documentation jobs remain advisory (soft-fail: true) to avoid blocking PRs on infrastructure test flakiness or non-critical doc checks:

Job main.yml pr-validation.yml
Terraform Tests soft-fail: true soft-fail: true
Go Tests soft-fail: true soft-fail: true
Terraform Docs Check soft-fail: true soft-fail: true

Documentation and Tooling

  • CONTRIBUTING.md gained a Warning Policy table documenting enforcement levels for all CI linters
  • package.json added lint:sh and lint:py scripts and updated lint:all to include them

Type of Change

  • 🐛 Bug fix (non-breaking change fixing an issue)
  • ✨ New feature (non-breaking change adding functionality)
  • 💥 Breaking change (fix or feature causing existing functionality to change)
  • 📚 Documentation update
  • 🏗️ Infrastructure change (Terraform/IaC)
  • ♻️ Refactoring (no functional changes)

Component(s) Affected

  • infrastructure/terraform/prerequisites/ - Azure subscription setup
  • infrastructure/terraform/ - Terraform infrastructure
  • infrastructure/setup/ - OSMO control plane / Helm
  • workflows/ - Training and evaluation workflows
  • training/ - Training pipelines and scripts
  • docs/ - Documentation

Testing Performed

  • 1021 Pester tests passed, 0 failed, 17 not run (Integration/Slow tags)
  • ShellCheck wrapper validated with 10 new test contexts (28 assertions)
  • YamlLint strict mode validated with updated test expectations (40 assertions)

Documentation Impact

  • No documentation changes needed
  • Documentation updated in this PR
  • Documentation issue filed

Bug Fix Checklist

  • Linked to issue being fixed
  • Regression test included

Checklist

- add ShellCheck CI workflow, PowerShell wrapper, and .shellcheckrc config
- promote YamlLint warnings to failures for strict warnings compliance
- add ShellCheck and YamlLint Pester unit tests with strict mode coverage
- integrate ShellCheck into pr-validation and main workflows
- update CONTRIBUTING.md warning policy table and package.json scripts

Closes #6

🔧 - Generated by Copilot
…e paths

- remove LASTEXITCODE reset that silently masked all test failures in CI
- add explicit exit 1 when Pester reports failed tests
- fix test dot-source paths from broken scripts/lib symlinks to shared/lib

🐛 - Generated by Copilot
@WilliamBerryiii WilliamBerryiii requested a review from a team as a code owner April 5, 2026 01:16
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 5, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 7d55df1.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout de0fac2e4500dabe0009e67214ff5f5447ce83dd 🟢 6
Details
CheckScoreReason
Maintained⚠️ 23 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Packaging⚠️ -1packaging workflow not detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 6branch protection is not maximal on development and all release branches
SAST🟢 8SAST tool detected but not run on all commits
actions/actions/upload-artifact bbbca2ddaa5d8feaa63e36b76fdaad77386f024f 🟢 5.7
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 54 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits

Scanned Files

  • .github/workflows/shellcheck.yml

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 5, 2026

Codecov Report

❌ Patch coverage is 93.96552% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.86%. Comparing base (c88d253) to head (7d55df1).

Files with missing lines Patch % Lines
scripts/linting/Invoke-ShellCheck.ps1 93.80% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #392      +/-   ##
==========================================
+ Coverage   50.48%   50.86%   +0.38%     
==========================================
  Files         267      268       +1     
  Lines       18188    18302     +114     
  Branches     1855     1903      +48     
==========================================
+ Hits         9182     9310     +128     
+ Misses       8716     8702      -14     
  Partials      290      290              
Flag Coverage Δ *Carryforward flag
pester 82.20% <93.96%> (+0.98%) ⬆️
pytest 6.89% <ø> (ø) Carriedforward from 282847a
pytest-dataviewer 61.97% <ø> (ø)
vitest 50.72% <ø> (ø)

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
scripts/linting/Invoke-YamlLint.ps1 93.02% <100.00%> (ø)
scripts/linting/Markdown-Link-Check.ps1 62.50% <100.00%> (+14.94%) ⬆️
scripts/linting/Invoke-ShellCheck.ps1 93.80% <93.80%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- default exit code to failure before try block prevents undefined variable error under StrictMode when CLI binary is not installed

🐛 - Generated by Copilot
Copy link
Copy Markdown
Contributor

@rezatnoMsirhC rezatnoMsirhC left a comment

Choose a reason for hiding this comment

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

I'm now realizing this PR is for linters and not tests, so leaving soft-fail: true on terraform-tests and go-tests was probably intentional. Do we have another issue for enforcing strict warnings/errors on those later on?

name: Terraform Tests
uses: ./.github/workflows/terraform-tests.yml
with:
soft-fail: true
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.

Shouldn't this be soft-fail: false?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correct — updated to soft-fail: false. After merging main, all linting jobs (Terraform Lint, Terraform Validation, Go Lint, ShellCheck) now use soft-fail: false. The new test jobs added by main (Terraform Tests, Go Tests) and Terraform Docs Check remain soft-fail: true as they're outside the scope of this PR.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correction on my earlier reply — this comment points to the Terraform Tests job, which intentionally stays soft-fail: true. Test jobs are out of scope for this PR. The linting jobs above (Terraform Lint, Terraform Validation) are the ones changed to soft-fail: false.

name: Go Tests
uses: ./.github/workflows/go-tests.yml
with:
soft-fail: true
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.

Shouldn't this be soft-fail: false?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yep — changed to soft-fail: false. Same as the Terraform Validation comment above, all linting jobs are now strict.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correction — this comment points to the Go Tests job, which intentionally stays soft-fail: true. The linting jobs (Go Lint, etc.) are the ones changed to soft-fail: false.

name: Terraform Tests
uses: ./.github/workflows/terraform-tests.yml
with:
soft-fail: true
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.

Shouldn't this be soft-fail: false?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed — now soft-fail: false. Same treatment as in main.yml: all linting jobs are strict, test jobs remain soft-fail.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correction — this comment points to the Terraform Tests job, which intentionally stays soft-fail: true. This PR only enforces strict failures on linting jobs (Terraform Validation, Go Lint, ShellCheck). Test jobs remain soft-fail to avoid blocking PRs on infrastructure test flakiness.

name: Go Tests
uses: ./.github/workflows/go-tests.yml
with:
soft-fail: true
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.

Shouldn't this be soft-fail: false?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done — changed to soft-fail: false.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correction — this comment points to the Go Tests job, which intentionally stays soft-fail: true. Same as above: only linting jobs are made strict in this PR.

Comment on lines +102 to +113
$excludeDirs = @('.venv', 'external', 'node_modules', '.git', 'docs/docusaurus')
$allShFiles = @(Get-ChildItem -Path $repoRoot -Filter '*.sh' -Recurse -File | Where-Object {
$relativePath = $_.FullName.Substring($repoRoot.Length + 1)
$excluded = $false
foreach ($dir in $excludeDirs) {
if ($relativePath -like "$dir*" -or $relativePath -like "*/$dir/*" -or $relativePath -like "*\$dir\*") {
$excluded = $true
break
}
}
-not $excluded
})
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.

I'm not sure if this will ever be a problem, but this exclusion pattern would detect false positives like external_tools/ if we ever add a directory like that to this repo (which we might want to spellcheck). I can't imagine the other entries in $excludeDirs causing any problems though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — tightened the exclusion matching. The filter now normalizes paths to forward slashes and uses -like "$dir/*" -or -like "*/$dir/*", which requires a directory boundary (start-of-path or /) before the excluded name. So external_tools/foo.sh would NOT match the external exclusion — only paths like external/foo.sh or some/external/foo.sh will match.

…t-warnings

# Conflicts:
#	.github/workflows/main.yml
#	.github/workflows/pr-validation.yml
#	package.json
#	scripts/linting/Invoke-ShellCheck.ps1
#	scripts/tests/lib/Get-VerifiedDownload.Tests.ps1
#	scripts/tests/lib/terraform-outputs.Tests.ps1
#	scripts/tests/linting/Invoke-ShellCheck.Tests.ps1
- update PSScriptAnalyzer path from shared/ci/linting/ to scripts/linting/

📝 - Generated by Copilot
…k.ps1

- update relative path from ../../../scripts/lib/ to ../lib/ after shared/ci rename

🔧 - Generated by Copilot
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.

[Task]: Enforce strict compiler warning equivalents

4 participants