Skip to content

eslint-factory: no-github-request-interpolated-route detects clients by 4 hard-coded names only — off-list Octokit clients and h [Content truncated due to length] #44515

Description

@github-actions

First review of the newest rule no-github-request-interpolated-route (added since 2026-07-08). The rule is sound on the syntactic forms it targets — it correctly flags full-path interpolation and + concatenation on the four known client names. Live true positives it catches: route_slash_command.cjs:180/192/204/216, add_reaction.cjs:193, add_reaction_and_edit_comment.cjs:266, add_workflow_run_comment.cjs:442.

Two soundness gaps stem from the rule being purely syntactic with no scope resolution.

1. Client detection is a 4-name allow-list

create() only matches when callee.object is an Identifier whose name is in {github, octokit, githubClient, octokitClient} (no-github-request-interpolated-route.ts:5,54-55). Any other binding that holds an Octokit client escapes:

  • Off-list client (grounded): fallbackClient is a real Octokit client in update_activation_comment.cjs:211fallbackClient.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", ...). Today it uses a safe literal route, so there is no live miss, but fallbackClient.request(`...${x}`) would be silently accepted.
  • Aliases: const gh = github; gh.request(...) escapes. The codebase already aliases the client via parameter defaults (assign_agent_helpers.cjs:99,149,191,252,294,347 use githubClient = github); those happen to land on an on-list name, but they demonstrate that client bindings are routinely renamed.

2. Variable-indirection: the route argument is only inspected as a syntactic node

The rule inspects node.arguments[0] directly, so a route hoisted into a variable is never examined. Grounded live sites: update_project.cjs:877 and create_project.cjs:252 both call github.request(route, params). Today each route holds a safe literal ternary (typed placeholders, no interpolation), so there is no live true-positive miss — but the rule offers no regression guard: adding a single ${...} to either ternary would go undetected.

Constraint — do NOT naively broaden to any .request()

Node core http.request / https.request are used live: validate_secrets.cjs:66,106, mcp_cli_bridge.cjs:175, mount_mcp_as_cli.cjs:177 (and several .test.cjs). Flagging every .request() call would produce large numbers of false positives. The fix must be scope-aware, not name-broadening.

Acceptance criteria

  • Resolve callee.object to a known Octokit source (e.g. getOctokit(...) results, context.github, github, plus simple const x = <knownClient> aliases and parameter defaults) instead of a fixed name set; keep http/https request calls excluded.
  • Optionally follow a single-assignment const route = <interpolated template | concat> and flag at the request site — or, at minimum, document that variable indirection is out of scope so it is a deliberate limitation rather than an accidental gap.
  • Add tests: off-list-but-aliased client (const gh = github); a fallbackClient-style binding; github.request(route) where route is an interpolated const; and regression tests asserting http.request/https.request stay unflagged.
  • Re-verify after the change: update_activation_comment.cjs:211, update_project.cjs:877, create_project.cjs:252 should remain unflagged (safe literals / recognized-but-safe client).

Generated by 🤖 ESLint Refiner · 208.1 AIC · ⌖ 12.6 AIC · ⊞ 4.6K ·

  • expires on Jul 15, 2026, 10:40 PM UTC-08:00

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions