Skip to content

[eslint-miner] fix(eslint-factory): recognize .addListener alias and req.on("response", cb) idiom in require-http-response-error-listener - #59679

Merged
pelikhan merged 2 commits into
mainfrom
eslint-miner-http-response-listener-fix-03f89df283813e3d
Sep 9, 2026
Merged

[eslint-miner] fix(eslint-factory): recognize .addListener alias and req.on("response", cb) idiom in require-http-response-error-listener#59679
pelikhan merged 2 commits into
mainfrom
eslint-miner-http-response-listener-fix-03f89df283813e3d

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes a soundness gap in require-http-response-error-listener — the only ESLint rule in this repo promoted to "error" severity — where two standard Node.js idioms caused the rule to silently skip its check:

  1. .addListener("error", ...) — a documented alias for .on() in Node's EventEmitter API — was not recognized as registering an error listener.
  2. req.on("response", cb) (registering the response handler as a separate listener on the request object, rather than passing it as the inline callback to .request()/.get()) caused getResponseCallback() to return null, so the rule performed no check at all for that call site.

Both are latent/ungrounded gaps (see #59646) — not currently causing false negatives on any live code in actions/setup/js, but filed proactively because this rule's elevated severity makes any false negative here higher-impact, and both idioms are standard patterns likely to appear as the codebase grows.

Changes

  • eslint-factory/src/rules/require-http-response-error-listener.ts:

    • isErrorListenerCall() now accepts "on", "once", and "addListener" (previously only "on"/"once").
    • New getResponseEventCallback() helper detects the req.on("response", cb) idiom (and .once/.addListener variants), including the chained http.request(...).on("response", cb) form, scoped to requests statically resolved to Node's http/https module via the existing isHttpRequestCall()/isHttpRequestResultBinding() resolution logic.
    • Extracted a shared checkResponseCallback() helper so both the inline-callback and separate-listener code paths run the same error-listener check.
    • Updated rule docs.description to document the new detection scope.
  • eslint-factory/src/rules/require-http-response-error-listener.test.ts:

    • Added valid-case tests for .addListener("error", ...) satisfying the check (per acceptance criterion (a)).
    • Added invalid-case tests for req.on("response", cb) with a missing 'error' listener being flagged, and valid-case tests for the idiom with an 'error' listener present — including the chained .on("response", ...).on("error", ...) form (per acceptance criteria (b) and (c)).

Evidence / Validation

  • cd eslint-factory && npm install && npm run build — succeeds, no type errors.
  • cd eslint-factory && npx vitest run675/675 tests pass (8/8 in the updated rule test file).
  • cd eslint-factory && npm run lint:setup-js0 errors reported by gh-aw-custom/require-http-response-error-listener (63 pre-existing unrelated warnings from other rules remain untouched). Confirms the 4 known live call sites (start_mcp_gateway.cjs:560, mount_mcp_as_cli.cjs:245, mcp_cli_bridge.cjs:240, handle_agent_failure.cjs:1820) remain true negatives — no regression.

Acceptance criteria (from #59646)

  • isErrorListenerCall() also recognizes .addListener("error", ...).
  • The rule detects the req.on("response", callback) idiom and applies the same error-listener check to that callback's response parameter.
  • Rule-test cases added for: (a) .addListener("error", ...) satisfying the check, (b) req.on("response", (res) => {...}) with a missing 'error' listener flagged, (c) same idiom with a present 'error' listener not flagged.
  • Re-run against the 4 known live call sites confirms no regression (all remain true negatives).

Fixes #59646

Generated by ESLint Miner · copilot · auto · 102.1 AIC · ⌖ 21.4 AIC · ⊞ 6.9K ·

  • expires on Sep 16, 2026, 12:58 AM UTC-08:00

…se\", cb) idiom

require-http-response-error-listener (the only rule at "error" severity)
missed two standard Node.js EventEmitter/HTTP idioms:

- .addListener("error", ...) is a documented alias for .on(), but was not
  recognized as satisfying the response-error-listener check.
- req.on("response", cb) — registering the response listener separately
  from the inline request callback — caused getResponseCallback() to
  return null, skipping the check entirely for that call site.

Both idioms are now detected: isErrorListenerCall() accepts
"on"/"once"/"addListener", and a new getResponseEventCallback() helper
recognizes the req.on("response", cb)/.once(...)/.addListener(...) idiom
(including the chained http.request(...).on("response", cb) form), scoped
to requests statically resolved to Node's http/https module.

Re-verified against the 4 known live call sites in actions/setup/js
(start_mcp_gateway.cjs, mount_mcp_as_cli.cjs, mcp_cli_bridge.cjs,
handle_agent_failure.cjs) — all remain true negatives (npm run
lint:setup-js still reports the rule at 0 errors).

Fixes #59646

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added automation cookie Issue Monster Loves Cookies! eslint labels Sep 9, 2026
@pelikhan
pelikhan marked this pull request as ready for review September 9, 2026 09:59
Copilot AI balanced review requested due to automatic review settings September 9, 2026 09:59
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

🔬 Test Quality Sentinel is analyzing test quality on this pull request...

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Ponytail Reviewer completed successfully!

Warning

Firewall blocked 1 domain

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

  • ab.chatgpt.com

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #59679

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

🔎 PR Code Quality Reviewer is reviewing code quality for this pull request...

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

🔍 Design Decision Gate 🏗️ is checking for design decision records on this pull request...

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer is reviewing this pull request using Matt Pocock's engineering skills...

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

Ponytail pass focused on simplification opportunities in changed lines.

net: -13 lines possible.

Warning

Firewall blocked 1 domain

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

  • ab.chatgpt.com

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by ✂️ Ponytail Reviewer for #59679 · codex · gpt53codex · 4.59 AIC · ⌖ 3.17 AIC · ⊞ 13.9K
Comment /ponytail to run again

if (callee.object.type !== AST_NODE_TYPES.Identifier || callee.object.name !== name) return false;
if (callee.property.type !== AST_NODE_TYPES.Identifier || (callee.property.name !== "on" && callee.property.name !== "once")) return false;
if (callee.property.type !== AST_NODE_TYPES.Identifier || !LISTENER_METHODS.has(callee.property.name)) return false;
const firstArg = call.arguments[0];

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.

L102: shrink: manual isFromHttpRequest boolean staging with two branches. Early-return by type and inline predicate assignment, same logic in fewer lines.

create(context) {
const sourceCode = context.sourceCode;

/** Reports `callback` when its declared response parameter never gets an 'error' listener attached. */

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.

L174: yagni: separate responseName temp used once for lookup. Use param.name directly in find(...) to remove a dead local.

return grandparent !== undefined && grandparent.type === AST_NODE_TYPES.CallExpression && grandparent.callee === parent && isErrorListenerCall(grandparent, responseName);
});

if (!hasErrorListener) {

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.

L191: shrink: guarded call split across temp + if. getResponseCallback(node) can be checked-and-called inline to cut ceremony.

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.

🟡 Changes recommended

Reassigned request bindings can produce false-positive errors on unrelated objects.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Extends the HTTP response error-listener ESLint rule to recognize additional Node.js listener idioms.

Changes:

  • Supports .addListener("error", ...).
  • Checks response handlers registered through request events.
  • Adds focused rule tests.
File summaries
File Description
require-http-response-error-listener.ts Adds listener detection and shared callback validation.
require-http-response-error-listener.test.ts Tests new valid and invalid patterns.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

if (def.type !== "Variable") return false;
const declarator = def.node as TSESTree.VariableDeclarator;
if (declarator.id.type !== AST_NODE_TYPES.Identifier) return false;
return declarator.init !== null && declarator.init !== undefined && declarator.init.type === AST_NODE_TYPES.CallExpression && isHttpRequestCall(declarator.init, sourceCode);
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot PR sous-chef triage for #59679.

Please address the current forward-progress blockers and then run the pr-finisher skill.

Open review feedback remains from Copilot review:

  • Reassigned request bindings can produce false-positive errors on unrelated objects.

Failed checks from the candidate set:

  • safe_outputs

Please push a fix and rerun the relevant checks, then use the pr-finisher skill.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 24 AIC · ⌖ 8.78 AIC · ⊞ 9.3K ·
Comment /souschef to run again

…reating them as HTTP requests

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

Copilot AI commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

@copilot PR sous-chef triage for #59679.

Please address the current forward-progress blockers and then run the pr-finisher skill....

Addressed the review feedback in 7d1cbc7 (latest push): isHttpRequestResultBinding() now validates every write reference to the binding — it must also be an http/https request()/get() call — so let req = http.request(options); req = makeClient(); req.on("response", res => res.resume()) is no longer matched. Added regression tests for both reassignment directions.

On the failed safe_outputs check: that failure is in the agentic workflow run's own safe_outputs job (run 34337763873 / 34337764125), not in code CI, and is unrelated to this diff. Local validation: make agent-report-progress passes (676/676 eslint-factory tests), npm run build clean, and npm run lint:setup-js reports 0 errors from gh-aw-custom/require-http-response-error-listener against the live actions/setup/js sources — no regression on the 4 known call sites.

Copilot AI requested a review from gh-aw-bot September 9, 2026 10:39
@pelikhan
pelikhan merged commit 105625b into main Sep 9, 2026
@pelikhan
pelikhan deleted the eslint-miner-http-response-listener-fix-03f89df283813e3d branch September 9, 2026 10:43
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

🎉 This pull request is included in a new release.

Release: v0.89.0

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

Labels

automation cookie Issue Monster Loves Cookies! eslint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

require-http-response-error-listener: response-callback detection misses .addListener alias and req.on("response", cb) idiom

4 participants