Skip to content

GraphQL: detect graphql-shield rules and SDL auth directives; link resolvers to mutations #112

Description

@bjcorder

Problem

The GraphQL adapter covers Python Graphene classes, type-graphql decorators, and Apollo resolver maps, but the two dominant JS/TS GraphQL authorization mechanisms outside decorators are missing (docs/PARSERS_AND_ADAPTERS.md, "GraphQL — Not yet"): graphql-shield permission maps and SDL directives (@auth/@hasRole in .graphql schema files). Projects using either are reported as having entirely unguarded operations. GraphQL operations are also not linked to reachable data mutations (docs/CAPABILITIES.md).

Current behavior

  • GraphqlAdapter (crates/authmap-adapters/src/lib.rs) scans Python and JS/TS files only; .graphql/.gql files are not discovered or scanned at all.
  • Apollo resolver-map fields are inventoried but resolver bodies are not inspected for auth, and no shield permissions object is correlated with the resolvers it wraps.
  • No mutation linking for GraphQL operations.

Proposed implementation

  1. graphql-shield permission maps
    • Detect shield({ Query: { field: rule }, Mutation: { ... } }) object literals; classify rule symbols (isAuthenticated, isAdmin, custom rule() definitions — inspect the rule body for ctx.user checks) and attach evidence to the matching Query/Mutation fields already inventoried from the resolver map. allow/not(...)/and(...)/or(...) combinators: extract the strongest recognizable component, otherwise emit graphql_shield_rule_unresolved with lower-confidence/unknown classification (conservative).
  2. SDL auth directives
    • Add .graphql/.gql to discovery extensions (crates/authmap-discovery) as a text-scanned (non-Tree-sitter) source kind.
    • A lightweight line/token scanner is sufficient to extract type/extend type Query|Mutation field definitions and their directives (@auth, @hasRole(role: "..."), @requires(...) — the directive vocabulary should be extensible via config rules).
    • Emit routes/evidence for directive-annotated fields; correlate with resolver-map inventory by field name when both exist (directive evidence + resolver evidence merge on the same operation).
  3. Route→mutation linking
    • Feed resolver functions through link_route_handler_mutations (crates/authmap-analysis/src/lib.rs) exactly as planned for tRPC, so ORM mutations inside resolvers create links.
  4. Follow-on (checklist, lower priority): imperative resolver-body auth — detect context.user / ctx.isAuthenticated guard shapes inside resolver bodies as lower-confidence evidence (noted "not yet classified here" in the adapter).

Acceptance criteria

  • shield fixture: fields wrapped by isAuthenticated classify as guarded; allow-listed field stays public; unresolvable combinator emits the diagnostic and does not claim a guard.
  • SDL fixture: .graphql schema with @auth/@hasRole directives yields guarded operations; role argument maps to role_guarded.
  • Resolver containing a Prisma mutation produces a route→mutation link; docs/CAPABILITIES.md linking caveat updated.
  • .graphql files respect existing scan limits and appear in discovery diagnostics as expected.
  • Unit tests + golden fixtures; docs/PARSERS_AND_ADAPTERS.md GraphQL Not yet list and docs/DIAGNOSTICS.md updated; CHANGELOG entry.

References

  • docs/PARSERS_AND_ADAPTERS.md GraphQL limitations paragraph; docs/CAPABILITIES.md linking gap
  • crates/authmap-adapters/src/lib.rs (GraphqlAdapter, resolver-map extraction)
  • crates/authmap-discovery/src/lib.rs (extension gating)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:adapterFramework adapter workarea:linkingReachability and route-to-operation linkingdetectionAnalyzer detection behavior or pattern coverageenhancementNew feature or requestframework:graphqlGraphQL adapterrustRust implementation work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions