Validate the subscription root
…not to be an introspection field.
This commit is contained in:
		@@ -137,25 +137,28 @@ singleFieldSubscriptionsRule :: forall m. Rule m
 | 
				
			|||||||
singleFieldSubscriptionsRule = OperationDefinitionRule $ \case
 | 
					singleFieldSubscriptionsRule = OperationDefinitionRule $ \case
 | 
				
			||||||
    Full.OperationDefinition Full.Subscription name' _ _ rootFields location' -> do
 | 
					    Full.OperationDefinition Full.Subscription name' _ _ rootFields location' -> do
 | 
				
			||||||
        groupedFieldSet <- evalStateT (collectFields rootFields) HashSet.empty
 | 
					        groupedFieldSet <- evalStateT (collectFields rootFields) HashSet.empty
 | 
				
			||||||
        case HashSet.size groupedFieldSet of
 | 
					        case HashSet.toList groupedFieldSet of
 | 
				
			||||||
            1 -> lift mempty
 | 
					            [rootName]
 | 
				
			||||||
            _
 | 
					                | Text.isPrefixOf "__" rootName -> makeError location' name'
 | 
				
			||||||
                | Just name <- name' -> pure $ Error
 | 
					                    "exactly one top level field, which must not be an introspection field."
 | 
				
			||||||
                    { message = concat
 | 
					                | otherwise -> lift mempty
 | 
				
			||||||
                        [ "Subscription \""
 | 
					            [] -> makeError location' name' "exactly one top level field."
 | 
				
			||||||
                        , Text.unpack name
 | 
					            _ -> makeError location' name' "only one top level field."
 | 
				
			||||||
                        , "\" must select only one top level field."
 | 
					 | 
				
			||||||
                        ]
 | 
					 | 
				
			||||||
                    , locations = [location']
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                | otherwise -> pure $ Error
 | 
					 | 
				
			||||||
                    { message = errorMessage
 | 
					 | 
				
			||||||
                    , locations = [location']
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
    _ -> lift mempty
 | 
					    _ -> lift mempty
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
    errorMessage =
 | 
					    makeError location' (Just operationName) errorLine = pure $ Error
 | 
				
			||||||
        "Anonymous Subscription must select only one top level field."
 | 
					        { message = concat
 | 
				
			||||||
 | 
					            [ "Subscription \""
 | 
				
			||||||
 | 
					            , Text.unpack operationName
 | 
				
			||||||
 | 
					            , "\" must select "
 | 
				
			||||||
 | 
					            , errorLine
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        , locations = [location']
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    makeError location' Nothing errorLine = pure $ Error
 | 
				
			||||||
 | 
					        { message = "Anonymous Subscription must select " <> errorLine
 | 
				
			||||||
 | 
					        , locations = [location']
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    collectFields = foldM forEach HashSet.empty
 | 
					    collectFields = foldM forEach HashSet.empty
 | 
				
			||||||
    forEach accumulator = \case
 | 
					    forEach accumulator = \case
 | 
				
			||||||
        Full.FieldSelection fieldSelection -> forField accumulator fieldSelection
 | 
					        Full.FieldSelection fieldSelection -> forField accumulator fieldSelection
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ import qualified Language.GraphQL.AST.DirectiveLocation as DirectiveLocation
 | 
				
			|||||||
import qualified Language.GraphQL.Type.In as In
 | 
					import qualified Language.GraphQL.Type.In as In
 | 
				
			||||||
import qualified Language.GraphQL.Type.Out as Out
 | 
					import qualified Language.GraphQL.Type.Out as Out
 | 
				
			||||||
import Language.GraphQL.Validate
 | 
					import Language.GraphQL.Validate
 | 
				
			||||||
import Test.Hspec (Spec, context, describe, it, shouldBe, shouldContain, xit)
 | 
					import Test.Hspec (Spec, context, describe, it, shouldBe, shouldContain)
 | 
				
			||||||
import Text.Megaparsec (parse, errorBundlePretty)
 | 
					import Text.Megaparsec (parse, errorBundlePretty)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
petSchema :: Schema IO
 | 
					petSchema :: Schema IO
 | 
				
			||||||
@@ -206,14 +206,14 @@ spec =
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                 in validate queryString `shouldContain` [expected]
 | 
					                 in validate queryString `shouldContain` [expected]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            xit "rejects an introspection field as the subscription root" $
 | 
					            it "rejects an introspection field as the subscription root" $
 | 
				
			||||||
                let queryString = "subscription sub {\n\
 | 
					                let queryString = "subscription sub {\n\
 | 
				
			||||||
                        \  __typename\n\
 | 
					                        \  __typename\n\
 | 
				
			||||||
                        \}"
 | 
					                        \}"
 | 
				
			||||||
                    expected = Error
 | 
					                    expected = Error
 | 
				
			||||||
                        { message =
 | 
					                        { message =
 | 
				
			||||||
                            "Subscription \"sub\" must select only one top \
 | 
					                            "Subscription \"sub\" must select exactly one top \
 | 
				
			||||||
                            \level field."
 | 
					                            \level field, which must not be an introspection field."
 | 
				
			||||||
                        , locations = [AST.Location 1 1]
 | 
					                        , locations = [AST.Location 1 1]
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                 in validate queryString `shouldContain` [expected]
 | 
					                 in validate queryString `shouldContain` [expected]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user