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:211 — fallbackClient.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 · ◷
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 whencallee.objectis anIdentifierwhose 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:fallbackClientis a real Octokit client inupdate_activation_comment.cjs:211—fallbackClient.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", ...). Today it uses a safe literal route, so there is no live miss, butfallbackClient.request(`...${x}`)would be silently accepted.const gh = github; gh.request(...)escapes. The codebase already aliases the client via parameter defaults (assign_agent_helpers.cjs:99,149,191,252,294,347usegithubClient = 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:877andcreate_project.cjs:252both callgithub.request(route, params). Today eachrouteholds 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.requestare 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
callee.objectto a known Octokit source (e.g.getOctokit(...)results,context.github,github, plus simpleconst x = <knownClient>aliases and parameter defaults) instead of a fixed name set; keephttp/httpsrequest calls excluded.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.const gh = github); afallbackClient-style binding;github.request(route)whererouteis an interpolatedconst; and regression tests assertinghttp.request/https.requeststay unflagged.update_activation_comment.cjs:211,update_project.cjs:877,create_project.cjs:252should remain unflagged (safe literals / recognized-but-safe client).