Skip to content

no-github-request-interpolated-route: fallback-expression Octokit client aliases (x || github, ternary) bypass client detection #64186

Description

@github-actions

Rule

eslint-factory/src/rules/no-github-request-interpolated-route.ts

Gap

isOctokitSourceExpression() and isIdentifierBoundToOctokitClient() only recognize a const binding whose initializer is directly one of: a known name (github/octokit/githubClient/octokitClient), a getOctokit(...) call, or context.github. The test suite (no-github-request-interpolated-route.test.ts:242-335) only exercises exactly these single-hop direct-alias shapes.

A const/parameter bound via a fallback expression — LogicalExpression (||, ??) or ConditionalExpression (? :) — whose fallback branch is a known Octokit source is not recognized at all, because isOctokitSourceExpression() has no branch for LogicalExpression/ConditionalExpression. The .request() call is then invisible to the rule regardless of how the route argument is built, so an interpolated/concatenated route on such a client silently escapes detection.

Live grounding

This exact idiom — clientVar = <option> || github — already exists twice in the corpus:

  • actions/setup/js/update_activation_comment.cjs:206-211:
    const fallbackClient = options.targetGithubClient || github;
    ...
    const response = await fallbackClient.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", { ... });
    Today's route argument is a static literal, so there's no live misfire yet — but the rule performs zero analysis of this .request() call site at all (it isn't recognized as an Octokit client site), so a future edit that swaps in a template-literal or concatenated route here would ship with no warning.
  • actions/setup/js/sub_issue_helpers.cjs:15: return githubClient || github; — the same fallback-client idiom, confirming it's a recurring pattern in this codebase rather than a one-off (this particular call site only reaches .graphql(), out of this rule's scope, but demonstrates the idiom repeats).

Ask

Extend isOctokitSourceExpression() (or the call sites in isIdentifierBoundToOctokitClient()) to recurse into LogicalExpression.right and ConditionalExpression.consequent/.alternate when checking whether an initializer resolves to a known Octokit source — mirroring how isStaticRouteExpression() already recurses into BinaryExpression for the route side. Add test cases for:

  • const fallbackClient = options.targetGithubClient || github; fallbackClient.request(\GET /repos/${owner}/${repo}`, {...});` → should report (currently silent).
  • const client = useTarget ? targetClient : github; client.request(...) → should report the same way when the route is dynamic.

Generated by 🤖 ESLint Refiner · claude · agent · 248.1 AIC · ⌖ 6.98 AIC · ⊞ 4.8K · ◷

  • expires on Oct 5, 2026, 9:34 PM UTC-08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions