Skip to content

CodeRabbit Generated Unit Tests: Generate Unit Tests for PR Changes - #168

Closed
coderabbitai[bot] wants to merge 1 commit into
rebuildfrom
coderabbitai/utg/17110cd
Closed

CodeRabbit Generated Unit Tests: Generate Unit Tests for PR Changes#168
coderabbitai[bot] wants to merge 1 commit into
rebuildfrom
coderabbitai/utg/17110cd

Conversation

@coderabbitai

@coderabbitai coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Unit test generation was requested by @BillyOutlast.

The following files were modified:

  • .github/ci-config.test.cjs
  • scripts/check-new-vulns.test.cjs
  • vitest.config.ts

Summary by Sourcery

Add Vitest configuration and unit-style tests to validate CI workflows and the vulnerability-checking script.

Tests:

  • Add Vitest project configuration to run root-level .github and scripts test files alongside existing server tests.
  • Introduce comprehensive integration tests for scripts/check-new-vulns.cjs covering CLI arguments, audit JSON handling, risk register behavior, and pnpm/cargo advisory filtering and severities.
  • Add structural regression tests for GitHub Actions workflows, the rust-ci composite action, and Codecov configuration to guard CI behavior and triggers.

@sourcery-ai

sourcery-ai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds Vitest configuration to run new Node-based CJS tests for CI workflows and the vulnerability-check script, and introduces comprehensive end-to-end-style tests for scripts/check-new-vulns.cjs plus structural regression tests for key GitHub Actions and CI config files.

Sequence diagram for check-new-vulns.cjs test execution via child process

sequenceDiagram
  participant Vitest as Vitest_runner
  participant Tests as check_new_vulns_test_cjs
  participant Spawn as spawnSync
  participant Script as check_new_vulns_cjs

  Vitest->>Tests: run()
  Tests->>Spawn: spawnSync(process.execPath, [SCRIPT_PATH, args])
  Spawn->>Script: invoke script
  Script-->>Spawn: return result
  Spawn-->>Tests: status, stdout, stderr
  Tests-->>Vitest: expect(status, stdout, stderr)
Loading

Flow diagram for updated Vitest multi-project configuration

graph TD
  VitestConfig[vitest.config.ts] --> ServerProject[project ./server]
  VitestConfig --> RootProject[project root]

  RootProject --> NodeEnvironment[node test environment]
  NodeEnvironment --> CjsTests[scripts/**/*.test.cjs]
  NodeEnvironment --> GithubCiTests[.github/**/*.test.cjs]

  CjsTests --> CheckNewVulnsScript[scripts/check-new-vulns.cjs]
  GithubCiTests --> GithubWorkflows[workflow and CI YAML files]
Loading

File-Level Changes

Change Details Files
Configure Vitest to execute root-level Node environment tests for CI and scripts alongside existing server tests.
  • Extend Vitest projects configuration to include the existing ./server project and a new inline project named root
  • Configure the new root project with environment: "node" and root: "."
  • Scope the new project to include scripts/**/*.test.cjs and .github/**/*.test.cjs test files
vitest.config.ts
Add high-coverage black-box tests for the check-new-vulns.cjs CLI covering argument parsing, audit JSON handling, risk register behavior, pnpm format, and cargo format.
  • Introduce a test harness that runs scripts/check-new-vulns.cjs as a child Node process with controlled env, cwd, and temporary files to avoid process.exit side effects
  • Cover CLI argument validation including required flags, unsupported formats, help output, and handling of malformed flag values
  • Validate behavior when audit JSON is missing, empty, malformed, or missing expected keys for both pnpm and cargo audit formats
  • Test risk register resolution via GITHUB_WORKSPACE and cwd, including missing file (fail-open), commented advisories, and known advisory suppression
  • Assert severity filtering semantics (default critical, configurable min severity, aliases like moderate/medium, case-insensitivity, and missing severity treated as critical) and --ignored behavior including comma-separated lists with whitespace
  • Verify output formatting and exit codes for new vs known/ignored advisories, including edge cases in cargo audit entries (missing advisory data, unknown fields)
scripts/check-new-vulns.test.cjs
Introduce structural CI configuration regression tests to ensure workflow triggers, audit gating, Sonar, OSV, Codecov, and rust-ci composite behavior remain intact.
  • Add tests that assert specific trigger branches (including develop) and push behavior for ci.yml, osv-scanner.yml, and other branch-scoped workflows using simple substring/regex checks
  • Verify pnpm audit remains non-blocking and that a follow-up check-new-vulns.cjs step enforces new critical advisories without gating on infra noise
  • Check SonarQube scan and PR-comment workflow wiring, ensuring comments only run on successful scans and that certain steps are or are not continue-on-error as intended
  • Ensure workspace-root-triggered workflows re-run on changes to pnpm-workspace.yaml and package.json by counting path occurrences in workflow YAML
  • Validate the rust-ci composite action’s audit behavior (writing JSON with continue-on-error and running check-new-vulns.cjs via GITHUB_WORKSPACE)
  • Assert that .github/codecov.yml keeps coverage statuses informational, configures a server flag with carryforward, and uses only space indentation (no tabs)
.github/ci-config.test.cjs

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Author

Important

Review skipped

This PR was authored by the user configured for CodeRabbit reviews. CodeRabbit does not review PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0ec745a9-66a0-481b-a4a2-0fab6c2e1378

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@sourcery-ai sourcery-ai 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.

Hey - I've found 1 issue, and left some high level feedback:

  • The workflow-structure tests in .github/ci-config.test.cjs rely on large, exact substring matches, which may be brittle to formatting-only changes; consider narrowing those checks to smaller, more targeted substrings or regexes around the key lines you care about (e.g., specific if: or continue-on-error: directives) to reduce false failures from harmless YAML reformatting.
  • The branchesFor helper assumes a single-line branches: [..] array; if any workflow later switches to multiline branches: syntax, these tests will silently return null and fail in non-obvious ways—consider enhancing the parser or adding explicit assertions that the match succeeded before using the result.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The workflow-structure tests in `.github/ci-config.test.cjs` rely on large, exact substring matches, which may be brittle to formatting-only changes; consider narrowing those checks to smaller, more targeted substrings or regexes around the key lines you care about (e.g., specific `if:` or `continue-on-error:` directives) to reduce false failures from harmless YAML reformatting.
- The `branchesFor` helper assumes a single-line `branches: [..]` array; if any workflow later switches to multiline `branches:` syntax, these tests will silently return `null` and fail in non-obvious ways—consider enhancing the parser or adding explicit assertions that the match succeeded before using the result.

## Individual Comments

### Comment 1
<location path="vitest.config.ts" line_range="7-14" />
<code_context>
+    const jsonPath = writeFile(
+      "audit.json",
+      cargoAudit([
+        {
+          advisory: {
+            id: "RUSTSEC-2026-0001",
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Move `root` out of the nested `test` config so Vitest actually uses it as the project root.

In this inline project config, `root` is defined under `test`, so Vitest will likely ignore it and use the global root instead. To ensure this project is scoped correctly, define `root` at the project level and keep only test-specific options under `test`:

```ts
{
  root: ".",
  test: {
    name: "root",
    environment: "node",
    include: ["scripts/**/*.test.cjs", ".github/**/*.test.cjs"],
  },
}
```

```suggestion
      {
        root: ".",
        test: {
          name: "root",
          environment: "node",
          include: ["scripts/**/*.test.cjs", ".github/**/*.test.cjs"],
        },
      },
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread vitest.config.ts
Comment on lines +7 to +14
{
test: {
name: "root",
root: ".",
environment: "node",
include: ["scripts/**/*.test.cjs", ".github/**/*.test.cjs"],
},
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Move root out of the nested test config so Vitest actually uses it as the project root.

In this inline project config, root is defined under test, so Vitest will likely ignore it and use the global root instead. To ensure this project is scoped correctly, define root at the project level and keep only test-specific options under test:

{
  root: ".",
  test: {
    name: "root",
    environment: "node",
    include: ["scripts/**/*.test.cjs", ".github/**/*.test.cjs"],
  },
}
Suggested change
{
test: {
name: "root",
root: ".",
environment: "node",
include: ["scripts/**/*.test.cjs", ".github/**/*.test.cjs"],
},
},
{
root: ".",
test: {
name: "root",
environment: "node",
include: ["scripts/**/*.test.cjs", ".github/**/*.test.cjs"],
},
},

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

🔍 OpenCodeReview found 4 issue(s) in this PR.

  • ✅ Successfully posted inline: 4 comment(s)

Comment on lines +95 to +103
it("no longer marks the SonarQube Scan step as continue-on-error", () => {
expect(content).toContain(
[
" - name: SonarQube Scan",
" id: sonar-scan",
" uses: SonarSource/sonarqube-scan-action",
].join("\n"),
);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The test title claims to verify that continue-on-error is no longer present on the SonarQube Scan step, but the assertion only checks that three fixed lines exist (- name: SonarQube Scan, id: sonar-scan, uses: SonarSource/...). It does not assert the absence of continue-on-error: true from this step. If someone re-adds continue-on-error: true to this step (a regression the test claims to prevent), the assertion would still pass silently.

Suggestion: Explicitly verify that continue-on-error does not appear between the step name and the next step, or assert that the step's snippet does not contain continue-on-error: true.

Suggestion:

Suggested change
it("no longer marks the SonarQube Scan step as continue-on-error", () => {
expect(content).toContain(
[
" - name: SonarQube Scan",
" id: sonar-scan",
" uses: SonarSource/sonarqube-scan-action",
].join("\n"),
);
});
it("no longer marks the SonarQube Scan step as continue-on-error", () => {
// Verify the step exists as expected
const stepStart = content.indexOf("- name: SonarQube Scan");
expect(stepStart).toBeGreaterThan(-1);
// Check that continue-on-error is NOT present within the SonarQube step
const stepSnippet = content.slice(
stepStart,
content.indexOf("\n - name:", stepStart + 1) // up to the next step
);
expect(stepSnippet).not.toContain("continue-on-error");
});

Comment on lines +105 to +114
it("only runs the SonarCloud PR comment job when the scan succeeded", () => {
const jobStart = content.indexOf("sonar-pr-comment:");
const jobEnd = content.indexOf("\n dockerfile:");
expect(jobStart).toBeGreaterThan(-1);
expect(jobEnd).toBeGreaterThan(jobStart);
const job = content.slice(jobStart, jobEnd);
expect(job).toContain(
"if: github.event_name == 'pull_request' && needs.sonar.result == 'success'",
);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The job boundary is detected by searching for \n dockerfile: as the end marker of the sonar-pr-comment job. This is fragile because:

  1. If a new job is inserted between sonar-pr-comment and dockerfile in ci.yml, the slice will include unrelated content.
  2. If the dockerfile job is renamed (e.g., to Dockerfile-lint), indexOf returns -1 and the test fails cryptically.
  3. If the string \n dockerfile: appears anywhere earlier in the file (e.g., in a comment or step name), the slice will be wrong.

Suggestion: Use a more robust boundary marker, such as searching for the next top-level job key pattern (\n [a-z]+: following the current job) or parsing job-level YAML boundaries.

Suggestion:

Suggested change
it("only runs the SonarCloud PR comment job when the scan succeeded", () => {
const jobStart = content.indexOf("sonar-pr-comment:");
const jobEnd = content.indexOf("\n dockerfile:");
expect(jobStart).toBeGreaterThan(-1);
expect(jobEnd).toBeGreaterThan(jobStart);
const job = content.slice(jobStart, jobEnd);
expect(job).toContain(
"if: github.event_name == 'pull_request' && needs.sonar.result == 'success'",
);
});
it("only runs the SonarCloud PR comment job when the scan succeeded", () => {
const jobStart = content.indexOf("sonar-pr-comment:");
expect(jobStart).toBeGreaterThan(-1);
// Find the next top-level job (lines starting with 2 spaces + word + :)
const afterJob = content.indexOf("\n ", jobStart + 1);
const jobEnd = content.indexOf("\n ", afterJob + 1);
// Or alternatively, use a more specific next-job-name lookup
// const jobEnd = content.indexOf("\n dockerfile:");
if (jobEnd > jobStart) {
const job = content.slice(jobStart, jobEnd);
expect(job).toContain(
"if: github.event_name == 'pull_request' && needs.sonar.result == 'success'",
);
}
});

Comment on lines +29 to +34
function branchesFor(content, triggerName) {
const match = content.match(
new RegExp(`${triggerName}:\\n\\s*branches: \\[([^\\]]+)\\]`),
);
return match ? match[1] : null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The branchesFor regex helper only supports inline array format (branches: [rebuild, develop]). If any workflow file is reformatted to use block-style branch lists (as ci.yml already does: branches:\n - main), the regex returns null and tests fail with a confusing Cannot read properties of null error.

While all currently tested files use inline format, this hidden assumption makes the tests brittle against YAML formatting changes. It contradicts the project's own acknowledgment in the test header that "the same lightweight approach" is used elsewhere — since ci.yml already uses a different format.

Suggestion: Either add a fallback regex for block-style branches, or document this limitation explicitly and add a defensive null check with a clear error message.

Suggestion:

Suggested change
function branchesFor(content, triggerName) {
const match = content.match(
new RegExp(`${triggerName}:\\n\\s*branches: \\[([^\\]]+)\\]`),
);
return match ? match[1] : null;
}
function branchesFor(content, triggerName) {
// Try inline array format first: branches: [a, b, c]
const inlineMatch = content.match(
new RegExp(`${triggerName}:\\n\\s*branches: \\[([^\\]]+)\\]`),
);
if (inlineMatch) return inlineMatch[1];
// Fallback: block format (branches:\n - a\n - b)
const blockMatch = content.match(
new RegExp(`${triggerName}:\\n\\s*branches:\\n((?:\\s+-\\s+\\S+\\n?)+)`),
);
if (blockMatch) return blockMatch[1];
return null;
}

Comment on lines +80 to +85
expect(content).toContain(
[
" - name: Post coverage gaps to PR",
].join("\n"),
);
const stepStart = content.indexOf("- name: Post coverage gaps to PR");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The test uses toContain with exact leading spaces (" - name: Post coverage gaps to PR" — 6 spaces) to assert the step name exists, but then uses indexOf without leading spaces ("- name: Post coverage gaps to PR") to find the step boundary for further assertions. This inconsistency works today but is fragile: if the same step name appears elsewhere in the file with different indentation (e.g., in a different job), indexOf could locate the wrong occurrence.

Suggestion: Use consistent leading spaces in both toContain and indexOf calls.

Suggestion:

Suggested change
expect(content).toContain(
[
" - name: Post coverage gaps to PR",
].join("\n"),
);
const stepStart = content.indexOf("- name: Post coverage gaps to PR");
expect(content).toContain(
" - name: Post coverage gaps to PR",
);
const stepStart = content.indexOf(" - name: Post coverage gaps to PR");

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

SonarCloud Analysis ✅

No BLOCKER, CRITICAL, or MAJOR issues found.

@BillyOutlast
BillyOutlast deleted the branch rebuild July 29, 2026 22:44
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