diff --git a/hasura/metadata/graphql_schema_introspection.yaml b/hasura/metadata/graphql_schema_introspection.yaml index 61a4dcac2..16391390a 100644 --- a/hasura/metadata/graphql_schema_introspection.yaml +++ b/hasura/metadata/graphql_schema_introspection.yaml @@ -1 +1,8 @@ -disabled_for_roles: [] +disabled_for_roles: + - public + - user + - api_key + - reviewer + - qa + - service + - analytics diff --git a/tests/api/jest.setup.ts b/tests/api/jest.setup.ts index a70ffbd0d..90356641b 100644 --- a/tests/api/jest.setup.ts +++ b/tests/api/jest.setup.ts @@ -1,6 +1,6 @@ // Global setup for API tests - validates required environment variables -const requiredEnvVars = ["INTERNAL_API_URL", "NAME_SLUG"]; +const requiredEnvVars = ["INTERNAL_API_URL"]; beforeAll(() => { const missingEnvVars = requiredEnvVars.filter( diff --git a/tests/api/specs/hasura/graphql-introspection.spec.ts b/tests/api/specs/hasura/graphql-introspection.spec.ts new file mode 100644 index 000000000..f410310ac --- /dev/null +++ b/tests/api/specs/hasura/graphql-introspection.spec.ts @@ -0,0 +1,51 @@ +import axios from "axios"; + +describe("GraphQL Introspection", () => { + const hasAdminSecret = Boolean(process.env.HASURA_GRAPHQL_ADMIN_SECRET); + + beforeAll(() => { + const requiredEnvVars = ["HASURA_GRAPHQL_URL"]; + + const missingEnvVars = requiredEnvVars.filter( + (envVar) => !process.env[envVar], + ); + + if (missingEnvVars.length > 0) { + throw new Error( + `Required environment variables are not set: ${missingEnvVars.join(", ")}`, + ); + } + }); + + it("rejects introspection queries from unauthenticated requests", async () => { + const response = await axios.post( + process.env.HASURA_GRAPHQL_URL!, + { query: "{ __schema { types { name } } }" }, + { + headers: { "Content-Type": "application/json" }, + validateStatus: () => true, + }, + ); + // Hasura returns 200 with an errors array when introspection is disabled + expect(response.data.errors).toBeDefined(); + expect(response.data.errors[0].message).toMatch(/introspection/i); + }); + + (hasAdminSecret ? it : it.skip)( + "allows introspection queries with the admin secret", + async () => { + const response = await axios.post( + process.env.HASURA_GRAPHQL_URL!, + { query: "{ __schema { types { name } } }" }, + { + headers: { + "Content-Type": "application/json", + "x-hasura-admin-secret": process.env.HASURA_GRAPHQL_ADMIN_SECRET!, + }, + }, + ); + expect(response.data.data.__schema).toBeDefined(); + expect(response.data.errors).toBeUndefined(); + }, + ); +});