Conversation
Generated Code Check ✅All generated code is up to date. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces first-class permission management to the GraphQL API by adding new Tenant/Group/Permissions schema types plus query & mutation resolvers that read/write authorization data via cfg.PermissionManager.
Changes:
- Adds new GraphQL schema/types for tenants, groups, and hierarchical permissions, plus queries and mutations to manage them.
- Implements new gqlgen resolvers to list tenants/groups and to add/remove permissions and set parent relationships.
- Adds a loader middleware nil-guard and introduces resolver-focused tests with a mocked
PermissionManager.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
server/model/models_gen.go |
Adds generated model structs for Tenant, Group, and permission-related types/inputs. |
server/model/finders.go |
Exposes PermissionManager type alias from authz. |
server/model/config.go |
Adds PermissionManager to model.Config. |
schema/graphql/permissions.graphqls |
Defines the new GraphQL types, queries, mutations, and permissions fields on Feed/FeedVersion. |
gqlgen.yml |
Marks Tenant.groups, Group.*, Feed.permissions, and FeedVersion.permissions as resolver-backed fields. |
server/gql/permission_resolver.go |
New resolvers for tenants/groups, permission fields, and permission/admin mutations. |
server/gql/loaders.go |
Skips creating loaders when cfg.Finder is nil. |
server/gql/permission_resolver_test.go |
Adds mock-based resolver tests for tenant/group queries and permission mutations. |
internal/generated/gqlout/generated.go |
Regenerated gqlgen output for new schema/resolvers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
irees
added a commit
that referenced
this pull request
Apr 8, 2026
## Summary Adds missing GraphQL query filters and a new `users` resolver to the permissions API, following up on the permissions PR (#581). The `tenants` and `groups` queries now accept `ids: [Int!]` for direct lookup, matching the convention used by `feeds`, `agencies`, and other existing queries. A new `users` query exposes user search through the `AdminManager` interface, using the standard `where` filter pattern. ### Schema changes - `tenants` and `groups` queries accept `ids: [Int!]` parameter for direct ID lookup - New `User` type with `id`, `name`, and `email` fields - New `UserFilter` input with `id` (single lookup) and `q` (search) fields - New `users(limit: Int, where: UserFilter)` query ### Resolver and interface changes - `AdminManager` interface now includes `UserList` and `User` methods (already implemented on `azchecker.Checker`) - `Tenants`/`Groups` resolvers call `ObjectPermissions` directly for each requested ID, skipping the full `ListObjects` call - `Users` resolver returns empty list gracefully when `AdminManager` is not configured or user is not found ## Test plan - Verify `tenants(ids: [...])` returns matching tenants and empty list for nonexistent IDs - Verify `groups(ids: [...])` returns matching groups and empty list for nonexistent IDs - Verify `users` query lists all users, searches by `q`, looks up by `id`, and respects `limit` - Verify `users(where:{id:...})` returns empty list for unknown IDs (consistent with tenants/groups) - Verify `users` returns empty list when no `AdminManager` is configured
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add permission management to the GraphQL API, enabling the frontend to query and mutate authorization data alongside transit entities. This is the first step toward sunsetting the separate admin REST API — all permission reads and writes are now expressible through GraphQL. Also decouples
azchecker.Checkerfrom itsauth0andfgadependencies, making it pluggable for different auth backends.New GraphQL types
Tenant— represents a tenant organization withid,name,groups, andpermissionsGroup— represents a group within a tenant withid,name,tenant,feeds, andpermissionsPermissions— generic permissions type reused across all entity types, containingactions,subjects,parent, andchildrenPermissionSubject— describes a user/group with a relationship to an entityPermissionRef— lightweight reference to a parent/child entity in the auth hierarchyNew queries
tenants— list tenants accessible to the current user (returns empty list when auth not configured)groups— list groups accessible to the current user (returns empty list when auth not configured)permissionsfield added toFeedandFeedVersiontypes (nullable, returns null when auth not configured)New mutations
permission_add(type, id, input)— add a permission to any entity typepermission_remove(type, id, input)— remove a permission from any entity typepermission_set_parent(type, id, input)— set an entity's parent in the auth hierarchytenant_save(id, input)— update a tenant's nametenant_create_group(id, input)— create a group within a tenantgroup_save(id, input)— update a group's nameChecker decoupling
NewCheckerFromConfignow acceptsUserProviderandFGAProvideras parameters instead of constructing them internallyauth0andfgaimports fromazchecker/checker.go— deployments inject their own providersCheckerConfigreduced to justGlobalAdmin— all provider config is handled by callersCheckerimplementations (withoutPermissionManagerorAdminManager) are supported: permission fields return null, admin mutations return errors, queries/data path works normallyAdminManagerinterface documented with guidance thatUserProviderimplementations are responsible for user visibility scopingEKLookupexported for callers that need to resolve symbolic tuple names to DB IDs (e.g., test setup)Implementation details
cfg.Checkerfrom context, type-asserting toPermissionManagerorAdminManageras neededpermissionsfield on Feed/FeedVersion returnsnullwhenPermissionManageris not configured (no error)tenantsandgroupsqueries return empty lists when unconfigured, matching the nullable patterntype,relation) viaObjectTypeString/RelationStringGroup.feedsresolves fullFeedentities viacfg.Finder.FindFeeds(not just ObjectRef)loaders.gonil-guard added to prevent panic when Finder is not configured"group"added as alias for"org"inObjectType_value— GraphQL API exposes "group" while FGA model uses "org"JWT hardening
useEmailAsIdis set)WithSkipJWKValidation()option for providers with incorrectly encoded x5t valuesTests
TL_TEST_FGA_ENDPOINTand test databaseBreaking changes
NewCheckerFromConfigsignature changed:(ctx, cfg, db) -> (*Checker, error)is now(cfg, userClient, fgaClient, db) -> *CheckerUserProviderandFGAProviderand pass them inExisting REST API
azchecker/server.gois unchanged — same endpoints, same response shapesTest plan
go test -run TestPermissionResolver -v ./server/gql/— all 8 test functions passgo test -run TestNewJWTHandler -v ./server/auth/mw/jwtcheck/— JWT tests passgo test ./server/gql/...with test DB to verify no regressions on existing resolversgo build ./server/...compiles cleanly{ feeds { permissions { actions } } }with and without auth configured