Skip to content

The 356-line GraphQL gateway has a single test file — audit its coverage of depth limiting, error masking and authorisation #1252

Description

@Jagadeeshftw

Priority: Medium  ·  Difficulty: Medium  ·  Area: GraphQL / API security  ·  Est. effort: 6–9 h

📌 Problem

src/graphql/ is small but exposed:

src/graphql/gateway.ts   356 lines
src/graphql/schema.ts    132 lines

Against that, tests/graphql/ contains a single file, gateway.test.ts.

The line counts are not the concern by themselves — the concern is that a GraphQL endpoint has a specific and well-known set of abuse surfaces, and a single test file for a 356-line gateway is unlikely to cover them. GraphQL differs from REST here: a single endpoint accepts arbitrarily-shaped queries, so protections that REST gets from routing must be implemented explicitly.

The first deliverable is an audit, not a guess. Establish which of the following the gateway implements, and which of those are actually tested:

  • Query depth limiting — without it, a recursive query can be nested arbitrarily deep and exhaust CPU or memory.
  • Query complexity/cost analysis — depth alone does not bound a wide query.
  • Introspection policy — is introspection enabled in production, and is that intended?
  • Error masking — do resolver errors leak stack traces, SQL, or internal messages to the client?
  • Authorisation — is it enforced per-resolver, or only at the transport layer? A single unguarded resolver is a full bypass.
  • Batching/aliasing limits — aliasing the same field many times multiplies work without increasing depth.
  • Rate limiting — the repo has src/redis/rateLimitStore.ts; does it apply to the GraphQL route?

🎯 Design decision required

State and defend:

  1. The audit result — a table of the surfaces above: implemented and tested / implemented but untested / not implemented. This is the core of the PR.
  2. Prioritisation. You are unlikely to close every gap in one PR. Rank them by exploitability against this specific schema and fix the top ones. Argue the ranking from the schema, not from a generic checklist.
  3. Defaults. For anything you add — a depth limit, a complexity budget — justify the specific number against the shapes the schema actually permits, not a value copied from a blog post.

🧩 Requirements and context

  • Do not change the schema's public shape. This is about protecting it, not redesigning it.
  • Every protection you add or confirm needs a test that demonstrates it rejecting an abusive query, not merely accepting a normal one.
  • Reuse existing infrastructure — src/redis/rateLimitStore.ts, src/validation/, the metrics registry — rather than introducing parallel mechanisms.
  • Error masking must not lose server-side detail: the client gets a safe message, the logs keep the full error.
  • Legitimate queries must keep working. Any limit you set must not break existing consumers; check tests/graphql/gateway.test.ts and the generated SDKs.

🛠️ Suggested execution

  1. Read gateway.ts and schema.ts and produce the audit table. Put it in the PR first.
  2. Write tests that attempt abuse for each surface, and record what currently happens.
  3. Fix the highest-ranked gaps.
  4. Confirm legitimate queries are unaffected.
  5. List remaining gaps for follow-up.

✅ Acceptance criteria

  • The PR contains the audit table covering all listed surfaces.
  • For each gap fixed, a test demonstrates an abusive query being rejected.
  • Any limit introduced is justified with a number derived from the actual schema.
  • Error responses carry no internal detail, while full errors still reach the logs — both proven by tests.
  • Existing legitimate queries still pass, including whatever the generated SDKs issue.
  • Remaining gaps are listed explicitly for follow-up.
  • pnpm typecheck, pnpm lint and pnpm test pass.

🚫 Out of scope

  • Changing the GraphQL schema's public shape.
  • Replacing the GraphQL server library.
  • REST route protections.

🧪 Verification

pnpm install --frozen-lockfile
pnpm test tests/graphql
pnpm typecheck && pnpm lint
pnpm check:sdk:ts        # confirm generated SDK queries still validate

📤 What your PR must include

  1. The audit table.
  2. Your prioritisation and the schema-specific reasoning behind it.
  3. Justification for any numeric limit you chose.
  4. The abuse tests, showing rejection.
  5. Closes #<n>.

🔒 Security notes

A GraphQL endpoint concentrates risk: one route, arbitrary query shapes, and per-resolver authorisation that is easy to apply inconsistently. Depth and complexity limits are denial-of-service controls, error masking is an information-disclosure control, and per-resolver authorisation is the actual access-control boundary. Establishing which of these exist today is worth more than adding any one of them blindly.

📋 Guidelines

  • Minimum 95% test coverage on changed lines
  • Clear documentation
  • Timeframe: 96 hours from assignment
  • One logical change per commit; no merge commits

💬 Join our community

Working on this, or want to sanity-check your approach before you start? Come and ask — the maintainers are there and happy to help.

Telegram: https://t.me/Grainlify

Activity

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

Metadata

Metadata

Assignees

Labels

GrantFox OSSGrantFox open-source programMaybe RewardedGrantFox: potentially rewarded contributionThird CampaignGrantFox third campaign issuepriority:mediumMedium difficulty / self-contained but non-trivialtestingTests and coverage

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions