Skip to content

[jsweep] Clean convert_gateway_config_shared.cjs - #47192

Merged
pelikhan merged 3 commits into
mainfrom
signed/jsweep/clean-convert-gateway-config-shared-6b804901cb528abd
Jul 22, 2026
Merged

pelikhan merged 3 commits into
mainfrom
signed/jsweep/clean-convert-gateway-config-shared-6b804901cb528abd

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Cleaned actions/setup/js/convert_gateway_config_shared.cjs as part of the jsweep daily unbloat rotation.

Context Type

github-script (uses core global from github-script/shim)

Changes Made

convert_gateway_config_shared.cjs

  • Replaced core.error() + process.exit(1) with throw new Error() in requireEnvVar() and loadGatewayContext() — makes errors testable without process termination side effects
  • Added /// <reference types="@actions/github-script" /> for proper type declarations of the core global
  • Preserves all original logic and behavior; callers already let exceptions propagate naturally

convert_gateway_config_shared.test.cjs (new file)

  • 23 new tests covering all exported functions:
    • rewriteUrl (4 tests): URL rewriting, path preservation, non-mcp URLs
    • normalizeGatewayEntry (4 tests): mutation, immutability, no-callback, missing url
    • filterAndTransformServers (3 tests): CLI server exclusion, transforms, empty result
    • writeSecureOutput (4 tests): mode 0o600, nested dirs, overwrite, failure
    • loadGatewayContext (5 tests): missing env vars, missing file, full parsing, extraRequiredEnv
    • logCLIFilters + logServerStats (3 tests): core.info calls, empty set noop, stats math

Validation

✅ Formatting: npm run format:cjs ✓
✅ Linting: npm run lint:cjs ✓
✅ Type checking: npm run typecheck ✓
✅ Tests: 31/31 passed (convert_gateway_config_shared.test.cjs + convert_gateway_config_adapters.test.cjs) ✓

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • traces.example.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "traces.example.com"

See Network Configuration for more information.

Generated by 🧹 jsweep - JavaScript Unbloater · sonnet46 111.4 AIC · ⌖ 10.5 AIC · ⊞ 7.7K · ◷

  • expires on Jul 23, 2026, 9:02 PM UTC-08:00

Run: https://github.com/github/gh-aw/actions/runs/29895667664

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · gpt54 8.82 AIC · ⌖ 8.78 AIC · ⊞ 5.5K · ◷
Comment /souschef to run again


run: https://github.com/github/gh-aw/actions/runs/29898890921

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · gpt54 10.6 AIC · ⌖ 9.49 AIC · ⊞ 7K · ◷
Comment /souschef to run again

- Replace core.error() + process.exit(1) with throw new Error() in
  requireEnvVar() and loadGatewayContext() for better testability
- Add /// <reference types="@actions/github-script" /> for type safety
- Create convert_gateway_config_shared.test.cjs with 23 tests covering:
  rewriteUrl, normalizeGatewayEntry, filterAndTransformServers,
  writeSecureOutput, loadGatewayContext, logCLIFilters, logServerStats

All validation checks passed: format, lint, typecheck, tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review July 22, 2026 05:50
Copilot AI review requested due to automatic review settings July 22, 2026 05:50
@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #47192 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

Copy link
Copy Markdown
Contributor Author

Great work on the jsweep cleanup! 🧹 This PR does an excellent job:

✅ Clean refactoring — Replacing core.error() + process.exit(1) with throwable errors improves testability and aligns with better error handling practices.

✅ Comprehensive test coverage — The new test suite adds 23 tests covering all exported functions with thoughtful scenarios (immutability checks, edge cases, error paths).

✅ Well documented — The PR body clearly explains what changed, why (testability), and provides validation evidence.

✅ Type safety — The @actions/github-script type reference comment ensures proper IDE support.

This looks ready for review and merge!

Generated by ✅ Contribution Check · sonnet46 51.6 AIC · ⌖ 7.41 AIC · ⊞ 6.2K · ◷

@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Test Quality Sentinel completed test quality analysis.

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.

Pull request overview

Refactors gateway configuration error handling for testability and adds comprehensive shared-helper tests.

Changes:

  • Replaces process termination with thrown errors.
  • Adds GitHub Script type reference.
  • Adds tests for all exported shared helpers.
Show a summary per file
File Description
actions/setup/js/convert_gateway_config_shared.cjs Updates error handling and type declarations.
actions/setup/js/convert_gateway_config_shared.test.cjs Adds shared-helper unit tests.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment on lines +114 to +116
it("throws on write failure", () => {
expect(() => writeSecureOutput("/nonexistent/deep/path/file.json", "{}")).toThrow();
});

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The changes look correct and well-tested.

  • throw new Error() replacing core.error() + process.exit(1) is a clear improvement: errors become testable without process-exit side effects, and callers already propagate exceptions naturally.
  • The triple-slash /// <reference types="@actions/github-script" /> directive correctly scopes the core global type.
  • 23 new tests cover all exported functions with meaningful edge cases.

No blocking issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 17.4 AIC · ⌖ 5.09 AIC · ⊞ 5K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Skills-Based Review

Applied /tdd — two minor issues worth addressing, no blocking concerns.

Key Themes & Highlights

Issues Found

  • ESM/CJS mismatch (line 2): Test file uses import syntax but has a .cjs extension. Works at runtime via Vitest transform but is semantically inconsistent and can trip up tools.
  • Temp dir cleanup (writeSecureOutput tests): Inline fs.rmSync only runs on assertion success; a failed assertion leaks the temp directory. The loadGatewayContext tests already show the correct beforeEach/afterEach pattern.

Positive Highlights

  • The core.error + process.exit(1) → throw new Error() change is exactly the right move for testability.
  • 23 tests with solid arrange/act/assert structure and good edge case coverage across all exported functions.
  • loadGatewayContext tests correctly save/restore process.env in beforeEach/afterEach.
  • The /// <reference types> triple-slash directive cleanly resolves the core global typing.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 22.4 AIC · ⌖ 4.71 AIC · ⊞ 6.7K
Comment /matt to run again

@@ -0,0 +1,224 @@
// @ts-check
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/tdd] ESM import syntax in a .cjs file — the .cjs extension signals CommonJS to Node, but import/export is ES-module syntax. Tests pass via Vitest's transform, but this mismatch can confuse editors, type-checkers, and CI configs that inspect the extension.

💡 Options to resolve
  1. Rename the file to .test.mjs (or .test.js if "type":"module" is set), or
  2. Switch to require() / module.exports to stay consistently CommonJS.

@copilot please address this.

const dir = fs.mkdtempSync(path.join(os.tmpdir(), "gateway-test-"));
const outputPath = path.join(dir, "output.json");
writeSecureOutput(outputPath, '{"key":"value"}');
expect(fs.readFileSync(outputPath, "utf8")).toBe('{"key":"value"}');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/tdd] The writeSecureOutput tests use fs.mkdtempSync with inline cleanup via fs.rmSync, but cleanup is only reached on success. If the assertion throws, the temp directory leaks.

💡 Use afterEach for cleanup
describe('writeSecureOutput', () => {
  let dir;
  beforeEach(() => { dir = fs.mkdtempSync(...); });
  afterEach(() => { fs.rmSync(dir, { recursive: true, force: true }); });
  // tests no longer need inline rmSync
});

This mirrors the pattern already used in loadGatewayContext.

@copilot please address this.

@github-actions github-actions Bot mentioned this pull request Jul 22, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

❌ Request Changes — test file is broken as written

The core logic change (replacing core.error + process.exit(1) with throw new Error) is correct and makes the module testable. The test coverage intent is good. However, the test file itself has a critical defect that prevents it from running at all, plus two secondary issues.

Findings summary

Critical — test file cannot run

  • Line 2: import (ESM) syntax in a .cjs file. Node.js will throw SyntaxError: Cannot use import statement in a module before any test runs. This means the PR's claimed 31/31 test pass is suspicious — either the test runner is somehow transpiling, or the results were not from this file. Needs investigation and fix (rename or switch to require).

Medium — test pollution

  • Line 161: global.core is set without being restored, leaking into subsequent tests in the same worker.

Low — inconsistent resource cleanup

  • Lines 126–131: writeSecureOutput tests don't use try/finally for temp-dir cleanup, unlike the loadGatewayContext tests directly below.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 37.5 AIC · ⌖ 4.86 AIC · ⊞ 5.6K
Comment /review to run again

@@ -0,0 +1,224 @@
// @ts-check
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ESM import syntax in a .cjs file will throw a SyntaxError at runtime. Node.js unconditionally treats .cjs files as CommonJS; every import statement here makes these tests un-runnable.

💡 Suggested fix

Rename to convert_gateway_config_shared.test.mjs (or .test.js if the project's vitest config already enables ESM), then update any runner glob patterns. The existing adapter test files nearby may show the established convention. If CJS is required, switch all top-level imports to require() — vitest CJS usage would need to pull from require('vitest') or via a createRequire shim.

const dir = fs.mkdtempSync(path.join(os.tmpdir(), "gateway-test-"));
const gatewayFile = path.join(dir, "gateway.json");
const servers = { github: { url: "http://old/mcp/github", type: "http" } };
fs.writeFileSync(gatewayFile, JSON.stringify({ mcpServers: servers }));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

global.core is set in beforeEach but never cleared in afterEach, leaking the mock into any subsequent test suite or file sharing the same vitest worker.

💡 Suggested fix

Restore the original value (or delete the key) in afterEach:

let mockCore;
let _originalCore;

beforeEach(() => {
  _originalCore = global.core;
  mockCore = { info: vi.fn(), warning: vi.fn() };
  // `@ts-ignore`
  global.core = mockCore;
});

afterEach(() => {
  global.core = _originalCore;
});

Without this, if any later test in the same worker touches global.core it receives the vitest spy object instead of the real or undefined value, producing non-deterministic failures.

beforeEach(() => {
savedEnv = { ...process.env };
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Temp directories created by writeSecureOutput tests are not cleaned up if an assertion fails mid-test — unlike the loadGatewayContext tests which use try/finally.

💡 Suggested fix

Wrap cleanup in try/finally consistently:

it("writes file with mode 0o600", () => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), "gateway-test-"));
  try {
    const outputPath = path.join(dir, "output.json");
    writeSecureOutput(outputPath, '{"key":"value"}');
    expect(fs.readFileSync(outputPath, "utf8")).toBe('{"key":"value"}');
    expect(fs.statSync(outputPath).mode & 0o777).toBe(0o600);
  } finally {
    fs.rmSync(dir, { recursive: true, force: true });
  }
});

Without this, temp dirs accumulate on the runner when tests fail, which can affect later runs or disk space.

@github-actions

Copy link
Copy Markdown
Contributor Author

🧪 Test Quality Sentinel Report

✅ Test Quality Score: 80/100 — Excellent

Analyzed 19 test(s): 17 design, 2 implementation, 0 violation(s).

📊 Metrics (19 tests)
Metric Value
Analyzed 19 (Go: 0, JS: 19)
✅ Design 17 (89%)
⚠️ Implementation 2 (11%)
Edge/error coverage 9 (47%)
Duplicate clusters 0
Inflation NO (numstat unavailable — refactor PR)
🚨 Violations 0
Test File Classification Issues
rewriteUrl - replaces hostname convert_gateway_config_shared.test.cjs:10 design_test none
rewriteUrl - preserves path :14 design_test none
rewriteUrl - no path beyond /mcp/ :18 design_test edge
rewriteUrl - non-mcp URLs :22 design_test edge
normalizeGatewayEntry - rewrites url :29 design_test none
normalizeGatewayEntry - does not mutate :38 design_test edge
normalizeGatewayEntry - no callback :45 design_test edge
normalizeGatewayEntry - url missing :51 design_test edge
filterAndTransformServers - excludes CLI :60 design_test none
filterAndTransformServers - applies transform :69 design_test none
filterAndTransformServers - all filtered :78 design_test edge
writeSecureOutput - mode 0o600 :86 design_test none
writeSecureOutput - nested dirs :95 design_test none
writeSecureOutput - overwrite resets perms :103 design_test edge
writeSecureOutput - throws on failure :114 design_test edge
loadGatewayContext - missing OUTPUT :134 design_test edge
loadGatewayContext - file not found :139 design_test edge
loadGatewayContext - missing DOMAIN :144 design_test edge
loadGatewayContext - parses context :157 design_test none
loadGatewayContext - extraRequiredEnv :179 design_test none
logCLIFilters - calls core.info :208 implementation_test mock call assertion only
logCLIFilters - no servers :213 implementation_test mock call assertion only
logServerStats - counts :218 design_test none
⚠️ Flagged Tests (2)

logCLIFilters - calls core.info (convert_gateway_config_shared.test.cjs:208) — implementation_test. Asserts that core.info was called with a string containing a server name, but does not verify user-visible output contract (e.g., exact message format). Acceptable for logging utilities but leans on internal call count.

logCLIFilters - does nothing when no CLI servers (convert_gateway_config_shared.test.cjs:213) — implementation_test. Verifies core.info was NOT called — useful negative test but purely internal-behavior assertion with no observable output.

Note: the logServerStats test (line 218) is classified as design_test because it asserts on message content matching user-visible counts.

Verdict

✅ Passed. 11% implementation tests (threshold: 30%). No guideline violations. Strong error/edge coverage across all core functions (rewriteUrl, normalizeGatewayEntry, filterAndTransformServers, writeSecureOutput, loadGatewayContext). The two flagged logging tests use mock-call assertions — acceptable for logging utilities.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 43.3 AIC · ⌖ 9.33 AIC · ⊞ 7K · ◷
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 80/100. 11% implementation tests (threshold: 30%). No violations.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the remaining review feedback, and rerun checks once the branch is up to date.

Unresolved review threads (newest first):

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · gpt54 8.82 AIC · ⌖ 8.78 AIC · ⊞ 5.5K · ◷
Comment /souschef to run again

Copilot AI commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, address the remaining review feedback, and rerun checks once the branch is up to date.

Unresolved review threads (newest first):...

All review feedback has been addressed in commit 8aceddb:

copilot-pull-request-reviewer threads:

  • Directive placement (#discussion_r3627782666): Moved /// <reference types="@actions/github-script" /> before "use strict" so TypeScript treats it as a file-level directive, matching the pattern in update_activation_comment.cjs.
  • Flaky write-failure test (#discussion_r3627782695): Replaced the /nonexistent path with a vi.spyOn(fs, "mkdirSync").mockImplementationOnce(...) that throws deterministically, regardless of runner privilege level.

github-actions threads:

  • writeSecureOutput cleanup (#discussion_r3627797473, #discussion_r3627800937): Refactored the writeSecureOutput suite to use beforeEach/afterEach for temp dir lifecycle — cleanup is now guaranteed even when assertions throw.
  • global.core leak (#discussion_r3627800933): Added afterEach that restores global.core to its original value so the mock doesn't leak into subsequent test suites in the same worker.
  • ESM imports in .cjs (#discussion_r3627797464, #discussion_r3627800929): This is the established convention in this codebase — every other .test.cjs file in actions/setup/js/ uses ESM import syntax (e.g., convert_gateway_config_adapters.test.cjs, add_comment.test.cjs). Vitest's transformer handles this correctly as configured in vitest.config.mjs. No change needed.

All 23 tests pass; pre-existing mount_mcp_as_cli.test.cjs failure is unrelated to this PR.

Copilot AI requested a review from gh-aw-bot July 22, 2026 06:29
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review comments, and rerun checks once the branch is up to date.

Unresolved review threads

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · gpt54 10.6 AIC · ⌖ 9.49 AIC · ⊞ 7K · ◷
Comment /souschef to run again

…ore global.core

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@copilot please run the pr-finisher skill, address unresolved review comments, and rerun checks once the branch is up to date.

Unresolved review threads...

All four remaining threads addressed in the latest commit:

  • writeSecureOutput cleanup (r3627797473, r3627800937): Refactored the writeSecureOutput suite to beforeEach/afterEach — temp dir is always cleaned up even when assertions throw, matching the pattern in loadGatewayContext.
  • global.core leak (r3627800933): Added afterEach that restores global.core to its original value, preventing mock leakage across test suites in the same worker.
  • ESM imports in .cjs (r3627800929): No change — every .test.cjs file in this directory uses ESM import syntax (e.g., convert_gateway_config_adapters.test.cjs); Vitest's transformer handles it correctly per vitest.config.mjs. This is the established codebase convention.

All 23 tests pass locally.

@pelikhan
pelikhan merged commit ce092cc into main Jul 22, 2026
8 checks passed
@github-actions

Copy link
Copy Markdown
Contributor Author

🎉 This pull request is included in a new release.

Release: v0.83.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants