Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add authorization directive #38955

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 83 additions & 0 deletions packages/gatsby/src/schema/extensions/__tests__/authorization.ts
@@ -0,0 +1,83 @@
const { build } = require(`../..`)
import { GraphQLObjectType, GraphQLSchema } from "graphql"
const { store } = require(`../../../redux`)
const { actions } = require(`../../../redux/actions`)
const { dispatch } = store
const { createTypes } = actions

const report = require(`gatsby-cli/lib/reporter`)
report.error = jest.fn()
report.panic = jest.fn()
report.warn = jest.fn()
report.log = jest.fn()
report.activityTimer = jest.fn(() => {
return {
start: jest.fn(),
setStatus: jest.fn(),
end: jest.fn(),
}
})

const buildSchema = async () => {
await build({})
const {
schemaCustomization: { composer: schemaComposer },
schema,
} = store.getState()
return { schema, schemaComposer }
}

afterEach(() => {
report.error.mockClear()
report.panic.mockClear()
report.warn.mockClear()
report.log.mockClear()
})
describe(`authorization extension`, () => {
beforeEach(() => {
dispatch({ type: `DELETE_CACHE` })
})

it(`adds authorization extension to type and field`, async () => {
dispatch(
createTypes(`
type Auth implements Node @dontInfer @authorization(labels: ["ADMIN"]) {
authField: ID! @authorization(labels: ["USER"])
}
`)
)
const { schema }: { schema: GraphQLSchema } = await buildSchema()
const authType = schema.getType(`Auth`) as GraphQLObjectType
const authTypeFields = authType.getFields()

const authTypeDirective = authType.astNode?.directives?.find(
dir => dir.name.value === `authorization`
)
const authTypeDirectiveValue = authTypeDirective?.arguments?.[0].value
const authFieldDirective =
authTypeFields.authField.astNode?.directives?.find(
dir => dir.name.value === `authorization`
)
const authFieldDirectiveValue = authFieldDirective?.arguments?.[0].value

expect(authFieldDirectiveValue).toMatchObject({
kind: "ListValue",
values: [
{
kind: "StringValue",
value: "USER",
},
],
})

expect(authTypeDirectiveValue).toMatchObject({
kind: "ListValue",
values: [
{
kind: "StringValue",
value: "ADMIN",
},
],
})
})
})
11 changes: 11 additions & 0 deletions packages/gatsby/src/schema/extensions/index.js
Expand Up @@ -69,6 +69,17 @@ const typeExtensions = {
`must also implement the Node interface.`,
locations: [DirectiveLocation.INTERFACE],
},
authorization: {
description: `Define authorization rules for this type.`,
args: {
labels: {
type: `[String!]!`,
defaultValue: [],
description: `A list of auth scopes that are allowed to access this type.`,
}
},
locations: [DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION],
},
}

const builtInFieldExtensions = {
Expand Down
3 changes: 3 additions & 0 deletions packages/gatsby/src/schema/schema.js
Expand Up @@ -485,6 +485,9 @@ const convertDirectivesToExtensions = (typeComposer, directives) => {
extensions[`nodeInterface`] = true
}
break
case `authorization`:
extensions[`authorization`] = args
break
default:
}
})
Expand Down