Move RoleName into SchemaContext.

### Description

I am not 100% sure about this PR; while I think the code is better this way, I'm willing to be convinced otherwise.

In short, this PR moves the `RoleName` field into the `SchemaContext`, instead of being a nebulous `Has RoleName` constraint on the reader monad. The major upside of this is that it makes it an explicit named field, rather than something that must be given as part of a tuple of arguments when calling `runReader`.

However, the downside is that it breaks the helper permissions functions of `Schema.Table`, which relied on `Has RoleName r`. This PR makes the choice of passing the role name explicitly to all of those functions, which in turn means first explicitly fetching the role name in a lot of places. It makes it more explicit when a schema building block relies on the role name, but is a bit verbose...

### Alternatives

Some alternatives worth considering:
- attempting something like `Has context r, Has RoleName context`, which would allow them to be independent from the context but still fetch the role name from the reader, but might require type annotations to not be ambiguous
- keeping the permission functions the same, with `Has RoleName r`, and introducing a bunch of newtypes instead of using tuples to explicitly implement all the required `Has` instances
- changing the permission functions to `Has SchemaContext r`, since they are functions used only to build the schema, and therefore may be allowed to be tied to the context.

What do y'all think?

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5073
GitOrigin-RevId: 8fd09fafb54905a4d115ef30842d35da0c3db5d2
This commit is contained in:
Antoine Leblanc 2022-07-29 16:37:09 +01:00 committed by hasura-bot
parent 178e452b6b
commit 0a69db81c9
22 changed files with 147 additions and 134 deletions

View File

@ -420,12 +420,13 @@ bqComputedField ::
m (Maybe (FieldParser n (AnnotatedField 'BigQuery)))
bqComputedField sourceName ComputedFieldInfo {..} tableName tableInfo = runMaybeT do
stringifyNumbers <- retrieve Options.soStringifyNumbers
roleName <- retrieve scRole
fieldName <- lift $ textToName $ computedFieldNameToText _cfiName
functionArgsParser <- lift $ computedFieldFunctionArgs _cfiFunction
case _cfiReturnType of
BigQuery.ReturnExistingTable returnTable -> do
returnTableInfo <- lift $ askTableInfo sourceName returnTable
returnTablePermissions <- MaybeT $ tableSelectPermissions returnTableInfo
returnTablePermissions <- hoistMaybe $ tableSelectPermissions roleName returnTableInfo
selectionSetParser <- MaybeT (fmap (P.multiple . P.nonNullableParser) <$> tableSelectionSet sourceName returnTableInfo)
selectArgsParser <- lift $ tableArguments sourceName returnTableInfo
let fieldArgsParser = liftA2 (,) functionArgsParser selectArgsParser
@ -444,7 +445,7 @@ bqComputedField sourceName ComputedFieldInfo {..} tableName tableInfo = runMaybe
}
BigQuery.ReturnTableSchema returnFields -> do
-- Check if the computed field is available in the select permission
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
guard $ Map.member _cfiName $ spiComputedFields selectPermissions
objectTypeName <-
mkTypename =<< do

View File

@ -36,7 +36,6 @@ import Hasura.GraphQL.Schema.Parser
)
import Hasura.GraphQL.Schema.Parser qualified as P
import Hasura.GraphQL.Schema.Select
import Hasura.GraphQL.Schema.Table
import Hasura.GraphQL.Schema.Typename (MkTypename)
import Hasura.GraphQL.Schema.Update qualified as SU
import Hasura.Name qualified as Name
@ -131,8 +130,9 @@ msBuildTableUpdateMutationFields ::
C.GQLNameIdentifier ->
m [FieldParser n (AnnotatedUpdateG 'MSSQL (RemoteRelationshipField UnpreparedValue) (UnpreparedValue 'MSSQL))]
msBuildTableUpdateMutationFields scenario sourceName tableName tableInfo gqlName = do
roleName <- retrieve scRole
fieldParsers <- runMaybeT do
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
let mkBackendUpdate backendUpdateTableInfo =
(fmap . fmap) BackendUpdate $
SU.buildUpdateOperators

View File

@ -72,7 +72,8 @@ ifMatchedObjectParser ::
m (Maybe (Parser 'Input n (IfMatched (UnpreparedValue 'MSSQL))))
ifMatchedObjectParser sourceInfo tableInfo = runMaybeT do
-- Short-circuit if we don't have sufficient permissions.
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
roleName <- retrieve scRole
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
matchColumnsEnum <- MaybeT $ tableInsertMatchColumnsEnum sourceInfo tableInfo
lift do
updateColumnsEnum <- updateColumnsPlaceholderParser tableInfo

View File

@ -59,7 +59,7 @@ import Hasura.GraphQL.Schema.Parser
)
import Hasura.GraphQL.Schema.Parser qualified as P
import Hasura.GraphQL.Schema.Select
import Hasura.GraphQL.Schema.Table
import Hasura.GraphQL.Schema.Table (getTableGQLName, tableColumns)
import Hasura.GraphQL.Schema.Typename
import Hasura.GraphQL.Schema.Update qualified as SU
import Hasura.Name qualified as Name
@ -78,7 +78,7 @@ import Hasura.RQL.Types.Column
import Hasura.RQL.Types.Function (FunctionInfo)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.RQL.Types.Table (CustomRootField (..), RolePermInfo (..), TableConfig (..), TableCoreInfoG (..), TableCustomRootFields (..), TableInfo (..), UpdPermInfo (..), ViewInfo (..), isMutable, tableInfoName)
import Hasura.RQL.Types.Table (CustomRootField (..), RolePermInfo (..), TableConfig (..), TableCoreInfoG (..), TableCustomRootFields (..), TableInfo (..), UpdPermInfo (..), ViewInfo (..), getRolePermInfo, isMutable, tableInfoName)
import Hasura.SQL.Backend (BackendType (Postgres), PostgresKind (Citus, Vanilla))
import Hasura.SQL.Tag (HasTag)
import Hasura.SQL.Types
@ -225,9 +225,10 @@ pgkBuildTableUpdateMutationFields ::
-- | field display name
C.GQLNameIdentifier ->
m [FieldParser n (IR.AnnotatedUpdateG ('Postgres pgKind) (RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue ('Postgres pgKind)))]
pgkBuildTableUpdateMutationFields scenario sourceInfo tableName tableInfo gqlName =
pgkBuildTableUpdateMutationFields scenario sourceInfo tableName tableInfo gqlName = do
roleName <- retrieve scRole
concat . maybeToList <$> runMaybeT do
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
lift $ do
-- update_table and update_table_by_pk
singleUpdates <-
@ -279,10 +280,11 @@ updateTableMany ::
m (Maybe (P.FieldParser n (IR.AnnotatedUpdateG ('Postgres pgKind) (RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue ('Postgres pgKind)))))
updateTableMany scenario sourceInfo tableInfo gqlName = runMaybeT do
tCase <- asks getter
roleName <- retrieve scRole
let columns = tableColumns tableInfo
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsUpdatable viewInfo
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
guard $ not $ scenario == Frontend && upiBackendOnly updatePerms
updates <- lift (mkMultiRowUpdateParser sourceInfo tableInfo updatePerms)
selection <- lift $ P.multiple <$> GSB.mutationSelectionSet sourceInfo tableInfo

View File

@ -62,8 +62,9 @@ onConflictFieldParser ::
m (InputFieldsParser n (Maybe (IR.OnConflictClause ('Postgres pgKind) (IR.UnpreparedValue ('Postgres pgKind)))))
onConflictFieldParser sourceInfo tableInfo = do
tCase <- asks getter
permissions <- tablePermissions tableInfo
let maybeConstraints = tciUniqueOrPrimaryKeyConstraints . _tiCoreInfo $ tableInfo
roleName <- retrieve scRole
let permissions = getRolePermInfo roleName tableInfo
maybeConstraints = tciUniqueOrPrimaryKeyConstraints . _tiCoreInfo $ tableInfo
maybeConflictObject = conflictObjectParser sourceInfo tableInfo (_permUpd permissions) <$> maybeConstraints
case maybeConflictObject of
Just conflictObject -> conflictObject <&> P.fieldOptional (applyFieldNameCaseCust tCase Name._on_conflict) (Just "upsert condition")

View File

@ -62,8 +62,9 @@ selectFunction ::
m (Maybe (FieldParser n (SelectExp ('Postgres pgKind))))
selectFunction sourceInfo fi@FunctionInfo {..} description = runMaybeT do
tCase <- asks getter
roleName <- retrieve scRole
tableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
selectionSetParser <- MaybeT $ returnFunctionParser sourceInfo tableInfo
lift do
stringifyNumbers <- retrieve Options.soStringifyNumbers
@ -101,8 +102,9 @@ selectFunctionAggregate ::
m (Maybe (FieldParser n (AggSelectExp ('Postgres pgKind))))
selectFunctionAggregate sourceInfo fi@FunctionInfo {..} description = runMaybeT do
tCase <- asks getter
roleName <- retrieve scRole
targetTableInfo <- askTableInfo sourceInfo _fiReturnType
selectPermissions <- MaybeT $ tableSelectPermissions targetTableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName targetTableInfo
guard $ spiAllowAgg selectPermissions
xNodesAgg <- hoistMaybe $ nodesAggExtension @('Postgres pgKind)
tableInfo <- askTableInfo sourceInfo _fiReturnType
@ -153,8 +155,9 @@ selectFunctionConnection ::
m (Maybe (FieldParser n (ConnectionSelectExp ('Postgres pgKind))))
selectFunctionConnection sourceInfo fi@FunctionInfo {..} description pkeyColumns = runMaybeT do
tCase <- asks getter
roleName <- retrieve scRole
returnTableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
selectPermissions <- MaybeT $ tableSelectPermissions returnTableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName returnTableInfo
xRelayInfo <- hoistMaybe $ relayExtension @('Postgres pgKind)
tableInfo <- lift $ askTableInfo sourceInfo _fiReturnType
selectionSetParser <- MaybeT $ tableConnectionSelectionSet sourceInfo tableInfo
@ -195,8 +198,9 @@ computedFieldPG ::
m (Maybe (FieldParser n (AnnotatedField ('Postgres pgKind))))
computedFieldPG sourceInfo ComputedFieldInfo {..} parentTable tableInfo = runMaybeT do
tCase <- asks getter
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
stringifyNumbers <- retrieve Options.soStringifyNumbers
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
fieldName <- lift $ textToName $ computedFieldNameToText _cfiName
functionArgsParser <- lift $ computedFieldFunctionArgs _cfiFunction
case _cfiReturnType of
@ -226,7 +230,7 @@ computedFieldPG sourceInfo ComputedFieldInfo {..} parentTable tableInfo = runMay
pure $ P.selection fieldName fieldDescription fieldArgsParser dummyParser
PG.CFRSetofTable tableName -> do
otherTableInfo <- lift $ askTableInfo sourceInfo tableName
remotePerms <- MaybeT $ tableSelectPermissions otherTableInfo
remotePerms <- hoistMaybe $ tableSelectPermissions roleName otherTableInfo
selectionSetParser <- MaybeT (fmap (P.multiple . P.nonNullableParser) <$> tableSelectionSet sourceInfo otherTableInfo)
selectArgsParser <- lift $ tableArguments sourceInfo otherTableInfo
let fieldArgsParser = liftA2 (,) functionArgsParser selectArgsParser

View File

@ -116,8 +116,7 @@ fetchRemoteSchema env manager _rscName rsDef@ValidatedRemoteSchemaDef {..} = do
-- Minimum valid information required to run schema generation for
-- the remote schema.
minimumValidContext =
( adminRoleName :: RoleName,
mempty :: CustomizeRemoteFieldName,
( mempty :: CustomizeRemoteFieldName,
mempty :: MkTypename,
mempty :: MkRootFieldName,
HasuraCase,
@ -137,6 +136,7 @@ fetchRemoteSchema env manager _rscName rsDef@ValidatedRemoteSchemaDef {..} = do
SchemaContext
HasuraSchema
ignoreRemoteRelationship
adminRoleName
)
-- | Sends a GraphQL query to the given server.

View File

@ -197,7 +197,8 @@ buildRoleContext options sources remotes allActionInfos customTypes role remoteS
SchemaContext
HasuraSchema
(remoteRelationshipField sources (fst <$> remotes) remoteSchemaPermsCtx)
runMonadSchema schemaOptions schemaContext role $ do
role
runMonadSchema schemaOptions schemaContext $ do
-- build all sources (`apolloFedTableParsers` contains all the parsers and
-- type names, which are eligible for the `_Entity` Union)
(sourcesQueryFields, sourcesMutationFrontendFields, sourcesMutationBackendFields, subscriptionFields, apolloFedTableParsers) <-
@ -338,7 +339,8 @@ buildRelayRoleContext options sources allActionInfos customTypes role expFeature
SchemaContext
(RelaySchema $ nodeInterface sources)
(remoteRelationshipField sources mempty Options.DisableRemoteSchemaPermissions)
runMonadSchema schemaOptions schemaContext role do
role
runMonadSchema schemaOptions schemaContext do
node <- fmap NotNamespaced <$> nodeField sources
fieldsList <- traverse (buildBackendSource buildSource) $ toList sources
let (queryFields, mutationFrontendFields, mutationBackendFields, subscriptionFields) = mconcat fieldsList
@ -460,6 +462,7 @@ unauthenticatedContext allRemotes remoteSchemaPermsCtx = do
SchemaContext
HasuraSchema
ignoreRemoteRelationship
fakeRole
-- chosen arbitrarily to be as improbable as possible
fakeRole = mkRoleNameSafe [NT.nonEmptyTextQQ|MyNameIsOzymandiasKingOfKingsLookOnMyWorksYeMightyAndDespair|]
-- we delete all references to remote joins
@ -467,7 +470,7 @@ unauthenticatedContext allRemotes remoteSchemaPermsCtx = do
allRemotes <&> first \context ->
context {_rscRemoteRelationships = mempty}
runMonadSchema fakeSchemaOptions fakeSchemaContext fakeRole do
runMonadSchema fakeSchemaOptions fakeSchemaContext do
(queryFields, mutationFields, subscriptionFields, remoteErrors) <- case remoteSchemaPermsCtx of
Options.EnableRemoteSchemaPermissions ->
-- Permissions are enabled, unauthenticated users have access to nothing.
@ -583,7 +586,7 @@ buildQueryAndSubscriptionFields ::
StreamingSubscriptionsCtx ->
m ([P.FieldParser n (QueryRootField UnpreparedValue)], [P.FieldParser n (SubscriptionRootField UnpreparedValue)], [(G.Name, Parser 'Output n (ApolloFederationParserFunction n))])
buildQueryAndSubscriptionFields sourceInfo tables (takeExposedAs FEAQuery -> functions) streamingSubsCtx = do
roleName <- asks getter
roleName <- retrieve scRole
functionPermsCtx <- retrieve Options.soInferFunctionPermissions
functionSelectExpParsers <-
concat . catMaybes
@ -624,11 +627,12 @@ buildRelayQueryAndSubscriptionFields ::
FunctionCache b ->
m ([P.FieldParser n (QueryRootField UnpreparedValue)], [P.FieldParser n (SubscriptionRootField UnpreparedValue)])
buildRelayQueryAndSubscriptionFields sourceInfo tables (takeExposedAs FEAQuery -> functions) = do
roleName <- retrieve scRole
(tableConnectionQueryFields, tableConnectionSubscriptionFields) <-
unzip . catMaybes
<$> for (Map.toList tables) \(tableName, tableInfo) -> runMaybeT do
tableIdentifierName <- getTableIdentifierName @b tableInfo
SelPermInfo {..} <- MaybeT $ tableSelectPermissions tableInfo
SelPermInfo {..} <- hoistMaybe $ tableSelectPermissions roleName tableInfo
pkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
relayRootFields <- lift $ mkRFs $ buildTableRelayQueryFields sourceInfo tableName tableInfo tableIdentifierName pkeyColumns
let includeRelayWhen True = Just relayRootFields
@ -663,7 +667,7 @@ buildMutationFields ::
FunctionCache b ->
m [P.FieldParser n (MutationRootField UnpreparedValue)]
buildMutationFields scenario sourceInfo tables (takeExposedAs FEAMutation -> functions) = do
roleName <- asks getter
roleName <- retrieve scRole
tableMutations <- for (Map.toList tables) \(tableName, tableInfo) -> do
tableIdentifierName <- getTableIdentifierName @b tableInfo
inserts <-
@ -905,7 +909,6 @@ type ConcreteSchemaT m a =
( ReaderT
( SchemaOptions,
SchemaContext,
RoleName,
MkTypename,
MkRootFieldName,
CustomizeRemoteFieldName,
@ -920,11 +923,10 @@ runMonadSchema ::
Monad m =>
SchemaOptions ->
SchemaContext ->
RoleName ->
ConcreteSchemaT m a ->
m a
runMonadSchema options context roleName m =
flip runReaderT (options, context, roleName, mempty, mempty, mempty, HasuraCase) $
runMonadSchema options context m =
flip runReaderT (options, context, mempty, mempty, mempty, HasuraCase) $
P.runSchemaT m
buildBackendSource ::

View File

@ -10,7 +10,6 @@ where
import Data.Aeson qualified as J
import Data.Aeson.Key qualified as K
import Data.Aeson.KeyMap qualified as KM
import Data.Has
import Data.HashMap.Strict qualified as Map
import Data.Text.Extended
import Data.Text.NonEmpty
@ -65,7 +64,7 @@ actionExecute ::
ActionInfo ->
m (Maybe (FieldParser n (IR.AnnActionExecution (IR.RemoteRelationshipField IR.UnpreparedValue))))
actionExecute customTypes actionInfo = runMaybeT do
roleName <- asks getter
roleName <- retrieve scRole
guard (roleName == adminRoleName || roleName `Map.member` permissions)
let fieldName = unActionName actionName
description = G.Description <$> comment
@ -109,7 +108,7 @@ actionAsyncMutation ::
ActionInfo ->
m (Maybe (FieldParser n IR.AnnActionMutationAsync))
actionAsyncMutation nonObjectTypeMap actionInfo = runMaybeT do
roleName <- asks getter
roleName <- retrieve scRole
guard $ roleName == adminRoleName || roleName `Map.member` permissions
inputArguments <- lift $ actionInputArguments nonObjectTypeMap $ _adArguments definition
let fieldName = unActionName actionName
@ -140,7 +139,7 @@ actionAsyncQuery ::
ActionInfo ->
m (Maybe (FieldParser n (IR.AnnActionAsyncQuery ('Postgres 'Vanilla) (IR.RemoteRelationshipField IR.UnpreparedValue))))
actionAsyncQuery objectTypes actionInfo = runMaybeT do
roleName <- asks getter
roleName <- retrieve scRole
guard $ roleName == adminRoleName || roleName `Map.member` permissions
createdAtFieldParser <-
lift $ columnParser @('Postgres 'Vanilla) (ColumnScalar PGTimeStampTZ) (G.Nullability False)

View File

@ -14,7 +14,7 @@ import Data.Text.Casing qualified as C
import Data.Text.Extended
import Hasura.GraphQL.Parser.Class
import Hasura.GraphQL.Schema.Backend
import Hasura.GraphQL.Schema.Common (askTableInfo, partialSQLExpToUnpreparedValue)
import Hasura.GraphQL.Schema.Common (SchemaContext (..), askTableInfo, partialSQLExpToUnpreparedValue, retrieve)
import Hasura.GraphQL.Schema.NamingCase
import Hasura.GraphQL.Schema.Options qualified as Options
import Hasura.GraphQL.Schema.Parser
@ -85,6 +85,7 @@ boolExp sourceInfo tableInfo = memoizeOn 'boolExp (_siName sourceInfo, tableName
FieldInfo b ->
m (Maybe (InputFieldsParser n (Maybe (AnnBoolExpFld b (UnpreparedValue b)))))
mkField fieldInfo = runMaybeT do
roleName <- retrieve scRole
fieldName <- hoistMaybe $ fieldInfoGraphQLName fieldInfo
P.fieldOptional fieldName Nothing <$> case fieldInfo of
-- field_name: field_type_comparison_exp
@ -93,10 +94,10 @@ boolExp sourceInfo tableInfo = memoizeOn 'boolExp (_siName sourceInfo, tableName
-- field_name: field_type_bool_exp
FIRelationship relationshipInfo -> do
remoteTableInfo <- askTableInfo sourceInfo $ riRTable relationshipInfo
remotePermissions <- lift $ tableSelectPermissions remoteTableInfo
let remoteTableFilter =
fmap partialSQLExpToUnpreparedValue
<$> maybe annBoolExpTrue spiFilter remotePermissions
(fmap . fmap) partialSQLExpToUnpreparedValue $
maybe annBoolExpTrue spiFilter $
tableSelectPermissions roleName remoteTableInfo
remoteBoolExp <- lift $ boolExp sourceInfo remoteTableInfo
pure $ fmap (AVRelationship relationshipInfo . andAnnBoolExps remoteTableFilter) remoteBoolExp
FIComputedField ComputedFieldInfo {..} -> do

View File

@ -118,6 +118,7 @@ buildTableQueryAndSubscriptionFields ::
)
buildTableQueryAndSubscriptionFields sourceInfo tableName tableInfo streamSubCtx gqlName = do
tCase <- asks getter
roleName <- retrieve scRole
-- select table
selectName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfSelect mkSelectField gqlName
-- select table by pk
@ -125,13 +126,11 @@ buildTableQueryAndSubscriptionFields sourceInfo tableName tableInfo streamSubCtx
-- select table aggregate
selectAggName <- mkRootFieldName $ setFieldNameCase tCase tableInfo _tcrfSelectAggregate mkSelectAggregateField gqlName
selectPermission <- tableSelectPermissions tableInfo
selectTableParser <- optionalFieldParser QDBMultipleRows $ selectTable sourceInfo tableInfo selectName selectDesc
selectTableByPkParser <- optionalFieldParser QDBSingleRow $ selectTableByPk sourceInfo tableInfo selectPKName selectPKDesc
selectTableAggregateParser <- optionalFieldParser QDBAggregation $ selectTableAggregate sourceInfo tableInfo selectAggName selectAggDesc
case selectPermission of
case tableSelectPermissions roleName tableInfo of
-- No select permission found for the current role, so
-- no root fields will be accessible to the role
Nothing -> pure (mempty, mempty, Nothing)
@ -169,7 +168,7 @@ buildTableQueryAndSubscriptionFields sourceInfo tableName tableInfo streamSubCtx
apolloFedTableParser <- runMaybeT do
guard $ isApolloFedV1enabled (_tciApolloFederationConfig (_tiCoreInfo tableInfo))
tableSelSet <- MaybeT $ tableSelectionSet sourceInfo tableInfo
selectPerm <- MaybeT $ tableSelectPermissions tableInfo
selectPerm <- hoistMaybe $ tableSelectPermissions roleName tableInfo
stringifyNumbers <- retrieve Options.soStringifyNumbers
primaryKeys <- hoistMaybe $ fmap _pkColumns . _tciPrimaryKey . _tiCoreInfo $ tableInfo
let tableSelPerm = tablePermissionsInfo selectPerm

View File

@ -82,7 +82,9 @@ data SchemaContext = SchemaContext
{ -- | the kind of schema being built
scSchemaKind :: SchemaKind,
-- | how to process remote relationships
scRemoteRelationshipParserBuilder :: RemoteRelationshipParserBuilder
scRemoteRelationshipParserBuilder :: RemoteRelationshipParserBuilder,
-- | the role for which the schema is being built
scRole :: RoleName
}
-- | The kind of schema we're building, and its associated options.
@ -103,7 +105,6 @@ type MonadBuildSchemaBase r m n =
Has SchemaOptions r,
Has SchemaContext r,
-- TODO: make all `Has x r` explicit fields of 'SchemaContext'
Has RoleName r,
Has MkTypename r,
Has MkRootFieldName r,
Has CustomizeRemoteFieldName r,

View File

@ -73,13 +73,15 @@ insertIntoTable ::
insertIntoTable backendInsertAction scenario sourceInfo tableInfo fieldName description = runMaybeT $ do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
roleName <- retrieve scRole
let permissions = getRolePermInfo roleName tableInfo
insertPerms <- hoistMaybe $ _permIns permissions
-- If we're in a frontend scenario, we should not include backend_only inserts
-- For more info see Note [Backend only permissions]
guard $ not $ scenario == Frontend && ipiBackendOnly insertPerms
tCase <- asks getter
lift do
updatePerms <- _permUpd <$> tablePermissions tableInfo
let updatePerms = _permUpd permissions
-- objects [{ ... }]
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
@ -122,14 +124,16 @@ insertOneIntoTable ::
insertOneIntoTable backendInsertAction scenario sourceInfo tableInfo fieldName description = runMaybeT do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
roleName <- retrieve scRole
let permissions = getRolePermInfo roleName tableInfo
insertPerms <- hoistMaybe $ _permIns permissions
-- If we're in a frontend scenario, we should not include backend_only inserts
-- For more info see Note [Backend only permissions]
guard $ not $ scenario == Frontend && ipiBackendOnly insertPerms
selectionParser <- MaybeT $ tableSelectionSet sourceInfo tableInfo
tCase <- asks getter
lift do
updatePerms <- _permUpd <$> tablePermissions tableInfo
let updatePerms = _permUpd permissions
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
let argsParser = do
@ -206,7 +210,8 @@ tableFieldsInput sourceInfo tableInfo =
ColumnInfo b ->
m (Maybe (InputFieldsParser n (Maybe (IR.AnnotatedInsertField b (IR.UnpreparedValue b)))))
mkColumnParser columnInfo = runMaybeT $ do
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
roleName <- retrieve scRole
insertPerms <- hoistMaybe $ _permIns $ getRolePermInfo roleName tableInfo
let columnName = ciName columnInfo
columnDesc = ciDescription columnInfo
isAllowed = Set.member (ciColumn columnInfo) (ipiCols insertPerms)
@ -259,10 +264,11 @@ objectRelationshipInput ::
TableInfo b ->
m (Maybe (Parser 'Input n (IR.SingleObjectInsert b (IR.UnpreparedValue b))))
objectRelationshipInput backendInsertAction sourceInfo tableInfo = runMaybeT $ do
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
roleName <- retrieve scRole
let permissions = getRolePermInfo roleName tableInfo
updatePerms = _permUpd permissions
insertPerms <- hoistMaybe $ _permIns permissions
lift $ memoizeOn 'objectRelationshipInput (_siName sourceInfo, tableName) do
updatePerms <- _permUpd <$> tablePermissions tableInfo
_selectPerms <- _permSel <$> tablePermissions tableInfo
tableGQLName <- getTableGQLName tableInfo
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
@ -292,10 +298,11 @@ arrayRelationshipInput ::
TableInfo b ->
m (Maybe (Parser 'Input n (IR.MultiObjectInsert b (IR.UnpreparedValue b))))
arrayRelationshipInput backendInsertAction sourceInfo tableInfo = runMaybeT $ do
insertPerms <- MaybeT $ _permIns <$> tablePermissions tableInfo
roleName <- retrieve scRole
let permissions = getRolePermInfo roleName tableInfo
updatePerms = _permUpd permissions
insertPerms <- hoistMaybe $ _permIns permissions
lift $ memoizeOn 'arrayRelationshipInput (_siName sourceInfo, tableName) do
updatePerms <- _permUpd <$> tablePermissions tableInfo
_selectPerms <- _permSel <$> tablePermissions tableInfo
tableGQLName <- getTableGQLName tableInfo
objectParser <- tableFieldsInput sourceInfo tableInfo
backendInsertParser <- backendInsertAction sourceInfo tableInfo
@ -358,7 +365,8 @@ deleteFromTable ::
deleteFromTable scenario sourceInfo tableInfo fieldName description = runMaybeT $ do
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
deletePerms <- MaybeT $ _permDel <$> tablePermissions tableInfo
roleName <- retrieve scRole
deletePerms <- hoistMaybe $ _permDel $ getRolePermInfo roleName tableInfo
-- If we're in a frontend scenario, we should not include backend_only deletes
-- For more info see Note [Backend only permissions]
guard $ not $ scenario == Frontend && dpiBackendOnly deletePerms
@ -394,7 +402,8 @@ deleteFromTableByPk scenario sourceInfo tableInfo fieldName description = runMay
let viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsInsertable viewInfo
pkArgs <- MaybeT $ primaryKeysArguments tableInfo
deletePerms <- MaybeT $ _permDel <$> tablePermissions tableInfo
roleName <- retrieve scRole
deletePerms <- hoistMaybe $ _permDel $ getRolePermInfo roleName tableInfo
-- If we're in a frontend scenario, we should not include backend_only deletes
-- For more info see Note [Backend only permissions]
guard $ not $ scenario == Frontend && dpiBackendOnly deletePerms
@ -437,9 +446,10 @@ mutationSelectionSet ::
m (Parser 'Output n (IR.MutFldsG b (IR.RemoteRelationshipField IR.UnpreparedValue) (IR.UnpreparedValue b)))
mutationSelectionSet sourceInfo tableInfo =
memoizeOn 'mutationSelectionSet (_siName sourceInfo, tableName) do
roleName <- retrieve scRole
tableGQLName <- getTableGQLName tableInfo
returning <- runMaybeT do
_permissions <- MaybeT $ tableSelectPermissions tableInfo
_permissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
tableSet <- MaybeT $ tableSelectionList sourceInfo tableInfo
let returningName = Name._returning
returningDesc = "data from the rows affected by the mutation"
@ -473,7 +483,8 @@ primaryKeysArguments ::
TableInfo b ->
m (Maybe (InputFieldsParser n (AnnBoolExp b (IR.UnpreparedValue b))))
primaryKeysArguments tableInfo = runMaybeT $ do
selectPerms <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
selectPerms <- hoistMaybe $ tableSelectPermissions roleName tableInfo
primaryKeys <- hoistMaybe $ _tciPrimaryKey . _tiCoreInfo $ tableInfo
let columns = _pkColumns primaryKeys
guard $ all (\c -> ciColumn c `Map.member` spiCols selectPerms) columns

View File

@ -80,7 +80,8 @@ orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tab
NamingCase ->
FieldInfo b ->
m (Maybe (InputFieldsParser n (Maybe [IR.AnnotatedOrderByItemG b (IR.UnpreparedValue b)])))
mkField tCase fieldInfo = runMaybeT $
mkField tCase fieldInfo = runMaybeT $ do
roleName <- retrieve scRole
case fieldInfo of
FIColumn columnInfo -> do
let fieldName = ciName columnInfo
@ -92,8 +93,8 @@ orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tab
<&> fmap (pure . mkOrderByItemG @b (IR.AOCColumn columnInfo)) . join
FIRelationship relationshipInfo -> do
remoteTableInfo <- askTableInfo sourceInfo $ riRTable relationshipInfo
perms <- hoistMaybe $ tableSelectPermissions roleName remoteTableInfo
fieldName <- hoistMaybe $ G.mkName $ relNameToTxt $ riName relationshipInfo
perms <- MaybeT $ tableSelectPermissions remoteTableInfo
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
case riType relationshipInfo of
ObjRel -> do
@ -128,7 +129,7 @@ orderByExp sourceInfo tableInfo = memoizeOn 'orderByExp (_siName sourceInfo, tab
ReturnsTable table -> do
let aggregateFieldName = applyFieldNameCaseIdentifier tCase $ C.fromTuple (fieldName, [G.convertNameToSuffix Name._aggregate])
tableInfo' <- askTableInfo sourceInfo table
perms <- MaybeT $ tableSelectPermissions tableInfo'
perms <- hoistMaybe $ tableSelectPermissions roleName tableInfo'
let newPerms = fmap partialSQLExpToUnpreparedValue <$> spiFilter perms
aggregationParser <- lift $ orderByAggregation sourceInfo tableInfo'
pure $ do

View File

@ -58,6 +58,7 @@ nodeInterface sourceCache = NodeInterfaceParserBuilder $ memoizeOn 'nodeInterfac
idField = P.selection_ Name._id (Just idDescription) P.identifier
nodeInterfaceDescription = G.Description "An object with globally unique ID"
tCase <- asks getter
roleName <- retrieve scRole
tables :: [Parser 'Output n (SourceName, AB.AnyBackend TableMap)] <-
catMaybes . concat <$> for (Map.toList sourceCache) \(sourceName, anySourceInfo) ->
AB.dispatchAnyBackendWithTwoConstraints @BackendSchema @BackendTableSelectSchema
@ -65,7 +66,7 @@ nodeInterface sourceCache = NodeInterfaceParserBuilder $ memoizeOn 'nodeInterfac
\(sourceInfo :: SourceInfo b) ->
for (Map.toList $ takeValidTables $ _siTables sourceInfo) \(tableName, tableInfo) -> runMaybeT do
tablePkeyColumns <- hoistMaybe $ tableInfo ^? tiCoreInfo . tciPrimaryKey . _Just . pkColumns
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
annotatedFieldsParser <-
MaybeT $
withTypenameCustomization

View File

@ -71,7 +71,7 @@ remoteRelationshipToSchemaField ::
RemoteSchemaFieldInfo ->
m (Maybe (FieldParser n (IR.RemoteSchemaSelect (IR.RemoteRelationshipField IR.UnpreparedValue))))
remoteRelationshipToSchemaField remoteSchemaCache remoteSchemaPermissions lhsFields RemoteSchemaFieldInfo {..} = runMaybeT do
roleName <- asks getter
roleName <- retrieve scRole
remoteSchemaContext <-
Map.lookup _rrfiRemoteSchemaName remoteSchemaCache
`onNothing` throw500 ("invalid remote schema name: " <>> _rrfiRemoteSchemaName)
@ -188,13 +188,13 @@ remoteRelationshipToSourceField ::
remoteRelationshipToSourceField sourceCache RemoteSourceFieldInfo {..} =
withTypenameCustomization (mkCustomizedTypename (Just _rsfiSourceCustomization) HasuraCase) do
tCase <- asks getter
roleName <- retrieve scRole
sourceInfo <-
onNothing (unsafeSourceInfo @tgt =<< Map.lookup _rsfiSource sourceCache) $
throw500 $ "source not found " <> dquote _rsfiSource
tableInfo <- askTableInfo sourceInfo _rsfiTable
fieldName <- textToName $ relNameToTxt _rsfiName
maybePerms <- tableSelectPermissions @tgt tableInfo
case maybePerms of
case tableSelectPermissions @tgt roleName tableInfo of
Nothing -> pure []
Just tablePerms -> do
parsers <- case _rsfiType of

View File

@ -104,7 +104,8 @@ defaultSelectTable ::
m (Maybe (FieldParser n (SelectExp b)))
defaultSelectTable sourceInfo tableInfo fieldName description = runMaybeT do
tCase <- asks getter
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
selectionSetParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
lift $ memoizeOn 'defaultSelectTable (_siName sourceInfo, tableName, fieldName) do
stringifyNumbers <- retrieve Options.soStringifyNumbers
@ -160,8 +161,9 @@ selectTableConnection ::
m (Maybe (FieldParser n (ConnectionSelectExp b)))
selectTableConnection sourceInfo tableInfo fieldName description pkeyColumns = runMaybeT do
tCase <- asks getter
roleName <- retrieve scRole
xRelayInfo <- hoistMaybe $ relayExtension @b
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
selectionSetParser <- fmap P.nonNullableParser <$> MaybeT $ tableConnectionSelectionSet sourceInfo tableInfo
lift $ memoizeOn 'selectTableConnection (_siName sourceInfo, tableName, fieldName) do
stringifyNumbers <- retrieve Options.soStringifyNumbers
@ -210,7 +212,8 @@ selectTableByPk ::
m (Maybe (FieldParser n (SelectExp b)))
selectTableByPk sourceInfo tableInfo fieldName description = runMaybeT do
tCase <- asks getter
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
primaryKeys <- hoistMaybe $ fmap _pkColumns . _tciPrimaryKey . _tiCoreInfo $ tableInfo
selectionSetParser <- MaybeT $ tableSelectionSet sourceInfo tableInfo
guard $ all (\c -> ciColumn c `Map.member` spiCols selectPermissions) primaryKeys
@ -264,7 +267,8 @@ defaultSelectTableAggregate ::
m (Maybe (FieldParser n (AggSelectExp b)))
defaultSelectTableAggregate sourceInfo tableInfo fieldName description = runMaybeT $ do
tCase <- asks getter
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
guard $ spiAllowAgg selectPermissions
xNodesAgg <- hoistMaybe $ nodesAggExtension @b
nodesParser <- MaybeT $ tableSelectionList sourceInfo tableInfo
@ -371,7 +375,8 @@ defaultTableSelectionSet ::
TableInfo b ->
m (Maybe (Parser 'Output n (AnnotatedFields b)))
defaultTableSelectionSet sourceInfo tableInfo = runMaybeT do
_selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
_selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
schemaKind <- lift $ retrieve scSchemaKind
-- If this check fails, it means we're attempting to build a Relay schema, but
-- the current backend b does't support Relay; rather than returning an
@ -475,8 +480,9 @@ tableConnectionSelectionSet ::
TableInfo b ->
m (Maybe (Parser 'Output n (ConnectionFields b)))
tableConnectionSelectionSet sourceInfo tableInfo = runMaybeT do
roleName <- retrieve scRole
tableGQLName <- lift $ getTableGQLName tableInfo
_selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
void $ hoistMaybe $ tableSelectPermissions roleName tableInfo
edgesParser <- MaybeT $ tableEdgesSelectionSet tableGQLName
lift $ memoizeOn 'tableConnectionSelectionSet (_siName sourceInfo, tableName) do
connectionTypeName <- mkTypename $ tableGQLName <> Name._Connection
@ -973,6 +979,7 @@ fieldSelection ::
fieldSelection sourceInfo table tableInfo = \case
FIColumn columnInfo ->
maybeToList <$> runMaybeT do
roleName <- retrieve scRole
schemaKind <- retrieve scSchemaKind
let fieldName = ciName columnInfo
-- If the field name is 'id' and we're building a schema for the Relay
@ -980,7 +987,7 @@ fieldSelection sourceInfo table tableInfo = \case
-- ignore the original.
guard $ isHasuraSchema schemaKind || fieldName /= Name._id
let columnName = ciColumn columnInfo
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
guard $ columnName `Map.member` spiCols selectPermissions
let caseBoolExp = join $ Map.lookup columnName (spiCols selectPermissions)
caseBoolExpUnpreparedValue =
@ -1124,15 +1131,16 @@ relationshipField ::
m (Maybe [FieldParser n (AnnotatedField b)])
relationshipField sourceInfo table ri = runMaybeT do
tCase <- asks getter
roleName <- retrieve scRole
optimizePermissionFilters <- retrieve Options.soOptimizePermissionFilters
tableInfo <- lift $ askTableInfo sourceInfo table
otherTableInfo <- lift $ askTableInfo sourceInfo $ riRTable ri
remotePerms <- MaybeT $ tableSelectPermissions otherTableInfo
tablePerms <- hoistMaybe $ tableSelectPermissions roleName tableInfo
remotePerms <- hoistMaybe $ tableSelectPermissions roleName otherTableInfo
relFieldName <- lift $ textToName $ relNameToTxt $ riName ri
-- START black magic to deduplicate permission checks
thisTablePerm <-
IR._tpFilter . tablePermissionsInfo
<$> MaybeT (tableSelectPermissions =<< askTableInfo sourceInfo table)
let deduplicatePermissions :: AnnBoolExp b (IR.UnpreparedValue b) -> AnnBoolExp b (IR.UnpreparedValue b)
let thisTablePerm = IR._tpFilter $ tablePermissionsInfo tablePerms
deduplicatePermissions :: AnnBoolExp b (IR.UnpreparedValue b) -> AnnBoolExp b (IR.UnpreparedValue b)
deduplicatePermissions x =
case (optimizePermissionFilters, x) of
(OptimizePermissionFilters, BoolAnd [BoolField (AVRelationship remoteRI remoteTablePerm)]) ->
@ -1192,7 +1200,6 @@ relationshipField sourceInfo table ri = runMaybeT do
nullable <- case (riIsManual ri, riInsertOrder ri) of
-- Automatically generated forward relationship
(False, BeforeParent) -> do
tableInfo <- askTableInfo sourceInfo table
let columns = Map.keys $ riMapping ri
fieldInfoMap = _tciFieldInfoMap $ _tiCoreInfo tableInfo
findColumn col = Map.lookup (fromCol @b col) fieldInfoMap ^? _Just . _FIColumn

View File

@ -250,7 +250,8 @@ selectStreamTable ::
Maybe G.Description ->
m (Maybe (P.FieldParser n (StreamSelectExp b)))
selectStreamTable sourceInfo tableInfo fieldName description = runMaybeT $ do
selectPermissions <- MaybeT $ tableSelectPermissions tableInfo
roleName <- retrieve scRole
selectPermissions <- hoistMaybe $ tableSelectPermissions roleName tableInfo
xStreamSubscription <- hoistMaybe $ streamSubscriptionExtension @b
stringifyNumbers <- retrieve Options.soStringifyNumbers
tableStreamArgsParser <- lift $ tableStreamArguments sourceInfo tableInfo

View File

@ -4,7 +4,6 @@ module Hasura.GraphQL.Schema.Table
tableSelectColumnsEnum,
tableUpdateColumnsEnum,
updateColumnsPlaceholderParser,
tablePermissions,
tableSelectPermissions,
tableSelectFields,
tableColumns,
@ -119,13 +118,13 @@ tableUpdateColumnsEnum ::
TableInfo b ->
m (Maybe (Parser 'Both n (Column b)))
tableUpdateColumnsEnum tableInfo = do
roleName <- retrieve scRole
tableGQLName <- getTableGQLName tableInfo
columns <- tableUpdateColumns tableInfo
enumName <- mkTypename $ tableGQLName <> Name.__update_column
let tableName = tableInfoName tableInfo
enumDesc = Just $ G.Description $ "update columns of table " <>> tableName
enumValues = do
column <- columns
column <- tableUpdateColumns roleName tableInfo
pure (define $ ciName column, ciColumn column)
pure $ P.enum enumName enumDesc <$> nonEmpty enumValues
where
@ -152,52 +151,40 @@ updateColumnsPlaceholderParser tableInfo = do
Nothing
)
tablePermissions ::
forall b r m.
(MonadReader r m, Has RoleName r) =>
TableInfo b ->
m (RolePermInfo b)
tablePermissions tableInfo = do
roleName <- asks getter
pure $ getRolePermInfo roleName tableInfo
tableSelectPermissions ::
forall b r m.
(MonadReader r m, Has RoleName r) =>
TableInfo b ->
m (Maybe (SelPermInfo b))
tableSelectPermissions tableInfo = _permSel <$> tablePermissions tableInfo
tableSelectPermissions :: RoleName -> TableInfo b -> Maybe (SelPermInfo b)
tableSelectPermissions role tableInfo = _permSel $ getRolePermInfo role tableInfo
tableSelectFields ::
forall b r m.
( Backend b,
MonadError QErr m,
MonadReader r m,
Has RoleName r
Has SchemaContext r
) =>
SourceInfo b ->
TableInfo b ->
m [FieldInfo b]
tableSelectFields sourceInfo tableInfo = do
roleName <- retrieve scRole
let tableFields = _tciFieldInfoMap . _tiCoreInfo $ tableInfo
permissions <- tableSelectPermissions tableInfo
filterM (canBeSelected permissions) $ Map.elems tableFields
permissions = tableSelectPermissions roleName tableInfo
filterM (canBeSelected roleName permissions) $ Map.elems tableFields
where
canBeSelected Nothing _ = pure False
canBeSelected (Just permissions) (FIColumn columnInfo) =
canBeSelected _ Nothing _ = pure False
canBeSelected _ (Just permissions) (FIColumn columnInfo) =
pure $ Map.member (ciColumn columnInfo) (spiCols permissions)
canBeSelected _ (FIRelationship relationshipInfo) = do
canBeSelected role _ (FIRelationship relationshipInfo) = do
tableInfo' <- askTableInfo sourceInfo $ riRTable relationshipInfo
isJust <$> tableSelectPermissions @b tableInfo'
canBeSelected (Just permissions) (FIComputedField computedFieldInfo) =
pure $ isJust $ tableSelectPermissions @b role tableInfo'
canBeSelected role (Just permissions) (FIComputedField computedFieldInfo) =
case computedFieldReturnType @b (_cfiReturnType computedFieldInfo) of
ReturnsScalar _ ->
pure $ Map.member (_cfiName computedFieldInfo) $ spiComputedFields permissions
ReturnsTable tableName -> do
tableInfo' <- askTableInfo sourceInfo tableName
isJust <$> tableSelectPermissions @b tableInfo'
pure $ isJust $ tableSelectPermissions @b role tableInfo'
ReturnsOthers -> pure False
canBeSelected _ (FIRemoteRelationship _) = pure True
canBeSelected _ _ (FIRemoteRelationship _) = pure True
tableColumns ::
forall b. TableInfo b -> [ColumnInfo b]
@ -214,7 +201,7 @@ tableSelectColumns ::
( Backend b,
MonadError QErr m,
MonadReader r m,
Has RoleName r
Has SchemaContext r
) =>
SourceInfo b ->
TableInfo b ->
@ -228,17 +215,14 @@ tableSelectColumns sourceInfo tableInfo =
-- | Get the columns of a table that my be updated under the given update
-- permissions.
tableUpdateColumns ::
forall b r m.
( Backend b,
MonadError QErr m,
MonadReader r m,
Has RoleName r
) =>
forall b.
Backend b =>
RoleName ->
TableInfo b ->
m [ColumnInfo b]
tableUpdateColumns tableInfo = do
permissions <- _permUpd <$> tablePermissions tableInfo
pure $ filter (isUpdatable permissions) $ tableColumns tableInfo
[ColumnInfo b]
tableUpdateColumns role tableInfo =
let permissions = _permUpd $ getRolePermInfo role tableInfo
in filter (isUpdatable permissions) $ tableColumns tableInfo
where
isUpdatable :: Maybe (UpdPermInfo b) -> ColumnInfo b -> Bool
isUpdatable (Just permissions) columnInfo = columnIsUpdatable && columnIsPermitted && columnHasNoPreset

View File

@ -25,11 +25,11 @@ import Hasura.Base.Error (QErr)
import Hasura.Base.ToErrorValue
import Hasura.GraphQL.Schema.Backend (BackendSchema (..), BackendTableSelectSchema (..), MonadBuildSchema, columnParser)
import Hasura.GraphQL.Schema.BoolExp (boolExp)
import Hasura.GraphQL.Schema.Common (Scenario (..), mapField, partialSQLExpToUnpreparedValue)
import Hasura.GraphQL.Schema.Common (Scenario (..), SchemaContext (..), mapField, partialSQLExpToUnpreparedValue, retrieve)
import Hasura.GraphQL.Schema.Mutation (mutationSelectionSet, primaryKeysArguments)
import Hasura.GraphQL.Schema.NamingCase
import Hasura.GraphQL.Schema.Parser qualified as P
import Hasura.GraphQL.Schema.Table (getTableGQLName, tableColumns, tablePermissions, tableUpdateColumns)
import Hasura.GraphQL.Schema.Table (getTableGQLName, tableColumns, tableUpdateColumns)
import Hasura.GraphQL.Schema.Typename
import Hasura.Prelude
import Hasura.RQL.IR.BoolExp (AnnBoolExp, annBoolExpTrue)
@ -115,7 +115,8 @@ runUpdateOperator ::
runUpdateOperator tableInfo UpdateOperator {..} = do
let tableName = tableInfoName tableInfo
tableGQLName <- getTableGQLName tableInfo
columns <- tableUpdateColumns tableInfo
roleName <- retrieve scRole
let columns = tableUpdateColumns roleName tableInfo
let applicableCols :: Maybe (NonEmpty (ColumnInfo b)) =
nonEmpty . filter updateOperatorApplicableColumn $ columns
@ -271,7 +272,8 @@ updateTable backendUpdate scenario sourceInfo tableInfo fieldName description =
whereDesc = "filter the rows which have to be updated"
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsUpdatable viewInfo
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
roleName <- retrieve scRole
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
-- If we're in a frontend scenario, we should not include backend_only updates
-- For more info see Note [Backend only permissions]
guard $ not $ scenario == Frontend && upiBackendOnly updatePerms
@ -308,7 +310,8 @@ updateTableByPk backendUpdate scenario sourceInfo tableInfo fieldName descriptio
tableName = tableInfoName tableInfo
viewInfo = _tciViewInfo $ _tiCoreInfo tableInfo
guard $ isMutable viIsUpdatable viewInfo
updatePerms <- MaybeT $ _permUpd <$> tablePermissions tableInfo
roleName <- retrieve scRole
updatePerms <- hoistMaybe $ _permUpd $ getRolePermInfo roleName tableInfo
-- If we're in a frontend scenario, we should not include backend_only updates
-- For more info see Note [Backend only permissions]
guard $ not $ scenario == Frontend && upiBackendOnly updatePerms

View File

@ -125,8 +125,7 @@ buildQueryParsers introspection = do
-- test, we are free to give 'undefined' for such fields, as they won't be
-- evaluated.
schemaInfo =
( adminRoleName :: RoleName,
mempty :: CustomizeRemoteFieldName,
( mempty :: CustomizeRemoteFieldName,
mempty :: MkTypename,
mempty :: MkRootFieldName,
HasuraCase :: NamingCase,
@ -134,6 +133,7 @@ buildQueryParsers introspection = do
SchemaContext
HasuraSchema
ignoreRemoteRelationship
adminRoleName
)
RemoteSchemaParser query _ _ <-
runError $

View File

@ -25,7 +25,7 @@ import Hasura.GraphQL.Schema.Options qualified as Options
import Hasura.GraphQL.Schema.Typename
import Hasura.Prelude
import Hasura.RQL.Types.SourceCustomization (CustomizeRemoteFieldName, MkRootFieldName)
import Hasura.Session (RoleName, adminRoleName)
import Hasura.Session (adminRoleName)
import Language.Haskell.TH.Syntax qualified as TH
import Test.Hspec
@ -51,13 +51,6 @@ instance Has NamingCase SchemaEnvironment where
modifier :: (NamingCase -> NamingCase) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has NamingCase SchemaEnvironment>"
instance Has RoleName SchemaEnvironment where
getter :: SchemaEnvironment -> RoleName
getter = const adminRoleName
modifier :: (RoleName -> RoleName) -> SchemaEnvironment -> SchemaEnvironment
modifier = notImplemented "modifier<Has RoleName SchemaEnvironment>"
instance Has SchemaOptions SchemaEnvironment where
getter :: SchemaEnvironment -> SchemaOptions
getter =
@ -78,7 +71,8 @@ instance Has SchemaContext SchemaEnvironment where
const
SchemaContext
{ scSchemaKind = HasuraSchema,
scRemoteRelationshipParserBuilder = ignoreRemoteRelationship
scRemoteRelationshipParserBuilder = ignoreRemoteRelationship,
scRole = adminRoleName
}
modifier :: (SchemaContext -> SchemaContext) -> SchemaEnvironment -> SchemaEnvironment