From 7a1f3f53f4fa00206cbe47f6b9ae52717c2a83a8 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Thu, 21 Feb 2019 16:04:37 +0530 Subject: [PATCH 1/8] Add flag/EnvVar to enable/disable RQL/GraphQL interfaces --- server/src-exec/Main.hs | 5 +- server/src-lib/Hasura/Server/App.hs | 83 ++++++++++++++++------------ server/src-lib/Hasura/Server/Init.hs | 38 ++++++++++++- 3 files changed, 88 insertions(+), 38 deletions(-) diff --git a/server/src-exec/Main.hs b/server/src-exec/Main.hs index c7b2d068c0703..db8f7907e5b91 100644 --- a/server/src-exec/Main.hs +++ b/server/src-exec/Main.hs @@ -71,6 +71,7 @@ parseHGECommand = <*> parseCorsConfig <*> parseEnableConsole <*> parseEnableTelemetry + <*> parseAllowedIFaces parseArgs :: IO HGEOptions parseArgs = do @@ -101,7 +102,7 @@ main = do let logger = mkLogger loggerCtx case hgeCmd of HCServe so@(ServeOptions port host cp isoL mAdminSecret mAuthHook mJwtSecret - mUnAuthRole corsCfg enableConsole enableTelemetry) -> do + mUnAuthRole corsCfg enableConsole enableTelemetry allowedIFaces) -> do -- log serve options unLogger logger $ serveOptsToLog so hloggerCtx <- mkLoggerCtx $ defaultLoggerSettings False @@ -123,7 +124,7 @@ main = do pool <- Q.initPGPool ci cp (app, cacheRef) <- mkWaiApp isoL loggerCtx pool httpManager - am corsCfg enableConsole enableTelemetry + am corsCfg enableConsole enableTelemetry allowedIFaces let warpSettings = Warp.setPort port $ Warp.setHost host Warp.defaultSettings diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index be3028a59b6eb..8263287e09704 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -19,6 +19,7 @@ import qualified Data.ByteString.Lazy as BL import qualified Data.FileEmbed as FE #endif import qualified Data.HashMap.Strict as M +import qualified Data.HashSet as S import qualified Data.Text as T import qualified Network.HTTP.Client as HTTP import qualified Network.HTTP.Types as N @@ -89,13 +90,14 @@ mkConsoleHTML path authMode enableTelemetry = data ServerCtx = ServerCtx - { scIsolation :: Q.TxIsolation - , scPGPool :: Q.PGPool - , scLogger :: L.Logger - , scCacheRef :: IORef SchemaCache - , scCacheLock :: MVar () - , scAuthMode :: AuthMode - , scManager :: HTTP.Manager + { scIsolation :: Q.TxIsolation + , scPGPool :: Q.PGPool + , scLogger :: L.Logger + , scCacheRef :: IORef SchemaCache + , scCacheLock :: MVar () + , scAuthMode :: AuthMode + , scManager :: HTTP.Manager + , scAllowedIFaces :: S.HashSet ServerIFace } data HandlerCtx @@ -108,6 +110,12 @@ data HandlerCtx type Handler = ExceptT QErr (ReaderT HandlerCtx IO) +isRQLEnabled :: ServerCtx -> Bool +isRQLEnabled sc = S.member RQL $ scAllowedIFaces sc + +isGraphQLEnabled :: ServerCtx -> Bool +isGraphQLEnabled sc = S.member GRAPHQL $ scAllowedIFaces sc + -- {-# SCC parseBody #-} parseBody :: (FromJSON a) => Handler a parseBody = do @@ -289,8 +297,9 @@ mkWaiApp -> CorsConfig -> Bool -> Bool + -> S.HashSet ServerIFace -> IO (Wai.Application, IORef SchemaCache) -mkWaiApp isoLevel loggerCtx pool httpManager mode corsCfg enableConsole enableTelemetry = do +mkWaiApp isoLevel loggerCtx pool httpManager mode corsCfg enableConsole enableTelemetry ifaces = do cacheRef <- do pgResp <- runExceptT $ peelRun emptySchemaCache adminUserInfo httpManager pool Q.Serializable buildSchemaCache @@ -300,7 +309,7 @@ mkWaiApp isoLevel loggerCtx pool httpManager mode corsCfg enableConsole enableTe let serverCtx = ServerCtx isoLevel pool (L.mkLogger loggerCtx) cacheRef - cacheLock mode httpManager + cacheLock mode httpManager ifaces spockApp <- spockAsApp $ spockT id $ httpApp corsCfg serverCtx enableConsole enableTelemetry @@ -318,41 +327,45 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do middleware $ corsMiddleware (mkDefaultCorsPolicy corsCfg) -- API Console and Root Dir - when enableConsole serveApiConsole + when (enableConsole && enableRQL) serveApiConsole get "v1/version" $ do uncurry setHeader jsonHeader lazyBytes $ encode $ object [ "version" .= currentVersion ] - get ("v1/template" var) tmpltGetOrDeleteH - post ("v1/template" var) tmpltPutOrPostH - put ("v1/template" var) tmpltPutOrPostH - delete ("v1/template" var) tmpltGetOrDeleteH - - post "v1/query" $ mkSpockAction encodeQErr serverCtx $ do - query <- parseBody - v1QueryHandler query - - post "v1alpha1/graphql/explain" $ mkSpockAction encodeQErr serverCtx $ do - expQuery <- parseBody - gqlExplainHandler expQuery - - post "v1alpha1/graphql" $ mkSpockAction GH.encodeGQErr serverCtx $ do - query <- parseBody - v1Alpha1GQHandler query - - -- get "v1alpha1/graphql/schema" $ - -- mkSpockAction encodeQErr serverCtx v1Alpha1GQSchemaHandler - - post ("api/1/table" var var) $ \tableName queryType -> - mkSpockAction encodeQErr serverCtx $ - legacyQueryHandler (TableName tableName) queryType - - hookAny GET $ \_ -> do + when enableRQL $ do + get ("v1/template" var) tmpltGetOrDeleteH + post ("v1/template" var) tmpltPutOrPostH + put ("v1/template" var) tmpltPutOrPostH + delete ("v1/template" var) tmpltGetOrDeleteH + + post "v1/query" $ mkSpockAction encodeQErr serverCtx $ do + query <- parseBody + v1QueryHandler query + + when enableGraphQL $ do + post "v1alpha1/graphql/explain" $ mkSpockAction encodeQErr serverCtx $ do + expQuery <- parseBody + gqlExplainHandler expQuery + + post "v1alpha1/graphql" $ mkSpockAction GH.encodeGQErr serverCtx $ do + query <- parseBody + v1Alpha1GQHandler query + + -- get "v1alpha1/graphql/schema" $ + -- mkSpockAction encodeQErr serverCtx v1Alpha1GQSchemaHandler + when enableRQL $ do + post ("api/1/table" var var) $ \tableName queryType -> + mkSpockAction encodeQErr serverCtx $ + legacyQueryHandler (TableName tableName) queryType + + forM_ [GET,POST] $ \m -> hookAny m $ \_ -> do let qErr = err404 NotFound "resource does not exist" raiseGenericApiError qErr where + enableGraphQL = isGraphQLEnabled serverCtx + enableRQL = isRQLEnabled serverCtx tmpltGetOrDeleteH tmpltName = do tmpltArgs <- tmpltArgsFromQueryParams mkSpockAction encodeQErr serverCtx $ mkQTemplateAction tmpltName tmpltArgs diff --git a/server/src-lib/Hasura/Server/Init.hs b/server/src-lib/Hasura/Server/Init.hs index b486ade38f7ad..6ded0f7f6c812 100644 --- a/server/src-lib/Hasura/Server/Init.hs +++ b/server/src-lib/Hasura/Server/Init.hs @@ -7,6 +7,7 @@ import System.Exit (exitFailure) import qualified Data.Aeson as J import qualified Data.String as DataString +import qualified Data.HashSet as Set import qualified Data.Text as T import qualified Text.PrettyPrint.ANSI.Leijen as PP @@ -47,6 +48,7 @@ data RawServeOptions , rsoCorsConfig :: !(Maybe CorsConfig) , rsoEnableConsole :: !Bool , rsoEnableTelemetry :: !(Maybe Bool) + , rsoAllowedIFaces :: !(Maybe [ServerIFace]) } deriving (Show, Eq) data ServeOptions @@ -62,6 +64,7 @@ data ServeOptions , soCorsConfig :: !CorsConfig , soEnableConsole :: !Bool , soEnableTelemetry :: !Bool + , soAllowedIFaces :: !(Set.HashSet ServerIFace) } deriving (Show, Eq) data RawConnInfo = @@ -83,6 +86,13 @@ data HGECommandG a | HCVersion deriving (Show, Eq) +data ServerIFace + = RQL + | GRAPHQL + deriving (Show, Eq, Read, Generic) + +instance Hashable ServerIFace + type HGECommand = HGECommandG ServeOptions type RawHGECommand = HGECommandG RawServeOptions @@ -130,6 +140,9 @@ instance FromEnv Q.TxIsolation where instance FromEnv CorsConfig where fromEnv = readCorsDomains +instance FromEnv [ServerIFace] where + fromEnv = mapM (readServerIFace . T.unpack) . T.splitOn "," . T.pack + parseStrAsBool :: String -> Either String Bool parseStrAsBool t | t `elem` truthVals = Right True @@ -226,9 +239,11 @@ mkServeOptions rso = do fst enableConsoleEnv enableTelemetry <- fromMaybe True <$> withEnv (rsoEnableTelemetry rso) (fst enableTelemetryEnv) + allowedIFaces <- Set.fromList . fromMaybe [RQL,GRAPHQL] <$> + withEnv (rsoAllowedIFaces rso) (fst allowedIFacesEnv) return $ ServeOptions port host connParams txIso adminScrt authHook jwtSecret - unAuthRole corsCfg enableConsole enableTelemetry + unAuthRole corsCfg enableConsole enableTelemetry allowedIFaces where mkConnParams (RawConnParams s c i p) = do stripes <- fromMaybe 1 <$> withEnv s (fst pgStripesEnv) @@ -442,6 +457,13 @@ enableTelemetryEnv = , "Enable anonymous telemetry (default: true)" ) +allowedIFacesEnv :: (String,String) +allowedIFacesEnv = + ( "HASURA_GRAPHQL_ALLOWED_INTERFACES" + -- TODO: better description + , "List of comma separated allowed interfaces. (default: rql,graphql)" + ) + parseRawConnInfo :: Parser RawConnInfo parseRawConnInfo = RawConnInfo <$> host <*> port <*> user <*> password @@ -584,6 +606,12 @@ readHookType tyS = "POST" -> Right AHTPost _ -> Left "Only expecting GET / POST" +readServerIFace :: String -> Either String ServerIFace +readServerIFace si = case T.toUpper $ T.strip $ T.pack si of + "RQL" -> Right RQL + "GRAPHQL" -> Right GRAPHQL + _ -> Left "Only expecting interface types RQL / GRAPHQL" + parseWebHook :: Parser RawAuthHook parseWebHook = AuthHookG <$> url <*> urlType @@ -652,6 +680,14 @@ parseEnableTelemetry = optional $ help (snd enableTelemetryEnv) ) +parseAllowedIFaces :: Parser (Maybe [ServerIFace]) +parseAllowedIFaces = fmap (\x -> bool (Just x) Nothing $ null x ) $ many $ + option (eitherReader readServerIFace) + ( long "interface" <> + help "Name of interface to be enabled. Accepts RQL / GRAPHQL" + ) + + -- Init logging related connInfoToLog :: Q.ConnInfo -> StartupLog connInfoToLog (Q.ConnInfo host port user _ db _) = From 4e0a20fe572021a41bd9c2fb3dfc91d26ba50da1 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Fri, 22 Feb 2019 11:33:29 +0530 Subject: [PATCH 2/8] Tests for enabling/disabling RQL/GraphQL interfaces --- .circleci/test-server.sh | 81 +++++++++++++------ server/tests-py/conftest.py | 14 +++- server/tests-py/context.py | 22 +++-- .../introspection_only_kind_of_queryType.yaml | 17 ++++ server/tests-py/test_schema_stitching.py | 4 +- server/tests-py/test_server_interfaces.py | 57 +++++++++++++ server/tests-py/validate.py | 6 +- 7 files changed, 162 insertions(+), 39 deletions(-) create mode 100644 server/tests-py/queries/graphql_introspection/introspection_only_kind_of_queryType.yaml create mode 100644 server/tests-py/test_server_interfaces.py diff --git a/.circleci/test-server.sh b/.circleci/test-server.sh index 0517e443544a3..bb94d3da70ffa 100755 --- a/.circleci/test-server.sh +++ b/.circleci/test-server.sh @@ -66,6 +66,12 @@ combine_hpc_reports() { rm graphql-engine.tix || true } +kill_hge_and_combine_hpc_reports() { + kill -INT $PID + wait $PID || true + combine_hpc_reports +} + if [ -z "${HASURA_GRAPHQL_DATABASE_URL:-}" ] ; then echo "Env var HASURA_GRAPHQL_DATABASE_URL is not set" exit 1 @@ -147,9 +153,7 @@ wait_for_port 8080 pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" -kill -INT $PID -sleep 4 -combine_hpc_reports +kill_hge_and_combine_hpc_reports ########## echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ADMIN SECRET AND JWT #####################################>\n" @@ -162,9 +166,7 @@ export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jw pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" -kill -INT $PID -sleep 4 -combine_hpc_reports +kill_hge_and_combine_hpc_reports unset HASURA_GRAPHQL_JWT_SECRET @@ -176,9 +178,7 @@ export HASURA_GRAPHQL_JWT_SECRET="$(jq -n --arg key "$(cat $OUTPUT_FOLDER/ssl/jw pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" test_jwt.py -kill -INT $PID -sleep 4 -combine_hpc_reports +kill_hge_and_combine_hpc_reports unset HASURA_GRAPHQL_JWT_SECRET @@ -193,11 +193,50 @@ wait_for_port 8080 pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-cors test_cors.py -kill -INT $PID -sleep 4 -combine_hpc_reports +kill_hge_and_combine_hpc_reports + unset HASURA_GRAPHQL_CORS_DOMAIN +echo -e "\n<########## TEST GRAPHQL-ENGINE WITH GRAPHQL DISABLED ########>\n" + +export HASURA_GRAPHQL_ALLOWED_INTERFACES="rql" + +"$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! + +wait_for_port 8080 + +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-graphql-disabled test_server_interfaces.py + +kill_hge_and_combine_hpc_reports + +unset HASURA_GRAPHQL_ALLOWED_INTERFACES + +"$GRAPHQL_ENGINE" serve --interface rql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! + +wait_for_port 8080 + +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-graphql-disabled test_server_interfaces.py + +kill_hge_and_combine_hpc_reports + +echo -e "\n<########## TEST GRAPHQL-ENGINE WITH RQL DISABLED ########>\n" + +export HASURA_GRAPHQL_ALLOWED_INTERFACES="graphql" + +"$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! + +wait_for_port 8080 + +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-rql-disabled test_server_interfaces.py + +kill_hge_and_combine_hpc_reports +unset HASURA_GRAPHQL_ALLOWED_INTERFACES + +"$GRAPHQL_ENGINE" serve --interface graphql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! + +wait_for_port 8080 + +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-rql-disabled test_server_interfaces.py # webhook tests @@ -223,25 +262,21 @@ if [ "$RUN_WEBHOOK_TESTS" == "true" ] ; then pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" - kill -INT $PID - sleep 4 - combine_hpc_reports + kill_hge_and_combine_hpc_reports echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ADMIN SECRET & WEBHOOK (POST) #########################>\n" export HASURA_GRAPHQL_AUTH_HOOK_MODE="POST" "$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! - wait_for_port 8080 + wait_for_port 8080 pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" rm /etc/ssl/certs/webhook.crt update-ca-certificates - kill -INT $PID - sleep 4 - combine_hpc_reports + kill_hge_and_combine_hpc_reports echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ADMIN SECRET & HTTPS INSECURE WEBHOOK (GET) ########>\n" export HASURA_GRAPHQL_AUTH_HOOK_MODE="GET" @@ -252,9 +287,7 @@ if [ "$RUN_WEBHOOK_TESTS" == "true" ] ; then pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" --test-webhook-insecure test_webhook_insecure.py - kill -INT $PID - sleep 4 - combine_hpc_reports + kill_hge_and_combine_hpc_reports echo -e "\n<########## TEST GRAPHQL-ENGINE WITH ADMIN_SECRET & HTTPS INSECURE WEBHOOK (POST) ########>\n" export HASURA_GRAPHQL_AUTH_HOOK_MODE="POST" @@ -265,9 +298,7 @@ if [ "$RUN_WEBHOOK_TESTS" == "true" ] ; then pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" --test-webhook-insecure test_webhook_insecure.py - kill -INT $PID - sleep 4 - combine_hpc_reports + kill_hge_and_combine_hpc_reports kill $WH_PID diff --git a/server/tests-py/conftest.py b/server/tests-py/conftest.py index 55b88b42ccdfd..b77e9dd334335 100644 --- a/server/tests-py/conftest.py +++ b/server/tests-py/conftest.py @@ -33,6 +33,16 @@ def pytest_addoption(parser): help="Run testcases for CORS configuration" ) + parser.addoption( + "--test-rql-disabled", action="store_true", + help="Run Test cases with RQL queries being disabled" + ) + + parser.addoption( + "--test-graphql-disabled", action="store_true", + help="Run Test cases with GraphQL queries being disabled" + ) + @pytest.fixture(scope='session') def hge_ctx(request): @@ -45,6 +55,7 @@ def hge_ctx(request): hge_jwt_key_file = request.config.getoption('--hge-jwt-key-file') hge_jwt_conf = request.config.getoption('--hge-jwt-conf') test_cors = request.config.getoption('--test-cors') + rql_disabled = request.config.getoption('--test-rql-disabled') try: hge_ctx = HGECtx( hge_url=hge_url, @@ -53,7 +64,8 @@ def hge_ctx(request): hge_webhook=hge_webhook, webhook_insecure=webhook_insecure, hge_jwt_key_file=hge_jwt_key_file, - hge_jwt_conf=hge_jwt_conf + hge_jwt_conf=hge_jwt_conf, + rql_disabled=rql_disabled ) except HGECtxError as e: pytest.exit(str(e)) diff --git a/server/tests-py/context.py b/server/tests-py/context.py index f52c163bad3ed..1ffd254aa66f5 100644 --- a/server/tests-py/context.py +++ b/server/tests-py/context.py @@ -74,7 +74,7 @@ def server_bind(self): class HGECtx: - def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_jwt_key_file, hge_jwt_conf): + def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_jwt_key_file, hge_jwt_conf, rql_disabled): server_address = ('0.0.0.0', 5592) self.resp_queue = queue.Queue(maxsize=1) @@ -99,6 +99,7 @@ def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_ self.hge_jwt_key = f.read() self.hge_jwt_conf = hge_jwt_conf self.webhook_insecure = webhook_insecure + self.rql_disabled = rql_disabled self.may_skip_test_teardown = False self.ws_url = urlparse(hge_url) @@ -116,12 +117,13 @@ def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_ result = subprocess.run(['../../scripts/get-version.sh'], shell=False, stdout=subprocess.PIPE, check=True) self.version = result.stdout.decode('utf-8').strip() - try: - st_code, resp = self.v1q_f('queries/clear_db.yaml') - except requests.exceptions.RequestException as e: - self.teardown() - raise HGECtxError(repr(e)) - assert st_code == 200, resp + if not self.rql_disabled: + try: + st_code, resp = self.v1q_f('queries/clear_db.yaml') + except requests.exceptions.RequestException as e: + self.teardown() + raise HGECtxError(repr(e)) + assert st_code == 200, resp def _on_message(self, message): my_json = json.loads(message) @@ -152,6 +154,12 @@ def anyq(self, u, q, h): ) return resp.status_code, resp.json() + def sql(self, q): + conn = self.engine.connect() + res = conn.execute(q) + conn.close() + return res + def v1q(self, q, headers = {}): h = headers.copy() if self.hge_key is not None: diff --git a/server/tests-py/queries/graphql_introspection/introspection_only_kind_of_queryType.yaml b/server/tests-py/queries/graphql_introspection/introspection_only_kind_of_queryType.yaml new file mode 100644 index 0000000000000..19397c9596dd0 --- /dev/null +++ b/server/tests-py/queries/graphql_introspection/introspection_only_kind_of_queryType.yaml @@ -0,0 +1,17 @@ +description: GraphQL introspection query which returns the kind of queryType. This output should be the same across any GraphQL implementation +url: /v1alpha1/graphql +status: 200 +response: + data: + __schema: + queryType: + kind: OBJECT +query: + query: | + query foo { + __schema { + queryType { + kind + } + } + } diff --git a/server/tests-py/test_schema_stitching.py b/server/tests-py/test_schema_stitching.py index b618b8def8d76..9318ace48c778 100644 --- a/server/tests-py/test_schema_stitching.py +++ b/server/tests-py/test_schema_stitching.py @@ -166,11 +166,9 @@ def transact(self, hge_ctx): def test_add_schema(self, hge_ctx): """ check if the remote schema is added in the db """ - conn = hge_ctx.engine.connect() - res = conn.execute('select * from hdb_catalog.remote_schemas') + res = hge_ctx.sql('select * from hdb_catalog.remote_schemas') row = res.fetchone() assert row['name'] == "simple2-graphql" - conn.close() def test_add_schema_conflicts_with_tables(self, hge_ctx): """add remote schema which conflicts with hasura tables""" diff --git a/server/tests-py/test_server_interfaces.py b/server/tests-py/test_server_interfaces.py new file mode 100644 index 0000000000000..d9c7a4fc7fb58 --- /dev/null +++ b/server/tests-py/test_server_interfaces.py @@ -0,0 +1,57 @@ +#!/usrbin/env python3 + +import pytest +from validate import check_query, check_query_f + +def check_post_404(hge_ctx,url): + return check_query(hge_ctx, { + 'url': url, + 'status': 404, + 'query': {} + }) + + +@pytest.mark.skipif(not pytest.config.getoption("--test-rql-disabled"), + reason="flag --test-rql-disabled is not set. Cannot run tests for RQL disabled") +class TestRQLDisabled: + + def test_rql_v1_query_disabled(self, hge_ctx): + check_post_404(hge_ctx,'/v1/query') + + def test_rql_v1_template_disabled(self, hge_ctx): + check_post_404(hge_ctx,'/v1/template/foo') + + def test_rql_api_1_disabled(self, hge_ctx): + check_post_404(hge_ctx,'/api/1/table/foo/select') + + +@pytest.mark.skipif(not pytest.config.getoption("--test-graphql-disabled"), + reason="--test-graphql-disabled is not set. Cannot run GraphQL disabled tests") +class TestGraphQLDisabled: + + def test_graphql_endpoint_disabled(self, hge_ctx): + check_post_404(hge_ctx,'/v1alpha1/graphql') + + def test_graphql_explain_disabled(self, hge_ctx): + check_post_404(hge_ctx,'/v1alpha1/graphql/explain') + + +@pytest.mark.skipif(pytest.config.getoption("--test-graphql-disabled"), + reason="--test-graphql-disabled is set. Cannot run GraphQL enabled tests") +class TestGraphQLEnabled: + + def test_graphql_introspection(self, hge_ctx): + check_query_f(hge_ctx, "queries/graphql_introspection/introspection_only_kind_of_queryType.yaml") + + +@pytest.mark.skipif(pytest.config.getoption("--test-rql-disabled"), + reason="--test-rql-disabled is set. Cannot run RQL enabled tests") +class TestRQLEnabled: + + def test_reload_metadata(self, hge_ctx): + check_query_f(hge_ctx, "queries/v1/metadata/reload_metadata.yaml") + + def test_run_sql(self, hge_ctx): + check_query_f(hge_ctx, "queries/v1/run_sql/sql_set_timezone.yaml") + + diff --git a/server/tests-py/validate.py b/server/tests-py/validate.py index 96acb2be89b24..ad0e7a96915a0 100644 --- a/server/tests-py/validate.py +++ b/server/tests-py/validate.py @@ -62,7 +62,7 @@ def test_forbidden_when_admin_secret_reqd(hge_ctx, conf): # Test without admin secret code, resp = hge_ctx.anyq(conf['url'], conf['query'], headers) - assert code == 401, "\n" + yaml.dump({ + assert code in [401,404], "\n" + yaml.dump({ "expected": "Should be access denied as admin secret is not provided", "actual": { "code": code, @@ -73,7 +73,7 @@ def test_forbidden_when_admin_secret_reqd(hge_ctx, conf): # Test with random admin secret headers['X-Hasura-Admin-Secret'] = base64.b64encode(os.urandom(30)) code, resp = hge_ctx.anyq(conf['url'], conf['query'], headers) - assert code == 401, "\n" + yaml.dump({ + assert code in [401,404], "\n" + yaml.dump({ "expected": "Should be access denied as an incorrect admin secret is provided", "actual": { "code": code, @@ -85,7 +85,7 @@ def test_forbidden_when_admin_secret_reqd(hge_ctx, conf): def test_forbidden_webhook(hge_ctx, conf): h = {'Authorization': 'Bearer ' + base64.b64encode(base64.b64encode(os.urandom(30))).decode('utf-8')} code, resp = hge_ctx.anyq(conf['url'], conf['query'], h) - assert code == 401, "\n" + yaml.dump({ + assert code in [401,404], "\n" + yaml.dump({ "expected": "Should be access denied as it is denied from webhook", "actual": { "code": code, From 97e4081f64c598a7f93d17bad4cde506d882a0b9 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Fri, 22 Feb 2019 14:28:25 +0530 Subject: [PATCH 3/8] Fix test-server.sh: Kill GraphQL after rql disabled test --- .circleci/test-server.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/test-server.sh b/.circleci/test-server.sh index bb94d3da70ffa..f39590ab388b8 100755 --- a/.circleci/test-server.sh +++ b/.circleci/test-server.sh @@ -238,6 +238,8 @@ wait_for_port 8080 pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-rql-disabled test_server_interfaces.py +kill_hge_and_combine_hpc_reports + # webhook tests if [ $EUID != 0 ] ; then From 1e334ff1b15284ed55b373ad7148c49b74eb0ca2 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Fri, 22 Feb 2019 15:10:34 +0530 Subject: [PATCH 4/8] Add docs for server interfaces flag/envVar --- .../manual/deployment/graphql-engine-flags/reference.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst index 413c7b75451f7..c3e2e124189cd 100644 --- a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst +++ b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst @@ -139,6 +139,13 @@ For ``serve`` sub-command these are the flags and ENV variables available: - ``HASURA_GRAPHQL_TX_ISOLATION`` - transaction isolation. read-committed / repeatable-read / serializable (default: read-commited) + * - ``--interface `` + - N/A + - Enable the given server interface. (default: Both RQL/GraphQL interfaces are enabled) + + * - N/A + - ``HASURA_GRAPHQL_ALLOWED_INTERFACES`` + - Comma separated list of allowed interfaces. (default: ``rql,graphql``) .. note:: When the equivalent flags for environment variables are used, the flags will take precedence. From f79043fd450dd001af0e2b88d8e6eed737351c24 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Tue, 26 Feb 2019 10:56:20 +0530 Subject: [PATCH 5/8] Change `allowed interfaces` to `enabled APIs` --- .circleci/test-server.sh | 12 ++--- .../graphql-engine-flags/reference.rst | 10 ++-- server/src-exec/Main.hs | 6 +-- server/src-lib/Hasura/Server/App.hs | 12 ++--- server/src-lib/Hasura/Server/Init.hs | 49 +++++++++---------- 5 files changed, 42 insertions(+), 47 deletions(-) diff --git a/.circleci/test-server.sh b/.circleci/test-server.sh index f39590ab388b8..dda30d3f98659 100755 --- a/.circleci/test-server.sh +++ b/.circleci/test-server.sh @@ -199,7 +199,7 @@ unset HASURA_GRAPHQL_CORS_DOMAIN echo -e "\n<########## TEST GRAPHQL-ENGINE WITH GRAPHQL DISABLED ########>\n" -export HASURA_GRAPHQL_ALLOWED_INTERFACES="rql" +export HASURA_GRAPHQL_ENABLED_APIS="rql" "$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! @@ -209,9 +209,9 @@ pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-ke kill_hge_and_combine_hpc_reports -unset HASURA_GRAPHQL_ALLOWED_INTERFACES +unset HASURA_GRAPHQL_ENABLED_APIS -"$GRAPHQL_ENGINE" serve --interface rql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! +"$GRAPHQL_ENGINE" serve --enabled-apis rql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! wait_for_port 8080 @@ -221,7 +221,7 @@ kill_hge_and_combine_hpc_reports echo -e "\n<########## TEST GRAPHQL-ENGINE WITH RQL DISABLED ########>\n" -export HASURA_GRAPHQL_ALLOWED_INTERFACES="graphql" +export HASURA_GRAPHQL_ENABLED_APIS="graphql" "$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! @@ -230,9 +230,9 @@ wait_for_port 8080 pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-rql-disabled test_server_interfaces.py kill_hge_and_combine_hpc_reports -unset HASURA_GRAPHQL_ALLOWED_INTERFACES +unset HASURA_GRAPHQL_ENABLED_APIS -"$GRAPHQL_ENGINE" serve --interface graphql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! +"$GRAPHQL_ENGINE" serve --enabled-apis graphql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! wait_for_port 8080 diff --git a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst index c3e2e124189cd..b8905d7d3ddb6 100644 --- a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst +++ b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst @@ -139,13 +139,9 @@ For ``serve`` sub-command these are the flags and ENV variables available: - ``HASURA_GRAPHQL_TX_ISOLATION`` - transaction isolation. read-committed / repeatable-read / serializable (default: read-commited) - * - ``--interface `` - - N/A - - Enable the given server interface. (default: Both RQL/GraphQL interfaces are enabled) - - * - N/A - - ``HASURA_GRAPHQL_ALLOWED_INTERFACES`` - - Comma separated list of allowed interfaces. (default: ``rql,graphql``) + * - ``--enabled-apis `` + - ``HASURA_GRAPHQL_ENABLED_APIS`` + - Comma separated list of APIs to be enabled. (default: ``rql,graphql``) .. note:: When the equivalent flags for environment variables are used, the flags will take precedence. diff --git a/server/src-exec/Main.hs b/server/src-exec/Main.hs index db8f7907e5b91..b5f72ab250b82 100644 --- a/server/src-exec/Main.hs +++ b/server/src-exec/Main.hs @@ -71,7 +71,7 @@ parseHGECommand = <*> parseCorsConfig <*> parseEnableConsole <*> parseEnableTelemetry - <*> parseAllowedIFaces + <*> parseEnabledAPIs parseArgs :: IO HGEOptions parseArgs = do @@ -102,7 +102,7 @@ main = do let logger = mkLogger loggerCtx case hgeCmd of HCServe so@(ServeOptions port host cp isoL mAdminSecret mAuthHook mJwtSecret - mUnAuthRole corsCfg enableConsole enableTelemetry allowedIFaces) -> do + mUnAuthRole corsCfg enableConsole enableTelemetry enabledAPIs) -> do -- log serve options unLogger logger $ serveOptsToLog so hloggerCtx <- mkLoggerCtx $ defaultLoggerSettings False @@ -124,7 +124,7 @@ main = do pool <- Q.initPGPool ci cp (app, cacheRef) <- mkWaiApp isoL loggerCtx pool httpManager - am corsCfg enableConsole enableTelemetry allowedIFaces + am corsCfg enableConsole enableTelemetry enabledAPIs let warpSettings = Warp.setPort port $ Warp.setHost host Warp.defaultSettings diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index 8263287e09704..1a2a2efcbe4f7 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -97,7 +97,7 @@ data ServerCtx , scCacheLock :: MVar () , scAuthMode :: AuthMode , scManager :: HTTP.Manager - , scAllowedIFaces :: S.HashSet ServerIFace + , scEnabledAPIs :: S.HashSet API } data HandlerCtx @@ -111,10 +111,10 @@ data HandlerCtx type Handler = ExceptT QErr (ReaderT HandlerCtx IO) isRQLEnabled :: ServerCtx -> Bool -isRQLEnabled sc = S.member RQL $ scAllowedIFaces sc +isRQLEnabled sc = S.member RQL $ scEnabledAPIs sc isGraphQLEnabled :: ServerCtx -> Bool -isGraphQLEnabled sc = S.member GRAPHQL $ scAllowedIFaces sc +isGraphQLEnabled sc = S.member GRAPHQL $ scEnabledAPIs sc -- {-# SCC parseBody #-} parseBody :: (FromJSON a) => Handler a @@ -297,9 +297,9 @@ mkWaiApp -> CorsConfig -> Bool -> Bool - -> S.HashSet ServerIFace + -> S.HashSet API -> IO (Wai.Application, IORef SchemaCache) -mkWaiApp isoLevel loggerCtx pool httpManager mode corsCfg enableConsole enableTelemetry ifaces = do +mkWaiApp isoLevel loggerCtx pool httpManager mode corsCfg enableConsole enableTelemetry apis = do cacheRef <- do pgResp <- runExceptT $ peelRun emptySchemaCache adminUserInfo httpManager pool Q.Serializable buildSchemaCache @@ -309,7 +309,7 @@ mkWaiApp isoLevel loggerCtx pool httpManager mode corsCfg enableConsole enableTe let serverCtx = ServerCtx isoLevel pool (L.mkLogger loggerCtx) cacheRef - cacheLock mode httpManager ifaces + cacheLock mode httpManager apis spockApp <- spockAsApp $ spockT id $ httpApp corsCfg serverCtx enableConsole enableTelemetry diff --git a/server/src-lib/Hasura/Server/Init.hs b/server/src-lib/Hasura/Server/Init.hs index 6ded0f7f6c812..800ac8d1b4851 100644 --- a/server/src-lib/Hasura/Server/Init.hs +++ b/server/src-lib/Hasura/Server/Init.hs @@ -48,7 +48,7 @@ data RawServeOptions , rsoCorsConfig :: !(Maybe CorsConfig) , rsoEnableConsole :: !Bool , rsoEnableTelemetry :: !(Maybe Bool) - , rsoAllowedIFaces :: !(Maybe [ServerIFace]) + , rsoEnabledAPIs :: !(Maybe [API]) } deriving (Show, Eq) data ServeOptions @@ -64,7 +64,7 @@ data ServeOptions , soCorsConfig :: !CorsConfig , soEnableConsole :: !Bool , soEnableTelemetry :: !Bool - , soAllowedIFaces :: !(Set.HashSet ServerIFace) + , soEnabledAPIs :: !(Set.HashSet API) } deriving (Show, Eq) data RawConnInfo = @@ -86,12 +86,12 @@ data HGECommandG a | HCVersion deriving (Show, Eq) -data ServerIFace +data API = RQL | GRAPHQL deriving (Show, Eq, Read, Generic) -instance Hashable ServerIFace +instance Hashable API type HGECommand = HGECommandG ServeOptions type RawHGECommand = HGECommandG RawServeOptions @@ -140,8 +140,8 @@ instance FromEnv Q.TxIsolation where instance FromEnv CorsConfig where fromEnv = readCorsDomains -instance FromEnv [ServerIFace] where - fromEnv = mapM (readServerIFace . T.unpack) . T.splitOn "," . T.pack +instance FromEnv [API] where + fromEnv = readAPIs parseStrAsBool :: String -> Either String Bool parseStrAsBool t @@ -239,11 +239,11 @@ mkServeOptions rso = do fst enableConsoleEnv enableTelemetry <- fromMaybe True <$> withEnv (rsoEnableTelemetry rso) (fst enableTelemetryEnv) - allowedIFaces <- Set.fromList . fromMaybe [RQL,GRAPHQL] <$> - withEnv (rsoAllowedIFaces rso) (fst allowedIFacesEnv) + enabledAPIs <- Set.fromList . fromMaybe [RQL,GRAPHQL] <$> + withEnv (rsoEnabledAPIs rso) (fst enabledAPIsEnv) return $ ServeOptions port host connParams txIso adminScrt authHook jwtSecret - unAuthRole corsCfg enableConsole enableTelemetry allowedIFaces + unAuthRole corsCfg enableConsole enableTelemetry enabledAPIs where mkConnParams (RawConnParams s c i p) = do stripes <- fromMaybe 1 <$> withEnv s (fst pgStripesEnv) @@ -457,11 +457,10 @@ enableTelemetryEnv = , "Enable anonymous telemetry (default: true)" ) -allowedIFacesEnv :: (String,String) -allowedIFacesEnv = - ( "HASURA_GRAPHQL_ALLOWED_INTERFACES" - -- TODO: better description - , "List of comma separated allowed interfaces. (default: rql,graphql)" +enabledAPIsEnv :: (String,String) +enabledAPIsEnv = + ( "HASURA_GRAPHQL_ENABLED_APIS" + , "List of comma separated list of allowed APIs. (default: rql,graphql)" ) parseRawConnInfo :: Parser RawConnInfo @@ -606,11 +605,12 @@ readHookType tyS = "POST" -> Right AHTPost _ -> Left "Only expecting GET / POST" -readServerIFace :: String -> Either String ServerIFace -readServerIFace si = case T.toUpper $ T.strip $ T.pack si of - "RQL" -> Right RQL - "GRAPHQL" -> Right GRAPHQL - _ -> Left "Only expecting interface types RQL / GRAPHQL" +readAPIs :: String -> Either String [API] +readAPIs = mapM readAPI . T.splitOn "," . T.pack + where readAPI si = case T.toUpper $ T.strip si of + "RQL" -> Right RQL + "GRAPHQL" -> Right GRAPHQL + _ -> Left "Only expecting list of comma separated API types RQL / GRAPHQL" parseWebHook :: Parser RawAuthHook parseWebHook = @@ -680,14 +680,13 @@ parseEnableTelemetry = optional $ help (snd enableTelemetryEnv) ) -parseAllowedIFaces :: Parser (Maybe [ServerIFace]) -parseAllowedIFaces = fmap (\x -> bool (Just x) Nothing $ null x ) $ many $ - option (eitherReader readServerIFace) - ( long "interface" <> - help "Name of interface to be enabled. Accepts RQL / GRAPHQL" +parseEnabledAPIs :: Parser (Maybe [API]) +parseEnabledAPIs = optional $ + option (eitherReader readAPIs) + ( long "enabled-apis" <> + help (snd enabledAPIsEnv) ) - -- Init logging related connInfoToLog :: Q.ConnInfo -> StartupLog connInfoToLog (Q.ConnInfo host port user _ db _) = From beed128d9b731230d9eff767aeefb31f9e80fed6 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Tue, 26 Feb 2019 11:33:36 +0530 Subject: [PATCH 6/8] Move all enableRQL queries to one block --- server/src-lib/Hasura/Server/App.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index 1a2a2efcbe4f7..8fb4a51022646 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -343,6 +343,10 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do query <- parseBody v1QueryHandler query + post ("api/1/table" var var) $ \tableName queryType -> + mkSpockAction encodeQErr serverCtx $ + legacyQueryHandler (TableName tableName) queryType + when enableGraphQL $ do post "v1alpha1/graphql/explain" $ mkSpockAction encodeQErr serverCtx $ do expQuery <- parseBody @@ -354,10 +358,6 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do -- get "v1alpha1/graphql/schema" $ -- mkSpockAction encodeQErr serverCtx v1Alpha1GQSchemaHandler - when enableRQL $ do - post ("api/1/table" var var) $ \tableName queryType -> - mkSpockAction encodeQErr serverCtx $ - legacyQueryHandler (TableName tableName) queryType forM_ [GET,POST] $ \m -> hookAny m $ \_ -> do let qErr = err404 NotFound "resource does not exist" From 676f21f094b033ef68e3eacc00ca1be1f70d96bd Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Tue, 26 Feb 2019 14:19:42 +0530 Subject: [PATCH 7/8] Change RQL To METADATA --- .circleci/test-server.sh | 14 +++++++------- .../graphql-engine-flags/reference.rst | 2 +- server/src-lib/Hasura/Server/App.hs | 10 +++++----- server/src-lib/Hasura/Server/Init.hs | 12 ++++++------ server/tests-py/conftest.py | 8 ++++---- server/tests-py/context.py | 6 +++--- ...ver_interfaces.py => test_apis_disabled.py} | 18 +++++++++--------- 7 files changed, 35 insertions(+), 35 deletions(-) rename server/tests-py/{test_server_interfaces.py => test_apis_disabled.py} (70%) diff --git a/.circleci/test-server.sh b/.circleci/test-server.sh index dda30d3f98659..82e3bb2cb0c5b 100755 --- a/.circleci/test-server.sh +++ b/.circleci/test-server.sh @@ -199,27 +199,27 @@ unset HASURA_GRAPHQL_CORS_DOMAIN echo -e "\n<########## TEST GRAPHQL-ENGINE WITH GRAPHQL DISABLED ########>\n" -export HASURA_GRAPHQL_ENABLED_APIS="rql" +export HASURA_GRAPHQL_ENABLED_APIS="metadata" "$GRAPHQL_ENGINE" serve >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! wait_for_port 8080 -pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-graphql-disabled test_server_interfaces.py +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-graphql-disabled test_apis_disabled.py kill_hge_and_combine_hpc_reports unset HASURA_GRAPHQL_ENABLED_APIS -"$GRAPHQL_ENGINE" serve --enabled-apis rql >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! +"$GRAPHQL_ENGINE" serve --enabled-apis metadata >> "$OUTPUT_FOLDER/graphql-engine.log" 2>&1 & PID=$! wait_for_port 8080 -pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-graphql-disabled test_server_interfaces.py +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-graphql-disabled test_apis_disabled.py kill_hge_and_combine_hpc_reports -echo -e "\n<########## TEST GRAPHQL-ENGINE WITH RQL DISABLED ########>\n" +echo -e "\n<########## TEST GRAPHQL-ENGINE WITH METADATA DISABLED ########>\n" export HASURA_GRAPHQL_ENABLED_APIS="graphql" @@ -227,7 +227,7 @@ export HASURA_GRAPHQL_ENABLED_APIS="graphql" wait_for_port 8080 -pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-rql-disabled test_server_interfaces.py +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-metadata-disabled test_apis_disabled.py kill_hge_and_combine_hpc_reports unset HASURA_GRAPHQL_ENABLED_APIS @@ -236,7 +236,7 @@ unset HASURA_GRAPHQL_ENABLED_APIS wait_for_port 8080 -pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-rql-disabled test_server_interfaces.py +pytest -vv --hge-url="$HGE_URL" --pg-url="$HASURA_GRAPHQL_DATABASE_URL" --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --test-metadata-disabled test_apis_disabled.py kill_hge_and_combine_hpc_reports diff --git a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst index b8905d7d3ddb6..db96ee0fc3f1a 100644 --- a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst +++ b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst @@ -141,7 +141,7 @@ For ``serve`` sub-command these are the flags and ENV variables available: * - ``--enabled-apis `` - ``HASURA_GRAPHQL_ENABLED_APIS`` - - Comma separated list of APIs to be enabled. (default: ``rql,graphql``) + - Comma separated list of APIs to be enabled. (default: ``metadata,graphql``) .. note:: When the equivalent flags for environment variables are used, the flags will take precedence. diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index 8fb4a51022646..35f5cb552e0a2 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -110,8 +110,8 @@ data HandlerCtx type Handler = ExceptT QErr (ReaderT HandlerCtx IO) -isRQLEnabled :: ServerCtx -> Bool -isRQLEnabled sc = S.member RQL $ scEnabledAPIs sc +isMetadataEnabled :: ServerCtx -> Bool +isMetadataEnabled sc = S.member METADATA $ scEnabledAPIs sc isGraphQLEnabled :: ServerCtx -> Bool isGraphQLEnabled sc = S.member GRAPHQL $ scEnabledAPIs sc @@ -327,13 +327,13 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do middleware $ corsMiddleware (mkDefaultCorsPolicy corsCfg) -- API Console and Root Dir - when (enableConsole && enableRQL) serveApiConsole + when (enableConsole && enableMetadata) serveApiConsole get "v1/version" $ do uncurry setHeader jsonHeader lazyBytes $ encode $ object [ "version" .= currentVersion ] - when enableRQL $ do + when enableMetadata $ do get ("v1/template" var) tmpltGetOrDeleteH post ("v1/template" var) tmpltPutOrPostH put ("v1/template" var) tmpltPutOrPostH @@ -365,7 +365,7 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do where enableGraphQL = isGraphQLEnabled serverCtx - enableRQL = isRQLEnabled serverCtx + enableMetadata = isMetadataEnabled serverCtx tmpltGetOrDeleteH tmpltName = do tmpltArgs <- tmpltArgsFromQueryParams mkSpockAction encodeQErr serverCtx $ mkQTemplateAction tmpltName tmpltArgs diff --git a/server/src-lib/Hasura/Server/Init.hs b/server/src-lib/Hasura/Server/Init.hs index 800ac8d1b4851..a855be14282d9 100644 --- a/server/src-lib/Hasura/Server/Init.hs +++ b/server/src-lib/Hasura/Server/Init.hs @@ -87,7 +87,7 @@ data HGECommandG a deriving (Show, Eq) data API - = RQL + = METADATA | GRAPHQL deriving (Show, Eq, Read, Generic) @@ -239,7 +239,7 @@ mkServeOptions rso = do fst enableConsoleEnv enableTelemetry <- fromMaybe True <$> withEnv (rsoEnableTelemetry rso) (fst enableTelemetryEnv) - enabledAPIs <- Set.fromList . fromMaybe [RQL,GRAPHQL] <$> + enabledAPIs <- Set.fromList . fromMaybe [METADATA,GRAPHQL] <$> withEnv (rsoEnabledAPIs rso) (fst enabledAPIsEnv) return $ ServeOptions port host connParams txIso adminScrt authHook jwtSecret @@ -460,7 +460,7 @@ enableTelemetryEnv = enabledAPIsEnv :: (String,String) enabledAPIsEnv = ( "HASURA_GRAPHQL_ENABLED_APIS" - , "List of comma separated list of allowed APIs. (default: rql,graphql)" + , "List of comma separated list of allowed APIs. (default: metadata,graphql)" ) parseRawConnInfo :: Parser RawConnInfo @@ -608,9 +608,9 @@ readHookType tyS = readAPIs :: String -> Either String [API] readAPIs = mapM readAPI . T.splitOn "," . T.pack where readAPI si = case T.toUpper $ T.strip si of - "RQL" -> Right RQL - "GRAPHQL" -> Right GRAPHQL - _ -> Left "Only expecting list of comma separated API types RQL / GRAPHQL" + "METADATA" -> Right METADATA + "GRAPHQL" -> Right GRAPHQL + _ -> Left "Only expecting list of comma separated API types metadata / graphql" parseWebHook :: Parser RawAuthHook parseWebHook = diff --git a/server/tests-py/conftest.py b/server/tests-py/conftest.py index b77e9dd334335..46e9a49216a64 100644 --- a/server/tests-py/conftest.py +++ b/server/tests-py/conftest.py @@ -34,8 +34,8 @@ def pytest_addoption(parser): ) parser.addoption( - "--test-rql-disabled", action="store_true", - help="Run Test cases with RQL queries being disabled" + "--test-metadata-disabled", action="store_true", + help="Run Test cases with metadata queries being disabled" ) parser.addoption( @@ -55,7 +55,7 @@ def hge_ctx(request): hge_jwt_key_file = request.config.getoption('--hge-jwt-key-file') hge_jwt_conf = request.config.getoption('--hge-jwt-conf') test_cors = request.config.getoption('--test-cors') - rql_disabled = request.config.getoption('--test-rql-disabled') + metadata_disabled = request.config.getoption('--test-metadata-disabled') try: hge_ctx = HGECtx( hge_url=hge_url, @@ -65,7 +65,7 @@ def hge_ctx(request): webhook_insecure=webhook_insecure, hge_jwt_key_file=hge_jwt_key_file, hge_jwt_conf=hge_jwt_conf, - rql_disabled=rql_disabled + metadata_disabled=metadata_disabled ) except HGECtxError as e: pytest.exit(str(e)) diff --git a/server/tests-py/context.py b/server/tests-py/context.py index 1ffd254aa66f5..66f276bca6764 100644 --- a/server/tests-py/context.py +++ b/server/tests-py/context.py @@ -74,7 +74,7 @@ def server_bind(self): class HGECtx: - def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_jwt_key_file, hge_jwt_conf, rql_disabled): + def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_jwt_key_file, hge_jwt_conf, metadata_disabled): server_address = ('0.0.0.0', 5592) self.resp_queue = queue.Queue(maxsize=1) @@ -99,7 +99,7 @@ def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_ self.hge_jwt_key = f.read() self.hge_jwt_conf = hge_jwt_conf self.webhook_insecure = webhook_insecure - self.rql_disabled = rql_disabled + self.metadata_disabled = metadata_disabled self.may_skip_test_teardown = False self.ws_url = urlparse(hge_url) @@ -117,7 +117,7 @@ def __init__(self, hge_url, pg_url, hge_key, hge_webhook, webhook_insecure, hge_ result = subprocess.run(['../../scripts/get-version.sh'], shell=False, stdout=subprocess.PIPE, check=True) self.version = result.stdout.decode('utf-8').strip() - if not self.rql_disabled: + if not self.metadata_disabled: try: st_code, resp = self.v1q_f('queries/clear_db.yaml') except requests.exceptions.RequestException as e: diff --git a/server/tests-py/test_server_interfaces.py b/server/tests-py/test_apis_disabled.py similarity index 70% rename from server/tests-py/test_server_interfaces.py rename to server/tests-py/test_apis_disabled.py index d9c7a4fc7fb58..ebf74b19b0865 100644 --- a/server/tests-py/test_server_interfaces.py +++ b/server/tests-py/test_apis_disabled.py @@ -11,17 +11,17 @@ def check_post_404(hge_ctx,url): }) -@pytest.mark.skipif(not pytest.config.getoption("--test-rql-disabled"), - reason="flag --test-rql-disabled is not set. Cannot run tests for RQL disabled") -class TestRQLDisabled: +@pytest.mark.skipif(not pytest.config.getoption("--test-metadata-disabled"), + reason="flag --test-metadata-disabled is not set. Cannot run tests for metadata disabled") +class TestMetadataDisabled: - def test_rql_v1_query_disabled(self, hge_ctx): + def test_metadata_v1_query_disabled(self, hge_ctx): check_post_404(hge_ctx,'/v1/query') - def test_rql_v1_template_disabled(self, hge_ctx): + def test_metadata_v1_template_disabled(self, hge_ctx): check_post_404(hge_ctx,'/v1/template/foo') - def test_rql_api_1_disabled(self, hge_ctx): + def test_metadata_api_1_disabled(self, hge_ctx): check_post_404(hge_ctx,'/api/1/table/foo/select') @@ -44,9 +44,9 @@ def test_graphql_introspection(self, hge_ctx): check_query_f(hge_ctx, "queries/graphql_introspection/introspection_only_kind_of_queryType.yaml") -@pytest.mark.skipif(pytest.config.getoption("--test-rql-disabled"), - reason="--test-rql-disabled is set. Cannot run RQL enabled tests") -class TestRQLEnabled: +@pytest.mark.skipif(pytest.config.getoption("--test-metadata-disabled"), + reason="--test-metadata-disabled is set. Cannot run metadata enabled tests") +class TestMetadataEnabled: def test_reload_metadata(self, hge_ctx): check_query_f(hge_ctx, "queries/v1/metadata/reload_metadata.yaml") From 0e9ec4d598dfb469732918fe046e905e703db085 Mon Sep 17 00:00:00 2001 From: Nizar Malangadan Date: Thu, 28 Feb 2019 17:15:57 +0530 Subject: [PATCH 8/8] Show the allowed values for API in docs --- .../manual/deployment/graphql-engine-flags/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst index db96ee0fc3f1a..b8b55a6a5c92e 100644 --- a/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst +++ b/docs/graphql/manual/deployment/graphql-engine-flags/reference.rst @@ -141,7 +141,7 @@ For ``serve`` sub-command these are the flags and ENV variables available: * - ``--enabled-apis `` - ``HASURA_GRAPHQL_ENABLED_APIS`` - - Comma separated list of APIs to be enabled. (default: ``metadata,graphql``) + - Comma separated list of APIs (metadata & graphql) to be enabled. (default: ``metadata,graphql``) .. note:: When the equivalent flags for environment variables are used, the flags will take precedence.