mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
Merge branch 'master' into feature/add-identity-frequent-column
This commit is contained in:
commit
bf5a416f3e
13
CHANGELOG.md
13
CHANGELOG.md
@ -2,14 +2,25 @@
|
||||
|
||||
## Next release
|
||||
|
||||
### Breaking change
|
||||
|
||||
Headers from environment variables starting with `HASURA_GRAPHQL_` are not allowed
|
||||
in event triggers, actions & remote schemas.
|
||||
|
||||
If you do have such headers configured, then you must update the header configuration before upgrading.
|
||||
|
||||
### Bug fixes and improvements
|
||||
|
||||
(Add entries here in the order of: server, console, cli, docs, others)
|
||||
|
||||
- server: fix failing introspection query when an enum column is part of a primary key (fixes #5200)
|
||||
- server: disallow headers from env variables starting with `HASURA_GRAPHQL_` in actions, event triggers & remote schemas (#5519)
|
||||
**WARNING**: This might break certain deployments. See `Breaking change` section above.
|
||||
- server: bugfix to allow HASURA_GRAPHQL_QUERY_PLAN_CACHE_SIZE of 0 (#5363)
|
||||
- server: support only a bounded plan cache, with a default size of 4000 (closes #5363)
|
||||
- server: add logs for action handlers
|
||||
- server: add request/response sizes in event triggers (and scheduled trigger) logs
|
||||
- server: add request/response sizes in event triggers (and scheduled trigger) logs (#5463)
|
||||
- server: change startup log kind `db_migrate` to `catalog_migrate` (#5531)
|
||||
- console: handle nested fragments in allowed queries (close #5137) (#5252)
|
||||
- console: update sidebar icons for different action and trigger types (#5445)
|
||||
- console: make add column UX consistent with others (#5486)
|
||||
|
@ -40,7 +40,7 @@ const executeSQL = (isMigration, migrationName, statementTimeout) => (
|
||||
dispatch({ type: MAKING_REQUEST });
|
||||
dispatch(showSuccessNotification('Executing the Query...'));
|
||||
|
||||
const { isTableTrackChecked, isCascadeChecked } = getState().rawSQL;
|
||||
const { isTableTrackChecked, isCascadeChecked, sql } = getState().rawSQL;
|
||||
const { migrationMode, readOnlyMode } = getState().main;
|
||||
|
||||
const migrateUrl = returnMigrateUrl(migrationMode);
|
||||
@ -49,13 +49,17 @@ const executeSQL = (isMigration, migrationName, statementTimeout) => (
|
||||
|
||||
const schemaChangesUp = [];
|
||||
|
||||
const sql =
|
||||
statementTimeout && !isMigration
|
||||
? `${getStatementTimeoutSql(statementTimeout)} ${getState().rawSQL.sql}`
|
||||
: getState().rawSQL.sql;
|
||||
if (statementTimeout && !isMigration) {
|
||||
schemaChangesUp.push(
|
||||
getRunSqlQuery(
|
||||
getStatementTimeoutSql(statementTimeout),
|
||||
false,
|
||||
readOnlyMode
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
schemaChangesUp.push(getRunSqlQuery(sql, isCascadeChecked, readOnlyMode));
|
||||
// check if track view enabled
|
||||
|
||||
if (isTableTrackChecked) {
|
||||
const objects = parseCreateSQL(sql);
|
||||
|
@ -774,7 +774,7 @@ class PermissionBuilder extends React.Component {
|
||||
|
||||
const _tableExp = [
|
||||
{ key: 'schema', value: schemaSelect },
|
||||
{ key: 'table', value: tableSelect },
|
||||
{ key: 'name', value: tableSelect },
|
||||
];
|
||||
|
||||
return <QueryBuilderJson element={_tableExp} />;
|
||||
|
@ -242,7 +242,7 @@ migrateCatalogSchema env logger pool httpManager sqlGenCtx = do
|
||||
initialiseResult `onLeft` \err -> do
|
||||
unLogger logger StartupLog
|
||||
{ slLogLevel = LevelError
|
||||
, slKind = "db_migrate"
|
||||
, slKind = "catalog_migrate"
|
||||
, slInfo = A.toJSON err
|
||||
}
|
||||
liftIO (printErrExit DatabaseMigrationError (BLC.unpack $ A.encode err))
|
||||
|
@ -214,6 +214,7 @@ mkMutationTypesAndFieldsRole tn insPermM selFldsM updColsM delPermM pkeyCols con
|
||||
(selFldsM ^.. _Just.traverse._SFPGColumn)
|
||||
<> (insPermM ^. _Just._1)
|
||||
<> (updColsM ^. _Just)
|
||||
<> (pkeyCols ^. _Just.pkColumns.to toList)
|
||||
allEnumReferences = allColumnInfos ^.. traverse.to pgiType._PGColumnEnumReference
|
||||
in flip map allEnumReferences $ \enumReference@(EnumReference referencedTableName _) ->
|
||||
let typeName = mkTableEnumType referencedTableName
|
||||
|
@ -8,8 +8,8 @@ import Hasura.RQL.Types.Error
|
||||
import Language.Haskell.TH.Syntax (Lift)
|
||||
|
||||
import qualified Data.CaseInsensitive as CI
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Environment as Env
|
||||
import qualified Data.Text as T
|
||||
import qualified Network.HTTP.Types as HTTP
|
||||
|
||||
|
||||
@ -35,7 +35,10 @@ instance FromJSON HeaderConf where
|
||||
case (value, valueFromEnv ) of
|
||||
(Nothing, Nothing) -> fail "expecting value or value_from_env keys"
|
||||
(Just val, Nothing) -> return $ HeaderConf name (HVValue val)
|
||||
(Nothing, Just val) -> return $ HeaderConf name (HVEnv val)
|
||||
(Nothing, Just val) -> do
|
||||
when (T.isPrefixOf "HASURA_GRAPHQL_" val) $
|
||||
fail $ "env variables starting with \"HASURA_GRAPHQL_\" are not allowed in value_from_env: " <> T.unpack val
|
||||
return $ HeaderConf name (HVEnv val)
|
||||
(Just _, Just _) -> fail "expecting only one of value or value_from_env keys"
|
||||
parseJSON _ = fail "expecting object for headers"
|
||||
|
||||
|
@ -64,7 +64,7 @@ data MigrationResult
|
||||
instance ToEngineLog MigrationResult Hasura where
|
||||
toEngineLog result = toEngineLog $ StartupLog
|
||||
{ slLogLevel = LevelInfo
|
||||
, slKind = "db_migrate"
|
||||
, slKind = "catalog_migrate"
|
||||
, slInfo = A.toJSON $ case result of
|
||||
MRNothingToDo ->
|
||||
"Already at the latest catalog version (" <> latestCatalogVersionString
|
||||
|
@ -26,6 +26,7 @@ import Control.Monad.Trans.Control
|
||||
import Control.Monad.Morph
|
||||
import Control.Monad.Unique
|
||||
import Data.String (fromString)
|
||||
import Network.URI (URI)
|
||||
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.Aeson.Lens as JL
|
||||
@ -237,22 +238,25 @@ extractEventContext e = do
|
||||
-- | Perform HTTP request which supports Trace headers
|
||||
tracedHttpRequest
|
||||
:: MonadTrace m
|
||||
=> HTTP.Request
|
||||
=> HTTP.Request
|
||||
-- ^ http request that needs to be made
|
||||
-> (HTTP.Request -> m a)
|
||||
-- ^ a function that takes the traced request and executes it
|
||||
-> m a
|
||||
tracedHttpRequest req f = trace (bsToTxt (HTTP.path req)) do
|
||||
let reqBytes = case HTTP.requestBody req of
|
||||
HTTP.RequestBodyBS bs -> Just (fromIntegral (BS.length bs))
|
||||
HTTP.RequestBodyLBS bs -> Just (BL.length bs)
|
||||
HTTP.RequestBodyBuilder len _ -> Just len
|
||||
HTTP.RequestBodyStream len _ -> Just len
|
||||
_ -> Nothing
|
||||
for_ reqBytes \b ->
|
||||
attachMetadata [("request_body_bytes", fromString (show b))]
|
||||
ctx <- currentContext
|
||||
let req' = req { HTTP.requestHeaders =
|
||||
injectHttpContext ctx <> HTTP.requestHeaders req
|
||||
}
|
||||
f req'
|
||||
tracedHttpRequest req f = do
|
||||
let method = bsToTxt (HTTP.method req)
|
||||
uri = show @URI (HTTP.getUri req)
|
||||
trace (method <> " " <> fromString uri) do
|
||||
let reqBytes = case HTTP.requestBody req of
|
||||
HTTP.RequestBodyBS bs -> Just (fromIntegral (BS.length bs))
|
||||
HTTP.RequestBodyLBS bs -> Just (BL.length bs)
|
||||
HTTP.RequestBodyBuilder len _ -> Just len
|
||||
HTTP.RequestBodyStream len _ -> Just len
|
||||
_ -> Nothing
|
||||
for_ reqBytes \b ->
|
||||
attachMetadata [("request_body_bytes", fromString (show b))]
|
||||
ctx <- currentContext
|
||||
let req' = req { HTTP.requestHeaders =
|
||||
injectHttpContext ctx <> HTTP.requestHeaders req
|
||||
}
|
||||
f req'
|
||||
|
@ -0,0 +1,21 @@
|
||||
description: Define an action with headers configuration
|
||||
url: /v1/query
|
||||
status: 400
|
||||
query:
|
||||
type: create_action
|
||||
args:
|
||||
name: create_user_1
|
||||
definition:
|
||||
kind: synchronous
|
||||
arguments:
|
||||
- name: name
|
||||
type: String!
|
||||
output_type: User!
|
||||
handler: http://127.0.0.1:5593/create-user
|
||||
headers:
|
||||
- name: x-client-id
|
||||
value_from_env: HASURA_GRAPHQL_CLIENT_NAME
|
||||
response:
|
||||
path: $.definition.headers[0]
|
||||
error: 'env variables starting with "HASURA_GRAPHQL_" are not allowed in value_from_env: HASURA_GRAPHQL_CLIENT_NAME'
|
||||
code: parse-failed
|
@ -0,0 +1,48 @@
|
||||
# https://github.com/hasura/graphql-engine/issues/5200
|
||||
description: Test introspecting enum types as user role
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
headers:
|
||||
X-Hasura-Role: user
|
||||
response:
|
||||
data:
|
||||
country:
|
||||
kind: ENUM
|
||||
name: country_enum
|
||||
enumValues:
|
||||
- name: India
|
||||
description: Republic of India
|
||||
- name: USA
|
||||
description: United States of America
|
||||
zones:
|
||||
fields:
|
||||
- name: code
|
||||
type:
|
||||
ofType:
|
||||
name: String
|
||||
- name: id
|
||||
type:
|
||||
ofType:
|
||||
name: Int
|
||||
query:
|
||||
query: |
|
||||
{
|
||||
country: __type(name: "country_enum") {
|
||||
name
|
||||
kind
|
||||
enumValues {
|
||||
name
|
||||
description
|
||||
}
|
||||
}
|
||||
zones: __type(name: "zones") {
|
||||
fields {
|
||||
name
|
||||
type {
|
||||
ofType {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,12 +23,34 @@ args:
|
||||
('Alyssa', 'red'),
|
||||
('Ben', 'blue');
|
||||
|
||||
CREATE TABLE country
|
||||
( value text PRIMARY KEY
|
||||
, comment text);
|
||||
INSERT INTO country (value, comment) VALUES
|
||||
('India', 'Republic of India'),
|
||||
('USA', 'United States of America');
|
||||
|
||||
CREATE TABLE zones
|
||||
( id SERIAL
|
||||
, code text NOT NULL
|
||||
, country text NOT NULL REFERENCES country
|
||||
, PRIMARY KEY (code, country) );
|
||||
INSERT INTO zones (code, country) VALUES
|
||||
('67432', 'USA'),
|
||||
('600036', 'India');
|
||||
|
||||
- type: track_table
|
||||
args:
|
||||
table: colors
|
||||
is_enum: true
|
||||
- type: track_table
|
||||
args: users
|
||||
- type: track_table
|
||||
args:
|
||||
table: country
|
||||
is_enum: true
|
||||
- type: track_table
|
||||
args: zones
|
||||
|
||||
# Anonymous users can query users, but not colors
|
||||
- type: create_select_permission
|
||||
@ -38,3 +60,12 @@ args:
|
||||
permission:
|
||||
columns: [id, name, favorite_color]
|
||||
filter: {}
|
||||
|
||||
# A user can query only code but not country
|
||||
- type: create_select_permission
|
||||
args:
|
||||
table: zones
|
||||
role: user
|
||||
permission:
|
||||
columns: [id, code]
|
||||
filter: {}
|
||||
|
@ -5,4 +5,6 @@ args:
|
||||
sql: |
|
||||
DROP TABLE users;
|
||||
DROP TABLE colors;
|
||||
DROP TABLE zones;
|
||||
DROP TABLE country;
|
||||
cascade: true
|
||||
|
@ -455,6 +455,9 @@ class TestActionsMetadata:
|
||||
def test_recreate_permission(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/recreate_permission.yaml')
|
||||
|
||||
def test_create_with_headers(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/create_with_headers.yaml')
|
||||
|
||||
# Test case for bug reported at https://github.com/hasura/graphql-engine/issues/5166
|
||||
@pytest.mark.usefixtures('per_class_tests_db_state')
|
||||
class TestActionIntrospection:
|
||||
|
@ -561,6 +561,9 @@ class TestGraphQLQueryEnums:
|
||||
def test_introspect(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/introspect.yaml', transport)
|
||||
|
||||
def test_introspect_user_role(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/introspect_user_role.yaml', transport)
|
||||
|
||||
def test_select_enum_field(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/select_enum_field.yaml', transport)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user