Skip to content

chore(ci): editorconfig, format gate, NuGet cache, dependabot expansion, CodeQL - #60

Merged
phuongnse merged 3 commits into
mainfrom
ci/enhance-workflow-and-security
May 23, 2026
Merged

chore(ci): editorconfig, format gate, NuGet cache, dependabot expansion, CodeQL#60
phuongnse merged 3 commits into
mainfrom
ci/enhance-workflow-and-security

Conversation

@phuongnse

@phuongnse phuongnse commented May 23, 2026

Copy link
Copy Markdown
Owner

Summary

Foundation hygiene PR enhancing the GitHub Actions CI for production scale. No application code semantics change — the only src/ touches are charset (BOM) fixes that the new .editorconfig surfaced on auto-generated migration files.

CI workflow (build-and-test.yml)

  • setup-dotnet built-in NuGet cache shaves restore time across PRs
  • dotnet format --verify-no-changes step closes the Gate 1 gap (CLAUDE.md required it locally; CI was not enforcing — that's how the DataModeling format gunk slipped through earlier)
  • dotnet test --logger trx + actions/upload-artifact for PR annotations + post-mortem
  • timeout-minutes per job — deadlocked test no longer burns minutes
  • New dependency-review job catches vulnerable transitive deps on PR (GitHub-native, fails on high+ severity)

CodeQL (codeql.yml new workflow)

  • SAST scanning for C# (autobuild mode) and JS/TS, security-extended,security-and-quality queries
  • Runs on PR (with path filters so docs-only PRs skip) + weekly cron on main

Dependabot (dependabot.yml extended)

  • Existing actions-only config kept; adds NuGet (Directory.Packages.props) + frontend npm
  • Per-ecosystem groups keep noise down: Microsoft.*, WolverineFx*, OpenIddict*, Serilog*, TanStack, Vite, Biome

.editorconfig (new — was missing)

  • Without it, dotnet format on Windows used CRLF while CI on Linux used LF → false-positive whitespace errors locally
  • Minimal version enforces LF, UTF-8 no-BOM, trim trailing whitespace, indent per file type
  • Comprehensive style/naming/analyzer rules deferred to a follow-up issue so this PR stays scoped

BOM fixes (drift-required side effect)

  • New charset rule surfaced 9 auto-generated files (5 migrations + 4 fixtures) with UTF-8 BOM. dotnet format strips. Zero behaviour change.

Linked spec

Requirements & rules followed

  • Spec → code — no AC delivery; foundation hygiene
  • Gate 0 — N/A
  • Gate 1dotnet build 0/0, dotnet format --verify-no-changes green, all unit + integration projects green locally (Testcontainers, Docker on dev machine)
  • Gate 2./scripts/check-doc-drift.sh green; module README touches in same PR
  • Gate 3 — new durable rules captured: .editorconfig as canonical .NET style config, format step now CI-enforced. Follow-up issue tracked for comprehensive style/naming rules.
  • No new TODO / FIXME / placeholder / stub

Follow-up

A separate issue will track the comprehensive .editorconfig (full C# style + naming + analyzer-severity rules) — that requires analysing existing patterns and dotnet format mass-application, which doesn't belong bundled with CI workflow changes.

Summary by CodeRabbit

  • Chores
    • Established repository-wide code formatting and editor configuration standards.
    • Enhanced automated dependency management with comprehensive update scheduling for backend and frontend packages.
    • Improved CI/CD pipeline with test result artifact retention and code formatting verification gates.

Review Change Stack

Foundation hygiene PR enhancing GitHub Actions CI for production scale.
No application code semantics change.

CI workflow:
- `setup-dotnet` built-in NuGet cache (`cache: true`) shaves restore time
- `dotnet format --verify-no-changes` step closes the Gate 1 gap
  (CLAUDE.md required it locally; CI was not enforcing)
- `dotnet test --logger trx` + `actions/upload-artifact` for PR
  annotations + post-mortem analysis
- `timeout-minutes` per job — deadlocked test no longer burns minutes
- New `dependency-review` job catches vulnerable transitive deps on PR
- New `codeql.yml` workflow for SAST scanning (C# + JS/TS),
  `security-extended,security-and-quality` queries, weekly + PR runs

Dependabot:
- Extends the existing actions-only config with NuGet (Directory.Packages)
  and frontend npm. Per-ecosystem groups keep noise down: Microsoft.*,
  WolverineFx*, OpenIddict, Serilog, TanStack, Vite, Biome.

.editorconfig:
- Project was missing this canonical .NET config. Without it,
  `dotnet format` on Windows used CRLF while CI on Linux used LF,
  producing false-positive whitespace errors locally. Minimal version
  here enforces LF, UTF-8 (no BOM), trim trailing whitespace, indent
  per file type. Comprehensive style/naming/analyzer rules are deferred
  to a follow-up issue so this PR stays scoped.

BOM fixes:
- New charset rule surfaced 9 files (auto-generated migrations + test
  fixtures) with UTF-8 BOM. `dotnet format` strips them. No behaviour
  change.

Module README touches (drift requirement):
- E04, E05, E06 each get a short, accurate detail about EF migrations
  in the Infrastructure row (naming the migrations the BOM fix
  touched). Identity is not in the drift script's path map.
@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1429b67c-ecfb-4bf4-b904-8232a3de733a

📥 Commits

Reviewing files that changed from the base of the PR and between 3973f6a and 54f141b.

📒 Files selected for processing (1)
  • .github/workflows/build-and-test.yml

📝 Walkthrough

Walkthrough

This PR standardizes repository formatting with .editorconfig, expands Dependabot automation to cover NuGet and npm ecosystems, enhances CI/CD workflows with caching and test reporting, updates epic documentation with infrastructure details, and removes BOM encoding artifacts from migration and test files.

Changes

Repository Quality and CI/CD Standards

Layer / File(s) Summary
Repository Formatting Standards
.editorconfig
Introduces repository-wide editor configuration enforcing UTF-8 encoding without BOM, LF line endings, final newline insertion, trailing-whitespace trimming, and language-specific indentation (2–4 spaces for C#/web/data files, tabs for Makefiles, 4 spaces for PowerShell, 2 spaces for shell scripts).
Multi-Ecosystem Dependabot Setup
.github/dependabot.yml
Expands Dependabot from a minimal GitHub Actions config to a version: 2 manifest that schedules weekly Monday updates (06:00 Asia/Ho_Chi_Minh) for NuGet packages (/), npm frontend packages (/frontend), and GitHub Actions. Includes ecosystem-specific grouped update rules for Microsoft.Extensions, EntityFrameworkCore, AspNetCore, Wolverine, OpenIddict, Serilog, testing packages, React, and build tooling.
CI Pipeline Enhancements and Test Reporting
.github/workflows/build-and-test.yml
The .NET build job adds a 20-minute timeout and enables dotnet caching scoped to **/*.csproj. A new dotnet format verification step gates the build. Test execution outputs TRX results to TestResults/, which are uploaded as artifacts with 14-day retention via if: always() to preserve results even on failure. The doc-drift and link-check jobs each gain 5-minute timeouts. A previously commented-out dependency-review job block is expanded with GHAS provisioning and CodeQL upload context notes.
Epic Infrastructure Documentation Updates
docs/epics/E04-workflow-builder/README.md, docs/epics/E05-form-builder/README.md, docs/epics/E06-workflow-engine/README.md
Infrastructure implementation-status rows are enhanced with concrete details: JSONB persistence for workflow definitions, specific migration examples (e.g., AddUniqueConstraintOnWorkflowName), Testcontainers test counts, EF Core migration-based schema management, and InternalsVisibleTo("Axis.Api") tenant-schema visibility.
BOM and Encoding Cleanup
src/Modules/FormBuilder/Axis.FormBuilder.Infrastructure/Migrations/20260519044541_AddFormWorkflowReferences.cs, src/Modules/WorkflowBuilder/Axis.WorkflowBuilder.Infrastructure/Migrations/20260518034752_AddUniqueConstraintOnWorkflowName.cs, src/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure/Migrations/20260517150217_AddExecutionSteps.cs, src/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure/Migrations/20260519044503_AddWorkflowActiveStatuses.cs, src/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure/Migrations/20260520012358_AddWorkflowSnapshot.cs, tests/Modules/FormBuilder/Axis.FormBuilder.Infrastructure.Tests/Fixtures/FormBuilderDatabaseFixture.cs, tests/Modules/WorkflowBuilder/Axis.WorkflowBuilder.Infrastructure.Tests/Fixtures/WorkflowBuilderDatabaseFixture.cs, tests/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure.Tests/Fixtures/WorkflowEngineDatabaseFixture.cs
Removes leading byte-order mark (BOM) and Unicode encoding prefixes from the first line of migration and test fixture files, aligning with the .editorconfig UTF-8 no-BOM requirement without changing runtime behavior.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly Related PRs

  • phuong-labs/axis#49: Modifies the same doc-drift job in .github/workflows/build-and-test.yml, reordering the job and adjusting how it invokes the drift check script.
  • phuong-labs/axis#51: Also modifies .github/workflows/build-and-test.yml and .github/dependabot.yml, overlapping on CI/governance infrastructure surfaces.

Poem

🐰 Hop along, dear code, in UTF-8 cheer,
No BOMs to spoil your debut here!
Dependabot now watches NuGet's door,
While CI times out and tests report more—
A cleaner repo, from root to core!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: CI/configuration updates including editorconfig, format gate, NuGet cache, dependabot expansion, and CodeQL workflow adjustments.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/enhance-workflow-and-security

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/build-and-test.yml (1)

11-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Grant pull-requests: write for dependency-review PR comment summaries

  • comment-summary-in-pr: on-failure requires pull-requests: write, but the workflow only grants permissions: contents: read.
  • actions/setup-dotnet cache keys are based on packages.lock.json; with cache-dependency-path: '**/*.csproj' (and no packages.lock.json in the repo), cache invalidation won’t track CPM-only changes in Directory.Packages.props.
🔧 Suggested fix
  dependency-review:
    name: Dependency review
    runs-on: ubuntu-latest
    timeout-minutes: 5
+   permissions:
+     contents: read
+     pull-requests: write
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-test.yml around lines 11 - 13, The workflow
currently only grants permissions: contents: read which prevents
comment-summary-in-pr: on-failure from posting PR summary comments; update the
permissions block to include pull-requests: write (in addition to contents:
read) so comment-summary-in-pr can create PR comments, and adjust the
actions/setup-dotnet cache config by changing cache-dependency-path from
'**/*.csproj' to include packages.lock.json and/or Directory.Packages.props
(e.g., '**/packages.lock.json' and 'Directory.Packages.props') so cache keys
reflect CPM-only changes.
🧹 Nitpick comments (1)
.github/workflows/build-and-test.yml (1)

30-31: ⚡ Quick win

Include central package metadata in NuGet cache key inputs.

Using only **/*.csproj misses central package version bumps in Directory.Packages.props, reducing cache effectiveness.

♻️ Suggested refactor
       with:
         dotnet-version: 8.0.x
         cache: true
-        cache-dependency-path: '**/*.csproj'
+        cache-dependency-path: |
+          **/*.csproj
+          Directory.Packages.props
+          **/packages.lock.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-test.yml around lines 30 - 31, The NuGet cache
key currently only tracks project files via cache-dependency-path '**/*.csproj'
and therefore misses central package version changes in
Directory.Packages.props; update the workflow step that defines
cache-dependency-path to include Directory.Packages.props (e.g., add
'**/Directory.Packages.props' alongside '**/*.csproj') so cache keys change when
central package metadata is updated and caching remains correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/build-and-test.yml:
- Around line 11-13: The workflow currently only grants permissions: contents:
read which prevents comment-summary-in-pr: on-failure from posting PR summary
comments; update the permissions block to include pull-requests: write (in
addition to contents: read) so comment-summary-in-pr can create PR comments, and
adjust the actions/setup-dotnet cache config by changing cache-dependency-path
from '**/*.csproj' to include packages.lock.json and/or Directory.Packages.props
(e.g., '**/packages.lock.json' and 'Directory.Packages.props') so cache keys
reflect CPM-only changes.

---

Nitpick comments:
In @.github/workflows/build-and-test.yml:
- Around line 30-31: The NuGet cache key currently only tracks project files via
cache-dependency-path '**/*.csproj' and therefore misses central package version
changes in Directory.Packages.props; update the workflow step that defines
cache-dependency-path to include Directory.Packages.props (e.g., add
'**/Directory.Packages.props' alongside '**/*.csproj') so cache keys change when
central package metadata is updated and caching remains correct.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 76de20bc-6b61-43de-8c1d-4087ee52e2b8

📥 Commits

Reviewing files that changed from the base of the PR and between 4ed1d1b and 0282bb2.

📒 Files selected for processing (15)
  • .editorconfig
  • .github/dependabot.yml
  • .github/workflows/build-and-test.yml
  • .github/workflows/codeql.yml
  • docs/epics/E04-workflow-builder/README.md
  • docs/epics/E05-form-builder/README.md
  • docs/epics/E06-workflow-engine/README.md
  • src/Modules/FormBuilder/Axis.FormBuilder.Infrastructure/Migrations/20260519044541_AddFormWorkflowReferences.cs
  • src/Modules/WorkflowBuilder/Axis.WorkflowBuilder.Infrastructure/Migrations/20260518034752_AddUniqueConstraintOnWorkflowName.cs
  • src/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure/Migrations/20260517150217_AddExecutionSteps.cs
  • src/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure/Migrations/20260519044503_AddWorkflowActiveStatuses.cs
  • src/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure/Migrations/20260520012358_AddWorkflowSnapshot.cs
  • tests/Modules/FormBuilder/Axis.FormBuilder.Infrastructure.Tests/Fixtures/FormBuilderDatabaseFixture.cs
  • tests/Modules/WorkflowBuilder/Axis.WorkflowBuilder.Infrastructure.Tests/Fixtures/WorkflowBuilderDatabaseFixture.cs
  • tests/Modules/WorkflowEngine/Axis.WorkflowEngine.Infrastructure.Tests/Fixtures/WorkflowEngineDatabaseFixture.cs

…nly)

Two CI failures on PR #60:

1. dependency-review fails on private repos without GitHub Advanced
   Security: "Dependency review is not supported on this repository."
   Comment the job out with a note explaining when to re-enable;
   Dependabot continues to cover the same threat model.

2. CodeQL init/analyze pinned to a SHA I had not verified; GitHub
   could not resolve it. Use the actual v4 floating-tag SHA from
   github/codeql-action.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-and-test.yml:
- Around line 124-143: Reintroduce a lightweight PR-time security gate by adding
a new job (e.g., dependency-security-gate) instead of the full commented
dependency-review job: have it checkout the repo and run two dedicated steps —
(1) NuGet/.NET audit: setup-dotnet, run dotnet restore and then run dotnet build
(or dotnet restore/build) with warnings promoted to errors for NU1900–NU1905
(use MSBuild/dotnet's -warnaserror:NU1900;NU1901;NU1902;NU1903;NU1904;NU1905 so
those NuGet audit warnings fail CI), and (2) npm/frontend audit: setup-node,
install deps and run npm audit --audit-level=high (relying on its non-zero exit
code to fail the job); name the job clearly (dependency-security-gate or
re-enable dependency-review) so reviewers can find and adjust it later.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: acb93460-0e0a-49e6-9257-976e043d30e7

📥 Commits

Reviewing files that changed from the base of the PR and between 0282bb2 and 3973f6a.

📒 Files selected for processing (2)
  • .github/workflows/build-and-test.yml
  • .github/workflows/codeql.yml

Comment thread .github/workflows/build-and-test.yml Outdated
Comment on lines +124 to +143
# NOTE: actions/dependency-review-action requires GitHub Advanced Security
# for private repositories (paid). Re-enable this job by uncommenting once
# GHAS is provisioned, or if/when the repo becomes public. In the meantime,
# Dependabot (configured in .github/dependabot.yml) opens PRs for new
# advisories against existing dependencies, which covers the same threat
# model with a delay.
#
# dependency-review:
# name: Dependency review
# runs-on: ubuntu-latest
# timeout-minutes: 5
# steps:
# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# with:
# persist-credentials: false
# - name: Dependency review
# uses: actions/dependency-review-action@67d4f4bd7a9b17a0db54d2a7519187c65e339de8 # v4.8.0
# with:
# fail-on-severity: high
# comment-summary-in-pr: on-failure

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For private GitHub repositories, what are the current availability/licensing requirements of actions/dependency-review-action, and what are recommended PR-time alternatives (NuGet + npm) that can fail CI on high/critical vulnerabilities without GitHub Advanced Security?

💡 Result:

Availability/licensing for actions/dependency-review-action on private repos (2026-05-23) 1) Private GitHub repositories - The dependency review action is available for private repositories only if the owning organization has a GitHub Advanced Security license. [1][2][3] - The action checks PR dependency changes and “will raise an error if any vulnerabilities or invalid licenses are being introduced.” [1][2] - License enforcement notes: license checking is not supported on GitHub Enterprise Server because the API does not return license information. [1] 2) Practical implication - If your organization does not have GitHub Advanced Security, you should not expect this action to provide the vulnerability/license enforcement experience on private repos; it is explicitly tied to Advanced Security for private repos. [1][2][3] Recommended PR-time alternatives (NuGet + npm) that can fail CI on high/critical vulnerabilities without GitHub Advanced Security A) NuGet (.NET): use NuGet Audit in a dedicated CI job and treat audit findings as failures - Microsoft documents “NuGet Audit” support for CI and describes running audits in CI while selectively treating warnings as errors in the audit pipeline. [4] - This is explicitly framed as a way to have audit runs “fail” in CI for known vulnerabilities while keeping other pipelines from being blocked. [4] B) npm (Node): use an audit tool with severity thresholds, and ensure it fails the build - npm’s built-in auditing (npm audit) can be used in CI, but you must handle reliability issues (for example, audit network timeouts can fail installs). One documented fix is to control audit behavior so the CI doesn’t fail due to network timeouts when you don’t need npm to audit as part of install. [5] - Since your requirement is “fail CI on high/critical vulnerabilities,” the recommended pattern is: 1) Disable/avoid audit during npm install (so CI doesn’t fail from transient audit endpoint issues), and 2) Run a separate security audit step (or a dedicated audit command) that enforces failure based on severity. The dotnet/aspnetcore PR specifically discusses adding audit=false to .npmrc to avoid audit being part of npm ci installs and causing failures from timeouts. [5] What I would implement as a PR-time gate (high level) - For NuGet: add a PR workflow step/job that runs NuGet Audit and configures MSBuild/CI so that audit findings cause a non-zero exit (only in the security gate job). [4] - For npm: avoid letting npm ci run audits during dependency install (to reduce audit-related CI flakiness), and run an explicit vulnerability audit command in a dedicated step that fails on high/critical. [5] Note: I did not find an authoritative single source in this round that names a specific “PR-time npm tool + exact high/critical threshold flags” equivalent to GitHub dependency-review-action. The sources above only directly support (a) that npm install audits can cause hard CI failures from timeouts and (b) that turning off install-time audit via .npmrc is a documented mitigation. [5] If you want, tell me your CI system (GitHub Actions/GitLab/etc.) and whether you use npm, yarn, or pnpm, and I’ll do a second targeted search for an authoritative npm auditing CLI that supports severity thresholds and a CI-fail contract.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the referenced lines around the commented dependency-review job
sed -n '100,170p' .github/workflows/build-and-test.yml

# Confirm whether dependency-review appears elsewhere
rg -n "dependency-review" .github/workflows/build-and-test.yml .github/workflows || true

# Look for any existing dependency/vulnerability scanning jobs/steps in the workflow
rg -n "(dependabot|audit|vuln|vulnerability|security|osv|trivy|grype|snyk|npm audit|nuget audit|dependency)" .github/workflows/build-and-test.yml || true

Repository: phuong-labs/axis

Length of output: 2814


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find other PR-time dependency/vulnerability scanning in .github/workflows =="
rg -n "(dependabot|audit|vuln|vulnerability|security|osv|trivy|grype|snyk|npm audit|nuget audit|dependency-review-action|osv-scanner|gitleaks|semgrep)" .github/workflows || true

echo
echo "== Check Dependabot config =="
if [ -f .github/dependabot.yml ]; then
  sed -n '1,220p' .github/dependabot.yml
else
  echo "Missing .github/dependabot.yml"
fi

echo
echo "== Search other GitHub config for dependency scanning =="
rg -n "(dependency-review|nuget audit|npm audit|osv|trivy|grype|snyk)" .github || true

Repository: phuong-labs/axis

Length of output: 3693


🌐 Web query:

npm audit --audit-level high ci fail exit code

💡 Result:

What you should expect 1) npm audit will fail in CI (non-zero exit code) when vulnerabilities are found at or above the threshold you set with --audit-level. The npm docs state that by default npm audit exits non-zero if any vulnerability is found, and that --audit-level “changes the command’s failure threshold” (it does not filter the report output) [1][2]. They also state that the command exits with code 0 if no vulnerabilities are found, and that if vulnerabilities are found, the exit code depends on the audit-level config [1][2]. 2) The specific command you gave: npm audit --audit-level high Using --audit-level=high means the audit should exit non-zero only when the results include a vulnerability with severity “high” or higher (docs example uses “moderate” as the rule, but the same mechanism applies to other levels) [1][2]. Why you might still see CI “pass” or exit 0 unexpectedly A) npm/Node version-specific behavior There is a reported npm CLI bug where exit codes were not being set properly in certain Node 20 versions: a user reported that npm audit “always exists with a 0 exit code, even if a vulnerability is found” for some versions [3]. If you’re seeing audit not failing, check your Node/npm versions and consider testing against an earlier LTS (the issue discussion reports reverting to Node 18 LTS as a workaround) [3]. B) CI scripting/step issues (not npm audit itself) Make sure the CI step is actually running npm audit (and that you’re not masking the exit code), and that the shell/CI runner is configured to fail the job on non-zero exit codes. Recommended CI usage - Run: npm audit --audit-level=high - Ensure your CI fails on any non-zero exit code from that command. If you need, you can also force a consistent behavior by pinning Node/npm versions in CI (to avoid version-specific regressions like the one reported above) [3][1].

Citations:


🌐 Web query:

NuGet Audit in CI treat findings as errors fail the build

💡 Result:

To make NuGet Audit findings fail your CI build (treat them as errors), you do this via MSBuild warning-as-error configuration using the NuGet Audit warning codes (NU1900–NU1905). NuGet Audit itself produces MSBuild warnings during restore when known vulnerable packages are used, and MSBuild can be configured to treat specific warning codes as errors so the restore/build fails. [1] 1) Fail the build for NuGet Audit warnings in the audit pipeline Use WarningsAsErrors together with the NuGetAuditCodes list (NU1900–NU1905). Microsoft Learn shows an approach that enables this only for your CI audit pipeline (e.g., via an AuditPipeline variable) and otherwise does not treat them as errors. [1] Example (.csproj or Directory.Build.props): NU1900;NU1901;NU1902;NU1903;NU1904;NU1905 $(WarningsAsErrors);$(NuGetAuditCodes) $(WarningsNotAsErrors);$(NuGetAuditCodes) Then set AuditPipeline=true for the CI job that you want to block on vulnerabilities. This is explicitly recommended for CI to avoid breaking developer builds/other pipelines while still failing the dedicated audit pipeline. [1] 2) Alternatively: treat specific audit codes as errors directly You can treat all (or selected) NuGet Audit warning codes as errors using WarningsAsErrors; a Microsoft documentation example notes using NU1901–NU1904 with TreatWarningsAsErrors to prevent newly discovered vulnerabilities from breaking builds. [2][3] 3) If you want to ensure transitive vulnerabilities are included NuGetAuditMode defaults differently depending on target framework: when targeting net10.0+ it defaults to all (including transitive packages) unless explicitly set, which can cause restore failures if warnings are treated as errors. Microsoft describes this behavior and how to avoid it (e.g., set NuGetAuditMode=direct). [3] So if your CI is failing because transitive deps are now included, either: - intentionally keep auditing transitive packages (and fail the build), or - reduce scope by setting direct in your project/Directory.Build.props. [3] 4) Practical note: this works at restore/build time, not as a separate “exit-code” switch NuGet Audit warnings appear during restore like other MSBuild warnings/errors, so the “fail CI” behavior comes from MSBuild’s warning-to-error settings rather than a dedicated “--fail” flag for nuget audit. Microsoft Learn discusses configuring CI restore so audit warnings are (or aren’t) treated as errors. [1] If you tell me your CI system (GitHub Actions/Azure DevOps/etc.) and whether you want to fail only on critical/high vs any severity, I can give a ready-to-paste workflow snippet and recommended MSBuild properties.

Citations:


Reintroduce a PR-time dependency vulnerability gate (fallback when GHAS isn’t available).

build-and-test.yml comments out the entire dependency-review job (lines 124-143), and there’s no other PR-time dependency vulnerability gate in the workflow; Dependabot creates follow-up PRs, but that doesn’t block the introducing PR from merging. Add a lightweight CI “security gate” instead:

  • NuGet/.NET: run a dedicated audit/restore step and fail the job by treating NuGet Audit warning codes (NU1900–NU1905) as MSBuild errors in that CI job (optionally set NuGetAuditMode=direct if you only want direct deps).
  • npm/frontend: run npm audit --audit-level=high in a dedicated step and rely on its non-zero exit code to fail CI (pin Node/npm if you hit exit-code inconsistencies).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-test.yml around lines 124 - 143, Reintroduce a
lightweight PR-time security gate by adding a new job (e.g.,
dependency-security-gate) instead of the full commented dependency-review job:
have it checkout the repo and run two dedicated steps — (1) NuGet/.NET audit:
setup-dotnet, run dotnet restore and then run dotnet build (or dotnet
restore/build) with warnings promoted to errors for NU1900–NU1905 (use
MSBuild/dotnet's -warnaserror:NU1900;NU1901;NU1902;NU1903;NU1904;NU1905 so those
NuGet audit warnings fail CI), and (2) npm/frontend audit: setup-node, install
deps and run npm audit --audit-level=high (relying on its non-zero exit code to
fail the job); name the job clearly (dependency-security-gate or re-enable
dependency-review) so reviewers can find and adjust it later.

CodeQL analysis ran successfully end-to-end (171 queries, no findings)
but the upload step failed with "Code Security must be enabled for this
repository to use code scanning" — same root cause as dependency-review:
GitHub Advanced Security is required on private repos for code scanning.

Remove the workflow file entirely so PRs aren't blocked by an
unsupportable check. Build-and-test.yml carries an inline comment
documenting both jobs (dependency-review + CodeQL) with restore
instructions, so re-enabling once GHAS is provisioned is a single
revert.
@phuongnse
phuongnse merged commit 8269e31 into main May 23, 2026
5 checks passed
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