graphql-engine-1.0.0: GraphQL API over Postgres
Safe HaskellNone
LanguageHaskell2010

Hasura.RQL.DDL.RemoteSchema.Permission

Description

Remote Schema Permissions Validation

This module parses the GraphQL IDL (Schema Document) that's provided by the user for configuring permissions for remote schemas to a schema introspection object, which is then used to construct the remote schema for the particular role.

This module does two things essentially:

  1. Checks if the given schema document is a subset of the upstream remote schema document. This is done by checking if all the objects, interfaces, unions, enums, scalars and input objects provided in the schema document exist in the upstream remote schema too. We validate the fields, directives and arguments too, wherever applicable.
  2. Parse the preset directives (if any) on input object fields or argument fields. A preset directive is used to specify any preset argument on a field, it can be either a static value or session variable value. There is some validation done on preset directives. For example: - Preset directives can only be specified at ARGUMENT_DEFINITION or INPUT_FIELD_DEFINITION - A field expecting object cannot have a scalar/enum preset directive and vice versa.

If a preset directive value is a session variable (like `x-hasura-*`), then it's considered to be a session variable value. In the case, the user wants to treat the session variable value literally, they can add the static key to the preset directive to indicate that the value provided should be considered literally. For example:

`user(id: Int @preset(value: "x-hasura-user-id", static: true))

In this case `x-hasura-user-id` will be considered literally.

For validation, we use the MonadValidate monad transformer to collect as many errors as possible and then report all those errors at one go to the user.

Synopsis

Documentation

data PresetInputTypeInfo Source #

Constructors

PresetScalar Name 
PresetEnum Name [EnumValue] 
PresetInputObject [InputValueDefinition] 

data RoleBasedSchemaValidationError Source #

Constructors

NonMatchingType Name GraphQLType GType GType

error to indicate that a type provided by the user differs from the corresponding type defined in the upstream remote schema

TypeDoesNotExist GraphQLType Name

error to indicate when a type definition doesn't exist in the upstream remote schema

NonMatchingDefaultValue Name Name (Maybe (Value Void)) (Maybe (Value Void))

error to indicate when the default value of an argument differs from the default value of the corresponding argument

NonExistingInputArgument Name Name

error to indicate when a given input argument doesn't exist in the corresponding upstream input object

MissingNonNullableArguments Name (NonEmpty Name) 
NonExistingDirectiveArgument Name GraphQLType Name (NonEmpty Name)

error to indicate when a given directive argument doesn't exist in the corresponding upstream directive

NonExistingField (FieldDefinitionType, Name) Name

error to indicate when a given field doesn't exist in a field type (Object/Interface)

NonExistingUnionMemberTypes Name (NonEmpty Name)

error to indicate when member types of an Union don't exist in the corresponding upstream union

CustomInterfacesNotAllowed Name (NonEmpty Name)

error to indicate when an object is trying to implement an interface which exists in the schema document but the interface doesn't exist in the upstream remote.

ObjectImplementsNonExistingInterfaces Name (NonEmpty Name)

error to indicate when object implements interfaces that don't exist

NonExistingEnumValues Name (NonEmpty Name)

error to indicate enum values in an enum do not exist in the corresponding upstream enum

MultipleSchemaDefinitionsFound

error to indicate when the user provided schema contains more than one schema definition

MissingQueryRoot

error to indicate when the schema definition doesn't contain the query root.

DuplicateTypeNames (NonEmpty Name) 
DuplicateDirectives (GraphQLType, Name) (NonEmpty Name) 
DuplicateFields (FieldDefinitionType, Name) (NonEmpty Name) 
DuplicateArguments Name (NonEmpty Name) 
DuplicateEnumValues Name (NonEmpty Name) 
InvalidPresetDirectiveLocation 
MultiplePresetDirectives (GraphQLType, Name) 
NoPresetArgumentFound 
InvalidPresetArgument Name 
ExpectedInputTypeButGotOutputType Name 
EnumValueNotFound Name Name 
ExpectedEnumValue Name (Value Void) 
KeyDoesNotExistInInputObject Name Name 
ExpectedInputObject Name (Value Void) 
ExpectedScalarValue Name (Value Void) 
DisallowSessionVarForListType Name 
InvalidStaticValue 
UnexpectedNonMatchingNames Name Name GraphQLType

Error to indicate we're comparing non corresponding type definitions. Ideally, this error will never occur unless there's a programming error

lookupInputType :: SchemaDocument -> Name -> Maybe PresetInputTypeInfo Source #

parsePresetValue :: forall m. (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => GType -> Name -> Bool -> Value Void -> m (Value RemoteSchemaVariable) Source #

parsePresetValue constructs a GraphQL value when an input value definition contains a preset with it. This function checks if the given preset value is a legal value to the field that's specified it. For example: A scalar input value cannot contain an input object value. When the preset value is a session variable, we treat it as a session variable whose value will be resolved while the query is executed. In the case of session variables preset, we make the GraphQL value as a Variable value and during the execution we resolve all these "session variable" variable(s) and then query the remote server.

parsePresetDirective :: forall m. (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => GType -> Name -> Directive Void -> m (Value RemoteSchemaVariable) Source #

validateDirective Source #

Arguments

:: MonadValidate [RoleBasedSchemaValidationError] m 
=> Directive a

provided directive

-> Directive a

upstream directive

-> (GraphQLType, Name)

parent type and name

-> m () 

validateDirective checks if the arguments of a given directive is a subset of the corresponding upstream directive arguments *NOTE*: This function assumes that the providedDirective and the upstreamDirective have the same name.

validateDirectives :: MonadValidate [RoleBasedSchemaValidationError] m => [Directive a] -> [Directive a] -> TypeSystemDirectiveLocation -> (GraphQLType, Name) -> m (Maybe (Directive a)) Source #

validateDirectives checks if the providedDirectives are a subset of upstreamDirectives and then validate each of the directives by calling the validateDirective

validateEnumTypeDefinition Source #

Arguments

:: MonadValidate [RoleBasedSchemaValidationError] m 
=> EnumTypeDefinition

provided enum type definition

-> EnumTypeDefinition

upstream enum type definition

-> m EnumTypeDefinition 

validateEnumTypeDefinition checks the validity of an enum definition provided by the user against the corresponding upstream enum. The function does the following things: 1. Validates the directives (if any) 2. For each enum provided, check if the enum values are a subset of the enum values of the corresponding upstream enum *NOTE*: This function assumes that the providedEnum and the upstreamEnum have the same name.

validateInputValueDefinition :: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => InputValueDefinition -> InputValueDefinition -> Name -> m RemoteSchemaInputValueDefinition Source #

validateInputValueDefinition validates a given input value definition , against the corresponding upstream input value definition. Two things are validated to do the same, the type and the default value of the input value definitions should be equal.

validateArguments :: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => ArgumentsDefinition InputValueDefinition -> ArgumentsDefinition RemoteSchemaInputValueDefinition -> Name -> m [RemoteSchemaInputValueDefinition] Source #

validateArguments validates the provided arguments against the corresponding upstream remote schema arguments.

validateInputObjectTypeDefinition :: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => InputObjectTypeDefinition InputValueDefinition -> InputObjectTypeDefinition RemoteSchemaInputValueDefinition -> m (InputObjectTypeDefinition RemoteSchemaInputValueDefinition) Source #

validateFieldDefinition :: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => FieldDefinition InputValueDefinition -> FieldDefinition RemoteSchemaInputValueDefinition -> (FieldDefinitionType, Name) -> m (FieldDefinition RemoteSchemaInputValueDefinition) Source #

validateFieldDefinitions Source #

Arguments

:: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) 
=> [FieldDefinition InputValueDefinition] 
-> [FieldDefinition RemoteSchemaInputValueDefinition] 
-> (FieldDefinitionType, Name)

parent type and name

-> m [FieldDefinition RemoteSchemaInputValueDefinition] 

validateInterfaceDefinition :: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => InterfaceTypeDefinition () InputValueDefinition -> InterfaceTypeDefinition [Name] RemoteSchemaInputValueDefinition -> m (InterfaceTypeDefinition () RemoteSchemaInputValueDefinition) Source #

validateScalarDefinition :: MonadValidate [RoleBasedSchemaValidationError] m => ScalarTypeDefinition -> ScalarTypeDefinition -> m ScalarTypeDefinition Source #

validateUnionDefinition :: MonadValidate [RoleBasedSchemaValidationError] m => UnionTypeDefinition -> UnionTypeDefinition -> m UnionTypeDefinition Source #

validateObjectDefinition Source #

Arguments

:: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) 
=> ObjectTypeDefinition InputValueDefinition 
-> ObjectTypeDefinition RemoteSchemaInputValueDefinition 
-> HashSet Name

Interfaces declared by in the role-based schema

-> m (ObjectTypeDefinition RemoteSchemaInputValueDefinition) 

validateSchemaDefinitions :: MonadValidate [RoleBasedSchemaValidationError] m => [SchemaDefinition] -> m (Maybe Name, Maybe Name, Maybe Name) Source #

helper function to validate the schema definitions mentioned in the schema document.

createPossibleTypesMap :: [ObjectTypeDefinition RemoteSchemaInputValueDefinition] -> HashMap Name [Name] Source #

Construction of the possibleTypes map for interfaces, while parsing the user provided Schema document, it doesn't include the possibleTypes, so constructing here, manually.

partitionTypeSystemDefinitions :: [TypeSystemDefinition] -> ([SchemaDefinition], [TypeDefinition () InputValueDefinition]) Source #

getSchemaDocIntrospection :: [TypeDefinition () RemoteSchemaInputValueDefinition] -> (Maybe Name, Maybe Name, Maybe Name) -> IntrospectionResult Source #

getSchemaDocIntrospection converts the PartitionedTypeDefinitions to IntrospectionResult because the function buildRemoteParser function which builds the remote schema parsers accepts an IntrospectionResult. The conversion involves converting `G.TypeDefinition ()` to `G.TypeDefinition [G.Name]`. The `[G.Name]` here being the list of object names that an interface implements. This is needed to be done here by-hand because while specifying the SchemaDocument through the GraphQL DSL, it doesn't include the possibleTypes along with an object.

validateRemoteSchema :: (MonadValidate [RoleBasedSchemaValidationError] m, MonadReader SchemaDocument m) => RemoteSchemaIntrospection -> m IntrospectionResult Source #

validateRemoteSchema accepts two arguments, the SchemaDocument of the role-based schema, that is provided by the user and the SchemaIntrospection of the upstream remote schema. This function, in turn calls the other validation functions for scalars, enums, unions, interfaces,input objects and objects.