2022-08-24 11:30:55 +03:00
import collections
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
import http . server
2022-10-21 20:32:58 +03:00
import inspect
2022-08-15 17:29:02 +03:00
import os
2018-09-18 09:21:57 +03:00
import pytest
2022-08-15 17:29:02 +03:00
import re
2022-10-13 18:43:59 +03:00
import socket
2022-08-15 17:29:02 +03:00
import sqlalchemy
2019-04-08 10:22:38 +03:00
import sys
2022-08-15 17:29:02 +03:00
import threading
import time
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
from typing import Optional
2022-10-13 18:43:59 +03:00
import urllib . parse
2022-09-29 20:18:49 +03:00
import uuid
2022-08-15 17:29:02 +03:00
2022-09-29 13:42:47 +03:00
import auth_webhook_server
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
from context import ActionsWebhookServer , EvtsWebhookServer , GQLWsClient , GraphQLWSClient , HGECtx , HGECtxGQLServer , HGECtxWebhook , PytestConf
2022-09-15 15:30:01 +03:00
import fixtures . hge
2022-11-15 22:07:34 +03:00
import fixtures . postgres
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
import fixtures . tls
2022-09-15 00:41:28 +03:00
import ports
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
import webhook
2018-10-30 12:21:58 +03:00
2018-09-18 09:21:57 +03:00
def pytest_addoption ( parser ) :
2022-09-15 15:30:01 +03:00
parser . addoption (
" --hge-bin " ,
metavar = " HGE_BIN " ,
required = False ,
help = " Hasura GraphQL Engine binary executable " ,
)
2018-09-18 09:21:57 +03:00
parser . addoption (
2019-04-08 10:22:38 +03:00
" --hge-urls " ,
metavar = " HGE_URLS " ,
help = " csv list of urls for graphql-engine " ,
required = False ,
nargs = ' + '
2018-09-18 09:21:57 +03:00
)
parser . addoption (
2019-04-08 10:22:38 +03:00
" --pg-urls " , metavar = " PG_URLS " ,
help = " csv list of urls for connecting to Postgres directly " ,
required = False ,
nargs = ' + '
2018-09-18 09:21:57 +03:00
)
2022-10-13 18:43:59 +03:00
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
parser . addoption ( ' --tls-ca-cert ' , help = ' The CA certificate used for helper services ' , required = False )
parser . addoption ( ' --tls-ca-key ' , help = ' The CA key used for helper services ' , required = False )
2022-10-13 18:43:59 +03:00
2018-10-28 21:27:49 +03:00
parser . addoption (
2021-10-12 20:58:46 +03:00
" --hge-jwt-key-file " , metavar = " HGE_JWT_KEY_FILE " , help = " File containing the private key used to encode jwt tokens using RS512 algorithm " , required = False
2018-10-28 21:27:49 +03:00
)
2019-02-05 15:04:16 +03:00
parser . addoption (
" --hge-jwt-conf " , metavar = " HGE_JWT_CONF " , help = " The JWT conf " , required = False
)
2018-09-18 09:21:57 +03:00
2019-03-04 10:46:53 +03:00
parser . addoption (
" --test-ws-init-cookie " ,
metavar = " read|noread " ,
required = False ,
help = " Run testcases for testing cookie sending over websockets "
)
2019-03-12 08:46:27 +03:00
parser . addoption (
" --test-hge-scale-url " ,
metavar = " <url> " ,
required = False ,
help = " Run testcases for horizontal scaling "
)
2019-07-11 08:37:06 +03:00
parser . addoption (
" --test-logging " ,
action = " store_true " ,
default = False ,
required = False ,
help = " Run testcases for logging "
)
2022-02-09 08:13:32 +03:00
parser . addoption (
" --test-startup-db-calls " ,
action = " store_true " ,
default = False ,
required = False ,
help = " Run testcases for startup database calls "
)
2019-09-04 18:02:35 +03:00
parser . addoption (
" --accept " ,
action = " store_true " ,
default = False ,
required = False ,
help = " Accept any failing test cases from YAML files as correct, and write the new files out to disk. "
)
2020-02-13 12:14:02 +03:00
parser . addoption (
" --skip-schema-teardown " ,
action = " store_true " ,
default = False ,
required = False ,
help = """
Skip tearing down the schema / Hasura metadata after tests . This option may result in test failures if the schema
has to change between the list of tests to be run
"""
)
parser . addoption (
" --skip-schema-setup " ,
action = " store_true " ,
default = False ,
required = False ,
help = """
Skip setting up schema / Hasura metadata before tests .
This option may result in test failures if the schema has to change between the list of tests to be run
"""
)
2019-09-04 18:02:35 +03:00
2020-02-13 12:14:02 +03:00
parser . addoption (
" --avoid-error-message-checks " ,
action = " store_true " ,
default = False ,
required = False ,
help = """
This option when set will ignore disparity in error messages between expected and response outputs .
Used basically in version upgrade / downgrade tests where the error messages may change
"""
)
parser . addoption (
" --collect-upgrade-tests-to-file " ,
metavar = " <path> " ,
required = False ,
help = " When used along with collect-only, it will write the list of upgrade tests into the file specified "
)
2019-07-11 08:37:06 +03:00
2020-05-05 22:57:17 +03:00
parser . addoption (
" --test-unauthorized-role " ,
action = " store_true " ,
help = " Run testcases for unauthorized role " ,
)
2021-12-08 21:28:36 +03:00
parser . addoption (
" --test-no-cookie-and-unauth-role " ,
action = " store_true " ,
help = " Run testcases for no unauthorized role and no cookie jwt header set (cookie auth is set as part of jwt config upon engine startup) " ,
)
2021-02-13 03:05:23 +03:00
parser . addoption (
" --redis-url " ,
metavar = " REDIS_URL " ,
help = " redis url for cache server " ,
default = False
)
2021-03-11 21:17:41 +03:00
parser . addoption (
" --backend " ,
help = " run integration tests using a particular backend " ,
default = " postgres "
)
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
2021-05-05 15:25:27 +03:00
parser . addoption (
" --pro-tests " ,
action = " store_true " ,
default = False ,
help = " Flag to specify if the pro tests are to be run "
)
2022-02-21 12:59:02 +03:00
parser . addoption (
" --test-read-only-source " ,
action = " store_true " ,
default = False ,
required = False ,
help = " Run testcases with a read-only database source "
)
2021-05-05 15:25:27 +03:00
2019-04-08 10:22:38 +03:00
#By default,
2022-09-15 15:30:01 +03:00
#1) Set test grouping to by class (--dist=loadfile)
#2) Set default parallelism to one
2019-04-08 10:22:38 +03:00
def pytest_cmdline_preparse ( config , args ) :
worker = os . environ . get ( ' PYTEST_XDIST_WORKER ' )
if ' xdist ' in sys . modules and not worker : # pytest-xdist plugin
num = 1
2022-09-15 15:30:01 +03:00
args [ : ] = [ ' --dist=loadfile ' , f ' -n { num } ' ] + args
2019-04-08 10:22:38 +03:00
def pytest_configure ( config ) :
2019-11-29 08:14:26 +03:00
# Pytest has removed the global pytest.config
# As a solution we are going to store it in PytestConf.config
PytestConf . config = config
2020-02-13 12:14:02 +03:00
if is_help_option_present ( config ) :
return
2019-04-08 10:22:38 +03:00
if is_master ( config ) :
2022-09-15 15:30:01 +03:00
assert not config . getoption ( ' --exitfirst ' ) , ' The " --exitfirst " / " -x " option does not work with xdist. \n See: https://github.com/pytest-dev/pytest-xdist/issues/54 '
if not ( config . getoption ( ' --hge-bin ' ) or config . getoption ( ' --hge-urls ' ) ) :
print ( " either --hge-bin or --hge-urls should be specified " )
if config . getoption ( ' --hge-bin ' ) and config . getoption ( ' --hge-urls ' ) :
print ( " only one of --hge-bin or --hge-urls should be specified " )
2019-04-08 10:22:38 +03:00
if not config . getoption ( ' --pg-urls ' ) :
print ( " pg-urls should be specified " )
config . hge_url_list = config . getoption ( ' --hge-urls ' )
2021-02-13 03:05:23 +03:00
config . pg_url_list = config . getoption ( ' --pg-urls ' )
2022-11-15 22:07:34 +03:00
if not config . getoption ( ' --hge-bin ' ) and config . getoption ( ' -n ' , default = None ) :
2019-04-08 10:22:38 +03:00
xdist_threads = config . getoption ( ' -n ' )
2022-09-15 15:30:01 +03:00
assert config . getoption ( ' --hge-bin ' ) or xdist_threads < = len ( config . hge_url_list ) , " Not enough hge_urls specified, Required " + str ( xdist_threads ) + " , got " + str ( len ( config . hge_url_list ) )
2019-04-08 10:22:38 +03:00
assert xdist_threads < = len ( config . pg_url_list ) , " Not enough pg_urls specified, Required " + str ( xdist_threads ) + " , got " + str ( len ( config . pg_url_list ) )
2020-02-13 12:14:02 +03:00
@pytest.hookimpl ( )
def pytest_report_collectionfinish ( config , startdir , items ) :
"""
Collect server upgrade tests to the given file
"""
tests_file = config . getoption ( ' --collect-upgrade-tests-to-file ' )
2022-08-24 11:30:55 +03:00
tests = collections . OrderedDict ( )
2020-02-13 12:14:02 +03:00
if tests_file :
def is_upgrade_test ( item ) :
# Check if allow_server_upgrade_tests marker are present
# skip_server_upgrade_tests marker is not present
return item . get_closest_marker ( ' allow_server_upgrade_test ' ) \
and not item . get_closest_marker ( ' skip_server_upgrade_test ' )
with open ( tests_file , ' w ' ) as f :
upgrade_items = filter ( is_upgrade_test , items )
for item in upgrade_items :
# This test should be run separately,
# since its schema setup has function scope
if ' per_method_tests_db_state ' in item . fixturenames :
tests [ item . nodeid ] = True
elif any ( [ ( x in item . fixturenames )
for x in
[ ' per_class_tests_db_state ' ,
' per_class_db_schema_for_mutation_tests '
]
] ) :
# For this test, schema setup has class scope
# We can run a class of these tests at a time
tests [ item . parent . nodeid ] = True
# Assume tests can only be run separately
else :
tests [ item . nodeid ] = True
for test in tests . keys ( ) :
f . write ( test + ' \n ' )
return ' '
2019-04-08 10:22:38 +03:00
@pytest.hookimpl ( optionalhook = True )
def pytest_configure_node ( node ) :
2020-02-13 12:14:02 +03:00
if is_help_option_present ( node . config ) :
return
2022-09-15 15:30:01 +03:00
if not node . config . getoption ( ' --hge-bin ' ) :
node . workerinput [ " hge-url " ] = node . config . hge_url_list . pop ( )
2022-11-15 22:07:34 +03:00
node . workerinput [ " pg-url " ] = node . config . pg_url_list . pop ( )
2019-04-08 10:22:38 +03:00
2022-08-02 22:32:46 +03:00
def run_on_current_backend ( request : pytest . FixtureRequest ) :
current_backend = request . config . getoption ( ' --backend ' )
# Currently, we default all tests to run on Postgres with or without a --backend flag.
# As our test suite develops, we may consider running backend-agnostic tests on all
# backends, unless a specific `--backend` flag is passed.
desired_backends = set ( name for marker in request . node . iter_markers ( ' backend ' ) for name in marker . args ) or set ( [ ' postgres ' ] )
return current_backend in desired_backends
def per_backend_tests_fixture ( request : pytest . FixtureRequest ) :
"""
This fixture ignores backend - specific tests unless the relevant - - backend flag has been passed .
"""
if not run_on_current_backend ( request ) :
desired_backends = set ( name for marker in request . node . iter_markers ( ' backend ' ) for name in marker . args )
pytest . skip ( ' Skipping test. This test can run on ' + ' , ' . join ( desired_backends ) + ' . ' )
@pytest.fixture ( scope = ' class ' , autouse = True )
def per_backend_test_class ( request : pytest . FixtureRequest ) :
return per_backend_tests_fixture ( request )
@pytest.fixture ( scope = ' function ' , autouse = True )
def per_backend_test_function ( request : pytest . FixtureRequest ) :
return per_backend_tests_fixture ( request )
2022-09-28 12:19:47 +03:00
@pytest.fixture ( scope = ' session ' )
2022-11-15 22:07:34 +03:00
def pg_version ( owner_engine : sqlalchemy . engine . Engine ) - > int :
return fixtures . postgres . version ( owner_engine )
@pytest.fixture ( scope = ' session ' )
def owner_engine ( request : pytest . FixtureRequest , hge_bin : str ) :
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
if not hge_bin :
return sqlalchemy . engine . create_engine ( request . config . workerinput [ " pg-url " ] ) # type: ignore
return fixtures . postgres . owner_engine ( request )
@pytest.fixture ( scope = ' session ' )
def runner_engine ( owner_engine : sqlalchemy . engine . Engine ) :
return fixtures . postgres . runner_engine ( owner_engine )
2022-09-28 12:19:47 +03:00
2022-08-15 17:29:02 +03:00
@pytest.fixture ( scope = ' class ' )
2022-11-15 22:07:34 +03:00
def metadata_schema_url (
request : pytest . FixtureRequest ,
owner_engine : sqlalchemy . engine . Engine ,
runner_engine : sqlalchemy . engine . Engine ,
hge_bin : Optional [ str ] ,
) :
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
if not hge_bin :
return request . config . workerinput [ " pg-url " ] # type: ignore
return fixtures . postgres . metadata_schema_url ( request , owner_engine , runner_engine )
@pytest.fixture ( scope = ' class ' )
def source_backend (
request : pytest . FixtureRequest ,
owner_engine : sqlalchemy . engine . Engine ,
runner_engine : sqlalchemy . engine . Engine ,
hge_ctx_fixture : HGECtx ,
hge_bin : Optional [ str ] ,
) :
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
if not hge_bin :
yield None
return
yield from fixtures . postgres . source_backend ( request , owner_engine , runner_engine , hge_ctx_fixture )
@pytest.fixture ( scope = ' class ' )
def postgis ( owner_engine : sqlalchemy . engine . Engine , source_backend : fixtures . postgres . Backend ) :
return fixtures . postgres . postgis ( owner_engine , source_backend )
2022-09-15 15:30:01 +03:00
2022-10-13 18:43:59 +03:00
@pytest.fixture ( scope = ' session ' )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
def tls_ca_configuration ( request : pytest . FixtureRequest , tmp_path_factory : pytest . TempPathFactory ) - > Optional [ fixtures . tls . TLSCAConfiguration ] :
cert_file : Optional [ str ] = request . config . getoption ( ' --tls-ca-cert ' ) # type: ignore
key_file : Optional [ str ] = request . config . getoption ( ' --tls-ca-key ' ) # type: ignore
if cert_file and key_file :
tmp_path = tmp_path_factory . mktemp ( ' tls ' )
return fixtures . tls . TLSCAConfiguration ( cert_file , key_file , tmp_path )
2022-10-13 18:43:59 +03:00
else :
return None
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
2022-09-28 12:19:47 +03:00
@pytest.fixture ( scope = ' class ' , autouse = True )
2022-10-13 18:43:59 +03:00
def hge_skip ( request : pytest . FixtureRequest , hge_server : Optional [ str ] , hge_fixture_env : dict [ str , str ] ) :
2022-09-28 12:19:47 +03:00
# Let `hge_server` manage this stuff.
2022-09-15 15:30:01 +03:00
if hge_server :
2022-09-28 12:19:47 +03:00
return
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
2022-09-28 12:19:47 +03:00
# Ensure that the correct environment variables have been set for the given test.
hge_marker_env : dict [ str , str ] = { marker . args [ 0 ] : marker . args [ 1 ] for marker in request . node . iter_markers ( ' hge_env ' ) }
2022-10-13 18:43:59 +03:00
hge_env = { * * hge_marker_env , * * hge_fixture_env }
incorrect_env = { name : value for name , value in hge_env . items ( ) if os . getenv ( name ) != value }
2022-09-28 12:19:47 +03:00
if len ( incorrect_env ) > 0 :
pytest . skip (
' This test expects the following environment variables: '
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
+ ' , ' . join ( [ f ' { name !r} = { value !r} (not { os . getenv ( name ) !r} ) ' for name , value in incorrect_env . items ( ) ] ) )
# Make sure that if there's a webhook, the test expects that there's a webhook
if ' HASURA_GRAPHQL_AUTH_HOOK ' in os . environ :
if ' HASURA_GRAPHQL_AUTH_HOOK ' not in hge_fixture_env :
pytest . skip ( ' HGE expects a running webhook, but this test does not provide one. ' )
if os . environ [ ' HASURA_GRAPHQL_AUTH_HOOK ' ] != hge_fixture_env [ ' HASURA_GRAPHQL_AUTH_HOOK ' ] :
pytest . skip ( f ' HGE expects a running webhook at { os . environ [ " HASURA_GRAPHQL_AUTH_HOOK " ] } , but this test provides one at { hge_fixture_env [ " HASURA_GRAPHQL_AUTH_HOOK " ] } . ' )
2022-09-15 15:30:01 +03:00
2022-09-28 12:19:47 +03:00
@pytest.fixture ( scope = ' session ' )
def hge_bin ( request : pytest . FixtureRequest ) - > Optional [ str ] :
return request . config . getoption ( ' --hge-bin ' ) # type: ignore
2022-08-15 17:29:02 +03:00
@pytest.fixture ( scope = ' class ' )
2022-09-28 12:19:47 +03:00
def hge_port ( ) - > int :
2022-09-15 15:30:01 +03:00
return fixtures . hge . hge_port ( )
2022-09-28 12:19:47 +03:00
@pytest.fixture ( scope = ' class ' )
def hge_url ( request : pytest . FixtureRequest , hge_bin : Optional [ str ] , hge_port : int ) - > str :
if hge_bin :
return f ' http://localhost: { hge_port } '
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
2022-09-28 12:19:47 +03:00
else :
return request . config . workerinput [ ' hge-url ' ] # type: ignore
# A hack to inject environment variables from other fixtures into HGE.
# All of this is because we cannot cleanly express dependencies between
# fixtures of the form "this loads before that, IF that is loaded".
#
# This is marked as "early" so the `fixture-order` plugin ensures that it is
# loaded _before_ `hge_server`. Similarly, any fixture using it must be at
# the same scope level and also marked as "early", to ensure that it is
# mutated before `hge_server` uses the data.
#
# In short, we use `early` to ensure that writes happen before reads.
@pytest.fixture ( scope = ' class ' )
@pytest.mark.early
def hge_fixture_env ( ) - > dict [ str , str ] :
return { }
@pytest.fixture ( scope = ' class ' )
2022-09-29 20:18:49 +03:00
def hge_key (
request : pytest . FixtureRequest ,
hge_bin : Optional [ str ] ,
) - > Optional [ str ] :
marker = request . node . get_closest_marker ( ' admin_secret ' )
if hge_bin :
# If the test requests an admin secret, generate one.
return str ( uuid . uuid4 ( ) ) if marker else None
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
2022-09-29 20:18:49 +03:00
else :
# If the environment variable is set, use it.
# This will be used in the event that we start the server outside the test harness.
# We skip the test if it explicitly requires that we have no admin secret.
anti_marker = request . node . get_closest_marker ( ' no_admin_secret ' )
env_key = os . environ . get ( ' HASURA_GRAPHQL_ADMIN_SECRET ' )
if anti_marker and env_key :
pytest . skip ( ' This test requires that the admin secret is not set. ' )
return env_key
2022-09-28 12:19:47 +03:00
2022-09-15 15:30:01 +03:00
@pytest.fixture ( scope = ' class ' )
def hge_server (
request : pytest . FixtureRequest ,
2022-09-28 12:19:47 +03:00
hge_bin : Optional [ str ] ,
2022-09-15 15:30:01 +03:00
hge_port : int ,
2022-09-28 12:19:47 +03:00
hge_url : str ,
2022-09-29 20:18:49 +03:00
hge_key : Optional [ str ] ,
2022-09-28 12:19:47 +03:00
hge_fixture_env : dict [ str , str ] ,
2022-11-15 22:07:34 +03:00
metadata_schema_url : str ,
2022-09-28 12:19:47 +03:00
) - > Optional [ str ] :
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
2022-09-28 12:19:47 +03:00
if not hge_bin :
return None
2022-11-15 22:07:34 +03:00
return fixtures . hge . hge_server ( request , hge_bin , hge_port , hge_url , hge_key , hge_fixture_env , metadata_schema_url )
2022-09-29 20:18:49 +03:00
@pytest.fixture ( scope = ' class ' )
def enabled_apis ( request : pytest . FixtureRequest , hge_bin : Optional [ str ] ) - > Optional [ set [ str ] ] :
if hge_bin :
hge_marker_env : dict [ str , str ] = { marker . args [ 0 ] : marker . args [ 1 ] for marker in request . node . iter_markers ( ' hge_env ' ) if marker . args [ 1 ] is not None }
enabled_apis_str = hge_marker_env . get ( ' HASURA_GRAPHQL_ENABLED_APIS ' )
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
2022-09-29 20:18:49 +03:00
else :
enabled_apis_str = os . environ . get ( ' HASURA_GRAPHQL_ENABLED_APIS ' )
if not enabled_apis_str :
return None
return set ( enabled_apis_str . split ( ' , ' ) )
2022-09-15 15:30:01 +03:00
@pytest.fixture ( scope = ' class ' )
2022-11-15 22:07:34 +03:00
def hge_ctx_fixture (
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
request : pytest . FixtureRequest ,
hge_url : str ,
2022-11-15 22:07:34 +03:00
hge_bin : Optional [ str ] ,
metadata_schema_url : str ,
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
hge_key : Optional [ str ] ,
enabled_apis : Optional [ set [ str ] ] ,
) :
# This madness allows us to figure out whether there is a webhook running.
# We need this information because we dynamically decide how we run queries according to the authentication method.
# This is probably terrible, but refactoring that logic would require rewriting every test.
webhook : Optional [ HGECtxWebhook ] = None
if webhook_server . __name__ in request . fixturenames :
webhook = request . getfixturevalue ( webhook_server . __name__ )
elif ' query_echo_webhook ' in request . fixturenames : # in test_webhook_request_context.py
webhook = HGECtxWebhook ( tls_trust = None )
hge_ctx = HGECtx (
hge_url = hge_url ,
2022-11-15 22:07:34 +03:00
metadata_schema_url = metadata_schema_url ,
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
hge_key = hge_key ,
webhook = webhook ,
enabled_apis = enabled_apis ,
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
clear_dbs = not hge_bin ,
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
config = request . config ,
)
2022-09-15 15:30:01 +03:00
yield hge_ctx
2019-04-08 10:22:38 +03:00
2018-09-18 09:21:57 +03:00
hge_ctx . teardown ( )
2022-09-15 15:30:01 +03:00
time . sleep ( 1 ) # TODO why do we sleep here?
2019-04-08 10:22:38 +03:00
2022-11-15 22:07:34 +03:00
# tie everything together
@pytest.fixture ( scope = ' class ' )
def hge_ctx (
hge_ctx_fixture : HGECtx ,
hge_server : Optional [ str ] ,
source_backend : Optional [ fixtures . postgres . Backend ] ,
) :
return hge_ctx_fixture
2019-04-08 10:22:38 +03:00
@pytest.fixture ( scope = ' class ' )
2022-09-28 12:19:47 +03:00
@pytest.mark.early
def evts_webhook ( hge_fixture_env : dict [ str , str ] ) :
2022-10-21 20:32:58 +03:00
server = EvtsWebhookServer ( extract_server_address_from ( ' EVENT_WEBHOOK_HANDLER ' ) )
thread = threading . Thread ( target = server . serve_forever )
thread . start ( )
print ( f ' { evts_webhook . __name__ } server started on { server . url } ' )
hge_fixture_env [ ' EVENT_WEBHOOK_HANDLER ' ] = server . url
yield server
server . shutdown ( )
server . server_close ( )
thread . join ( )
2019-04-08 10:22:38 +03:00
2022-08-15 17:29:02 +03:00
@pytest.fixture ( scope = ' class ' )
2022-09-28 12:19:47 +03:00
@pytest.mark.early
2022-10-12 17:26:33 +03:00
def actions_fixture ( hge_url : str , hge_key : Optional [ str ] , hge_fixture_env : dict [ str , str ] ) :
2022-10-21 20:32:58 +03:00
# Start actions' webhook server
server = ActionsWebhookServer ( hge_url , hge_key , server_address = extract_server_address_from ( ' ACTION_WEBHOOK_HANDLER ' ) )
2022-10-12 17:26:33 +03:00
thread = threading . Thread ( target = server . serve_forever )
thread . start ( )
2022-10-21 20:32:58 +03:00
print ( f ' { actions_fixture . __name__ } server started on { server . url } ' )
2022-10-12 17:26:33 +03:00
hge_fixture_env [ ' ACTION_WEBHOOK_HANDLER ' ] = server . url
yield server
server . shutdown ( )
server . server_close ( )
thread . join ( )
2020-02-13 20:38:23 +03:00
2021-08-09 13:20:04 +03:00
use_action_fixtures = pytest . mark . usefixtures (
2022-09-29 13:42:47 +03:00
' actions_fixture ' ,
2021-08-09 13:20:04 +03:00
' per_class_db_schema_for_mutation_tests ' ,
' per_method_db_data_for_mutation_tests '
)
2021-01-29 08:48:17 +03:00
@pytest.fixture ( scope = ' class ' )
2022-09-29 13:42:47 +03:00
@pytest.mark.early
def auth_hook ( hge_fixture_env : dict [ str , str ] ) :
2022-10-21 20:32:58 +03:00
server = auth_webhook_server . create_server ( extract_server_address_from ( ' HASURA_GRAPHQL_AUTH_HOOK ' ) )
thread = threading . Thread ( target = server . serve_forever )
thread . start ( )
print ( f ' { auth_hook . __name__ } server started on { server . url } ' )
hge_fixture_env [ ' HASURA_GRAPHQL_AUTH_HOOK ' ] = server . url + ' /auth '
2022-09-29 13:42:47 +03:00
ports . wait_for_port ( server . server_port )
yield server
auth_webhook_server . stop_server ( server )
2021-08-09 13:20:04 +03:00
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
@pytest.fixture ( scope = ' class ' )
@pytest.mark.early
def webhook_server (
request : pytest . FixtureRequest ,
hge_bin : Optional [ str ] ,
hge_fixture_env : dict [ str , str ] ,
tls_ca_configuration : Optional [ fixtures . tls . TLSCAConfiguration ] ,
) :
2022-10-27 14:47:48 +03:00
server_address = extract_server_address_from ( ' HASURA_GRAPHQL_AUTH_HOOK ' )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
scheme = None
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
if not hge_bin :
scheme = str ( urllib . parse . urlparse ( os . getenv ( ' HASURA_GRAPHQL_AUTH_HOOK ' ) ) . scheme )
if tls_ca_configuration :
if scheme is not None and scheme != ' https ' :
pytest . skip ( f ' Cannot run the remote schema server with TLS; HGE is configured to talk to it over " { scheme } " . ' )
if request . node . get_closest_marker ( ' no_tls_webhook_server ' ) is not None :
pytest . skip ( ' Only running this test with TLS disabled; skipping the version with TLS enabled. ' )
2022-10-27 14:47:48 +03:00
server = http . server . HTTPServer ( server_address , webhook . Handler )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
insecure = request . node . get_closest_marker ( ' tls_insecure_certificate ' ) is not None
tls_trust = fixtures . tls . TLSTrust . INSECURE if insecure else fixtures . tls . TLSTrust . SECURE
tls_ca_configuration . configure ( server , tls_trust )
else :
if scheme is not None and scheme != ' http ' :
pytest . skip ( f ' Cannot run the remote schema server without TLS; HGE is configured to talk to it over " { scheme } " . ' )
if request . node . get_closest_marker ( ' tls_webhook_server ' ) is not None :
pytest . skip ( ' Only running this test with TLS enabled; skipping the version with TLS disabled. ' )
2022-10-27 14:47:48 +03:00
server = http . server . HTTPServer ( server_address , webhook . Handler )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
tls_trust = None
thread = threading . Thread ( target = server . serve_forever )
thread . start ( )
request . addfinalizer ( server . shutdown )
scheme = ' https ' if tls_trust else ' http '
# We must use 'localhost' and not `server.server_address[0]`
# because when using TLS, we need a domain name, not an IP address.
host = ' localhost '
port = server . server_address [ 1 ]
hge_fixture_env [ ' HASURA_GRAPHQL_AUTH_HOOK ' ] = f ' { scheme } :// { host } : { port } / '
ports . wait_for_port ( port )
return HGECtxWebhook ( tls_trust = tls_trust )
2021-05-05 15:25:27 +03:00
@pytest.fixture ( scope = ' class ' )
def pro_tests_fixtures ( hge_ctx ) :
if not hge_ctx . pro_tests :
pytest . skip ( ' These tests are meant to be run with --pro-tests set ' )
2020-05-13 15:33:16 +03:00
@pytest.fixture ( scope = ' class ' )
2022-09-28 12:19:47 +03:00
@pytest.mark.early
def scheduled_triggers_evts_webhook ( hge_fixture_env : dict [ str , str ] ) :
2022-10-21 20:32:58 +03:00
server = EvtsWebhookServer ( extract_server_address_from ( ' SCHEDULED_TRIGGERS_WEBHOOK_DOMAIN ' ) )
thread = threading . Thread ( target = server . serve_forever )
thread . start ( )
print ( f ' { scheduled_triggers_evts_webhook . __name__ } server started on { server . url } ' )
hge_fixture_env [ ' SCHEDULED_TRIGGERS_WEBHOOK_DOMAIN ' ] = server . url
yield server
server . shutdown ( )
server . server_close ( )
thread . join ( )
2020-05-13 15:33:16 +03:00
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
# This will use TLS on CI, and won't when run locally. Unfortunately,
# parameterization doesn't really work (see test_webhook.py and test_tests.py
# for details), so we shall avoid it in favor of just testing what we can.
@pytest.fixture ( scope = ' class ' )
2022-09-15 00:41:28 +03:00
@pytest.mark.early
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
def gql_server (
request : pytest . FixtureRequest ,
hge_bin : Optional [ str ] ,
hge_url : str ,
hge_fixture_env : dict [ str , str ] ,
tls_ca_configuration : Optional [ fixtures . tls . TLSCAConfiguration ] ,
) :
2022-10-21 20:32:58 +03:00
server_address = extract_server_address_from ( ' REMOTE_SCHEMAS_WEBHOOK_DOMAIN ' )
2022-10-13 18:43:59 +03:00
scheme = None
2022-11-15 22:07:34 +03:00
# TODO: remove once parallelization work is completed
# `hge_bin` will no longer be optional
2022-10-13 18:43:59 +03:00
if not hge_bin :
scheme = str ( urllib . parse . urlparse ( os . getenv ( ' REMOTE_SCHEMAS_WEBHOOK_DOMAIN ' ) ) . scheme )
2022-10-21 20:32:58 +03:00
if socket . socket ( socket . AF_INET , socket . SOCK_STREAM ) . connect_ex ( server_address ) == 0 :
# The server is already running. This might be the case if we're running the server upgrade/downgrade tests.
# In this case, skip starting it and rely on the external service.
url = f ' http:// { server_address [ 0 ] } : { server_address [ 1 ] } '
hge_fixture_env [ ' REMOTE_SCHEMAS_WEBHOOK_DOMAIN ' ] = url
# Create an object with a field named "url", set to `url`.
return collections . namedtuple ( ' ExternalGraphQLServer ' , [ ' url ' ] ) ( url )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
if tls_ca_configuration :
2022-10-13 18:43:59 +03:00
if scheme is not None and scheme != ' https ' :
pytest . skip ( f ' Cannot run the remote schema server with TLS; HGE is configured to talk to it over " { scheme } " . ' )
else :
if scheme is not None and scheme != ' http ' :
pytest . skip ( f ' Cannot run the remote schema server without TLS; HGE is configured to talk to it over " { scheme } " . ' )
2022-10-21 20:32:58 +03:00
hge_urls : list [ str ] = request . config . getoption ( ' --hge-urls ' ) or [ hge_url ] # type: ignore
server = HGECtxGQLServer (
server_address = server_address ,
tls_ca_configuration = tls_ca_configuration ,
hge_urls = hge_urls ,
)
2022-09-15 00:41:28 +03:00
server . start_server ( )
2022-10-21 20:32:58 +03:00
print ( f ' { gql_server . __name__ } server started on { server . url } ' )
2022-09-28 12:19:47 +03:00
hge_fixture_env [ ' REMOTE_SCHEMAS_WEBHOOK_DOMAIN ' ] = server . url
2022-10-13 18:43:59 +03:00
request . addfinalizer ( server . stop_server )
return server
2020-05-13 15:33:16 +03:00
2019-04-08 10:22:38 +03:00
@pytest.fixture ( scope = ' class ' )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
def ws_client ( hge_ctx ) :
2020-02-13 12:14:02 +03:00
"""
This fixture provides an Apollo GraphQL websockets client
"""
2019-05-10 09:05:11 +03:00
client = GQLWsClient ( hge_ctx , ' /v1/graphql ' )
2019-04-08 10:22:38 +03:00
time . sleep ( 0.1 )
yield client
client . teardown ( )
2018-10-28 21:27:49 +03:00
2021-08-24 19:25:12 +03:00
@pytest.fixture ( scope = ' class ' )
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
def ws_client_graphql_ws ( hge_ctx ) :
2021-08-24 19:25:12 +03:00
"""
This fixture provides an GraphQL - WS client
"""
client = GraphQLWSClient ( hge_ctx , ' /v1/graphql ' )
time . sleep ( 0.1 )
yield client
client . teardown ( )
2022-10-21 20:32:58 +03:00
def extract_server_address_from ( env_var : str ) - > tuple [ str , int ] :
"""
Extracts a server address ( a pair of host and port ) from the given environment variable .
If the environment variable doesn ' t exist, returns `( ' localhost ' , 0)`.
"""
value = os . getenv ( env_var )
if not value :
return ( ' localhost ' , 0 )
url = urllib . parse . urlparse ( value )
if not url . hostname :
raise Exception ( f ' Invalid host in { env_var } . ' )
if not url . port :
raise Exception ( f ' Invalid port in { env_var } . ' )
print ( f ' Found { env_var } = { value !r} , so { inspect . stack ( ) [ 1 ] . function } server will start on { url . geturl ( ) } ' )
return ( url . hostname , url . port )
2018-10-28 21:27:49 +03:00
@pytest.fixture ( scope = ' class ' )
2020-02-13 12:14:02 +03:00
def per_class_tests_db_state ( request , hge_ctx ) :
"""
Set up the database state for select queries .
Has a class level scope , since select queries does not change database state
Expects either ` dir ( ) ` method which provides the directory
with ` setup . yaml ` and ` teardown . yaml ` files
Or class variables ` setup_files ` and ` teardown_files ` that provides
2021-07-01 12:20:53 +03:00
the list of setup and teardown files respectively .
By default , for a postgres backend the setup and teardown is done via
the ` / v1 / query ` endpoint , to setup using the ` / v1 / metadata ` ( metadata setup )
and ` / v2 / query ` ( DB setup ) , set the ` setup_metadata_api_version ` to " v2 "
2018-10-28 21:27:49 +03:00
"""
2020-02-13 12:14:02 +03:00
yield from db_state_context ( request , hge_ctx )
@pytest.fixture ( scope = ' function ' )
def per_method_tests_db_state ( request , hge_ctx ) :
2018-10-28 21:27:49 +03:00
"""
2020-02-13 12:14:02 +03:00
This fixture sets up the database state for metadata operations
Has a function level scope , since metadata operations may change both the schema and data
Class method / variable requirements are similar to that of per_class_tests_db_state fixture
"""
yield from db_state_context ( request , hge_ctx )
@pytest.fixture ( scope = ' class ' )
def per_class_db_schema_for_mutation_tests ( request , hge_ctx ) :
"""
This fixture sets up the database schema for mutations .
It has a class level scope , since mutations does not change schema .
Expects either ` dir ( ) ` class method which provides the directory with ` schema_setup . yaml ` and ` schema_teardown . yaml ` files ,
or variables ` schema_setup_files ` and ` schema_teardown_files `
that provides the list of setup and teardown files respectively
"""
2021-08-09 13:20:04 +03:00
# setting the default metadata API version to v1
setup_metadata_api_version = getattr ( request . cls , ' setup_metadata_api_version ' , " v1 " )
2021-10-29 17:42:07 +03:00
( setup , teardown , schema_setup , schema_teardown , pre_setup , post_teardown ) = [
2021-10-01 15:52:19 +03:00
hge_ctx . backend_suffix ( filename ) + " .yaml "
2021-10-29 17:42:07 +03:00
for filename in [ ' setup ' , ' teardown ' , ' schema_setup ' , ' schema_teardown ' , ' pre_setup ' , ' post_teardown ' ]
2021-10-01 15:52:19 +03:00
]
if hge_ctx . is_default_backend :
if setup_metadata_api_version == " v1 " :
db_context = db_context_with_schema_common (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
' schema_setup_files ' , ' schema_setup.yaml ' ,
' schema_teardown_files ' , ' schema_teardown.yaml ' ,
2021-10-01 15:52:19 +03:00
)
else :
2022-08-02 22:32:46 +03:00
db_context = db_context_with_schema_common_new (
request , hge_ctx ,
' schema_setup_files ' , setup ,
' schema_teardown_files ' , teardown ,
schema_setup , schema_teardown ,
pre_setup , post_teardown ,
2021-10-01 15:52:19 +03:00
)
2021-08-09 13:20:04 +03:00
else :
2022-08-02 22:32:46 +03:00
db_context = db_context_with_schema_common_new (
request , hge_ctx ,
' schema_setup_files ' , setup ,
' schema_teardown_files ' , teardown ,
schema_setup , schema_teardown ,
pre_setup , post_teardown ,
2021-08-09 13:20:04 +03:00
)
2021-10-01 15:52:19 +03:00
yield from db_context
2020-02-13 12:14:02 +03:00
@pytest.fixture ( scope = ' function ' )
def per_method_db_data_for_mutation_tests ( request , hge_ctx , per_class_db_schema_for_mutation_tests ) :
"""
This fixture sets up the data for mutations .
Has a function level scope , since mutations may change data .
Having just the setup file ( s ) , or the teardown file ( s ) is allowed .
Expects either ` dir ( ) ` class method which provides the directory with ` values_setup . yaml ` and / or ` values_teardown . yaml ` files .
The class may provide ` values_setup_files ` variables which contains the list of data setup files ,
Or the ` values_teardown_files ` variable which provides the list of data teardown files .
"""
2021-10-01 15:52:19 +03:00
# Non-default (Postgres) backend tests expect separate setup and schema_setup
# files for v1/metadata and v2/query requests, respectively.
( values_setup , values_teardown ) = [
hge_ctx . backend_suffix ( filename ) + " .yaml "
for filename in [ ' values_setup ' , ' values_teardown ' ]
]
2020-02-13 12:14:02 +03:00
yield from db_context_common (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
' values_setup_files ' , values_setup ,
2021-10-01 15:52:19 +03:00
' values_teardown_files ' , values_teardown ,
2022-08-02 22:32:46 +03:00
skip_setup = False , skip_teardown = False
2020-02-13 12:14:02 +03:00
)
def db_state_context ( request , hge_ctx ) :
2021-03-11 21:17:41 +03:00
# Non-default (Postgres) backend tests expect separate setup and schema_setup
# files for v1/metadata and v2/query requests, respectively.
2021-10-29 17:42:07 +03:00
( setup , teardown , schema_setup , schema_teardown , pre_setup , post_teardown ) = [
2021-03-11 21:17:41 +03:00
hge_ctx . backend_suffix ( filename ) + " .yaml "
2021-10-29 17:42:07 +03:00
for filename in [ ' setup ' , ' teardown ' , ' schema_setup ' , ' schema_teardown ' , ' pre_setup ' , ' post_teardown ' ]
2021-03-11 21:17:41 +03:00
]
2020-02-13 12:14:02 +03:00
2021-07-01 12:20:53 +03:00
# setting the default metadata API version to v1
setup_metadata_api_version = getattr ( request . cls , ' setup_metadata_api_version ' , " v1 " )
2021-05-25 16:54:18 +03:00
if hge_ctx . is_default_backend :
2021-07-01 12:20:53 +03:00
if setup_metadata_api_version == " v1 " :
# setup the metadata and DB schema using the `/v1/query` endpoint
db_context = db_context_with_schema_common (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
' setup_files ' , ' setup.yaml ' ,
' teardown_files ' , ' teardown.yaml ' ,
)
2021-07-01 12:20:53 +03:00
elif setup_metadata_api_version == " v2 " :
# setup the metadata using the "/v1/metadata" and the DB schema using the `/v2/query` endpoints
2022-08-02 22:32:46 +03:00
db_context = db_context_with_schema_common_new (
request , hge_ctx ,
' setup_files ' , setup ,
' teardown_files ' , teardown ,
schema_setup , schema_teardown ,
pre_setup , post_teardown ,
2021-07-01 12:20:53 +03:00
)
2022-07-05 21:00:08 +03:00
else :
raise NotImplementedError ( ' Invalid API version. ' )
2021-03-11 21:17:41 +03:00
else :
2021-07-01 12:20:53 +03:00
# setup the metadata using the "/v1/metadata" and the DB schema using the `/v2/query` endpoints
2022-08-02 22:32:46 +03:00
db_context = db_context_with_schema_common_new (
request , hge_ctx ,
' setup_files ' , setup ,
' teardown_files ' , teardown ,
schema_setup , schema_teardown ,
pre_setup , post_teardown ,
2021-03-11 21:17:41 +03:00
)
yield from db_context
2020-02-13 12:14:02 +03:00
def db_context_with_schema_common (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
setup_files_attr , setup_default_file ,
teardown_files_attr , teardown_default_file ,
) :
2020-02-13 12:14:02 +03:00
( skip_setup , skip_teardown ) = [
request . config . getoption ( ' -- ' + x )
for x in [ ' skip-schema-setup ' , ' skip-schema-teardown ' ]
]
yield from db_context_common (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
setup_files_attr , setup_default_file ,
2020-02-13 12:14:02 +03:00
teardown_files_attr , teardown_default_file ,
2022-08-02 22:32:46 +03:00
skip_setup , skip_teardown
2020-02-13 12:14:02 +03:00
)
2022-08-02 22:32:46 +03:00
def db_context_with_schema_common_new (
request , hge_ctx ,
setup_files_attr , setup_default_file ,
teardown_files_attr , teardown_default_file ,
setup_sql_file , teardown_sql_file ,
pre_setup_file , post_teardown_file ,
) :
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
( skip_setup , skip_teardown ) = [
request . config . getoption ( ' -- ' + x )
for x in [ ' skip-schema-setup ' , ' skip-schema-teardown ' ]
]
2022-08-02 22:32:46 +03:00
yield from db_context_common_new (
request , hge_ctx ,
setup_files_attr , setup_default_file , setup_sql_file ,
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
teardown_files_attr , teardown_default_file , teardown_sql_file ,
2021-10-29 17:42:07 +03:00
pre_setup_file , post_teardown_file ,
2022-08-02 22:32:46 +03:00
skip_setup , skip_teardown
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
)
2020-02-13 12:14:02 +03:00
def db_context_common (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
setup_files_attr , setup_default_file ,
2020-02-13 12:14:02 +03:00
teardown_files_attr , teardown_default_file ,
2022-08-02 22:32:46 +03:00
skip_setup = True , skip_teardown = True
) :
2020-02-13 12:14:02 +03:00
def get_files ( attr , default_file ) :
files = getattr ( request . cls , attr , None )
if not files :
files = os . path . join ( request . cls . dir ( ) , default_file )
return files
setup = get_files ( setup_files_attr , setup_default_file )
teardown = get_files ( teardown_files_attr , teardown_default_file )
2021-10-01 15:52:19 +03:00
if hge_ctx . is_default_backend :
2022-08-02 22:32:46 +03:00
yield from setup_and_teardown_v1q (
request , hge_ctx ,
setup , teardown ,
skip_setup , skip_teardown
)
2021-10-01 15:52:19 +03:00
else :
2022-08-02 22:32:46 +03:00
yield from setup_and_teardown_v2q (
request , hge_ctx ,
setup , teardown ,
skip_setup , skip_teardown
)
2021-10-01 15:52:19 +03:00
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
def db_context_common_new (
2022-08-02 22:32:46 +03:00
request , hge_ctx ,
setup_files_attr , setup_default_file , setup_default_sql_file ,
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
teardown_files_attr , teardown_default_file , teardown_default_sql_file ,
2021-10-29 17:42:07 +03:00
pre_setup_file , post_teardown_file ,
2022-08-02 22:32:46 +03:00
skip_setup = True , skip_teardown = True
) :
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
def get_files ( attr , default_file ) :
files = getattr ( request . cls , attr , None )
if not files :
files = os . path . join ( request . cls . dir ( ) , default_file )
return files
setup = get_files ( setup_files_attr , setup_default_file )
teardown = get_files ( teardown_files_attr , teardown_default_file )
setup_default_sql_file = os . path . join ( request . cls . dir ( ) , setup_default_sql_file )
teardown_default_sql_file = os . path . join ( request . cls . dir ( ) , teardown_default_sql_file )
2021-10-29 17:42:07 +03:00
pre_setup_default_file = os . path . join ( request . cls . dir ( ) , pre_setup_file )
post_teardown_default_file = os . path . join ( request . cls . dir ( ) , post_teardown_file )
2022-08-02 22:32:46 +03:00
yield from setup_and_teardown (
request , hge_ctx ,
setup , teardown ,
setup_default_sql_file , teardown_default_sql_file ,
pre_setup_default_file , post_teardown_default_file ,
skip_setup , skip_teardown
)
def setup_and_teardown_v1q (
request , hge_ctx ,
setup_files , teardown_files ,
skip_setup = False , skip_teardown = False
) :
2022-07-05 21:00:08 +03:00
def v1q_f ( filepath ) :
if os . path . isfile ( filepath ) :
return hge_ctx . v1q_f ( filepath )
2020-02-13 12:14:02 +03:00
if not skip_setup :
run_on_elem_or_list ( v1q_f , setup_files )
yield
# Teardown anyway if any of the tests have failed
if request . session . testsfailed > 0 or not skip_teardown :
run_on_elem_or_list ( v1q_f , teardown_files )
2022-08-02 22:32:46 +03:00
def setup_and_teardown_v2q (
request , hge_ctx ,
setup_files , teardown_files ,
skip_setup = False , skip_teardown = False
) :
2022-07-05 21:00:08 +03:00
def v2q_f ( filepath ) :
if os . path . isfile ( filepath ) :
return hge_ctx . v2q_f ( filepath )
2021-10-01 15:52:19 +03:00
if not skip_setup :
run_on_elem_or_list ( v2q_f , setup_files )
yield
# Teardown anyway if any of the tests have failed
if request . session . testsfailed > 0 or not skip_teardown :
run_on_elem_or_list ( v2q_f , teardown_files )
2022-08-02 22:32:46 +03:00
def setup_and_teardown (
request , hge_ctx ,
setup_files , teardown_files ,
sql_schema_setup_file , sql_schema_teardown_file ,
pre_setup_file , post_teardown_file ,
skip_setup = False , skip_teardown = False
) :
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
def v2q_f ( f ) :
if os . path . isfile ( f ) :
2022-07-05 21:00:08 +03:00
try :
hge_ctx . v2q_f ( f )
except AssertionError :
try :
run_on_elem_or_list ( pre_post_metadataq_f , post_teardown_file )
except :
pass
raise
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
def metadataq_f ( f ) :
if os . path . isfile ( f ) :
2022-07-05 21:00:08 +03:00
try :
hge_ctx . v1metadataq_f ( f )
except AssertionError :
try :
# drop the sql setup, if the metadata calls fail
run_on_elem_or_list ( v2q_f , sql_schema_teardown_file )
run_on_elem_or_list ( pre_post_metadataq_f , post_teardown_file )
except :
pass
raise
2021-10-29 17:42:07 +03:00
def pre_post_metadataq_f ( f ) :
if os . path . isfile ( f ) :
2022-07-05 21:00:08 +03:00
hge_ctx . v1metadataq_f ( f )
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
if not skip_setup :
2021-10-29 17:42:07 +03:00
run_on_elem_or_list ( pre_post_metadataq_f , pre_setup_file )
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
run_on_elem_or_list ( v2q_f , sql_schema_setup_file )
run_on_elem_or_list ( metadataq_f , setup_files )
yield
# Teardown anyway if any of the tests have failed
if request . session . testsfailed > 0 or not skip_teardown :
run_on_elem_or_list ( metadataq_f , teardown_files )
run_on_elem_or_list ( v2q_f , sql_schema_teardown_file )
2021-10-29 17:42:07 +03:00
run_on_elem_or_list ( pre_post_metadataq_f , post_teardown_file )
[Preview] Inherited roles for postgres read queries
fixes #3868
docker image - `hasura/graphql-engine:inherited-roles-preview-48b73a2de`
Note:
To be able to use the inherited roles feature, the graphql-engine should be started with the env variable `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` set to `inherited_roles`.
Introduction
------------
This PR implements the idea of multiple roles as presented in this [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/FGALanguageICDE07.pdf). The multiple roles feature in this PR can be used via inherited roles. An inherited role is a role which can be created by combining multiple singular roles. For example, if there are two roles `author` and `editor` configured in the graphql-engine, then we can create a inherited role with the name of `combined_author_editor` role which will combine the select permissions of the `author` and `editor` roles and then make GraphQL queries using the `combined_author_editor`.
How are select permissions of different roles are combined?
------------------------------------------------------------
A select permission includes 5 things:
1. Columns accessible to the role
2. Row selection filter
3. Limit
4. Allow aggregation
5. Scalar computed fields accessible to the role
Suppose there are two roles, `role1` gives access to the `address` column with row filter `P1` and `role2` gives access to both the `address` and the `phone` column with row filter `P2` and we create a new role `combined_roles` which combines `role1` and `role2`.
Let's say the following GraphQL query is queried with the `combined_roles` role.
```graphql
query {
employees {
address
phone
}
}
```
This will translate to the following SQL query:
```sql
select
(case when (P1 or P2) then address else null end) as address,
(case when P2 then phone else null end) as phone
from employee
where (P1 or P2)
```
The other parameters of the select permission will be combined in the following manner:
1. Limit - Minimum of the limits will be the limit of the inherited role
2. Allow aggregations - If any of the role allows aggregation, then the inherited role will allow aggregation
3. Scalar computed fields - same as table column fields, as in the above example
APIs for inherited roles:
----------------------
1. `add_inherited_role`
`add_inherited_role` is the [metadata API](https://hasura.io/docs/1.0/graphql/core/api-reference/index.html#schema-metadata-api) to create a new inherited role. It accepts two arguments
`role_name`: the name of the inherited role to be added (String)
`role_set`: list of roles that need to be combined (Array of Strings)
Example:
```json
{
"type": "add_inherited_role",
"args": {
"role_name":"combined_user",
"role_set":[
"user",
"user1"
]
}
}
```
After adding the inherited role, the inherited role can be used like single roles like earlier
Note:
An inherited role can only be created with non-inherited/singular roles.
2. `drop_inherited_role`
The `drop_inherited_role` API accepts the name of the inherited role and drops it from the metadata. It accepts a single argument:
`role_name`: name of the inherited role to be dropped
Example:
```json
{
"type": "drop_inherited_role",
"args": {
"role_name":"combined_user"
}
}
```
Metadata
---------
The derived roles metadata will be included under the `experimental_features` key while exporting the metadata.
```json
{
"experimental_features": {
"derived_roles": [
{
"role_name": "manager_is_employee_too",
"role_set": [
"employee",
"manager"
]
}
]
}
}
```
Scope
------
Only postgres queries and subscriptions are supported in this PR.
Important points:
-----------------
1. All columns exposed to an inherited role will be marked as `nullable`, this is done so that cell value nullification can be done.
TODOs
-------
- [ ] Tests
- [ ] Test a GraphQL query running with a inherited role without enabling inherited roles in experimental features
- [] Tests for aggregate queries, limit, computed fields, functions, subscriptions (?)
- [ ] Introspection test with a inherited role (nullability changes in a inherited role)
- [ ] Docs
- [ ] Changelog
Co-authored-by: Vamshi Surabhi <6562944+0x777@users.noreply.github.com>
GitOrigin-RevId: 3b8ee1e11f5ceca80fe294f8c074d42fbccfec63
2021-03-08 14:14:13 +03:00
2020-02-13 12:14:02 +03:00
def run_on_elem_or_list ( f , x ) :
if isinstance ( x , str ) :
return [ f ( x ) ]
elif isinstance ( x , list ) :
return [ f ( e ) for e in x ]
def is_help_option_present ( config ) :
return any ( [
config . getoption ( x )
for x in [ ' --fixtures ' , ' --help ' , ' --collect-only ' ]
] )
2019-04-08 10:22:38 +03:00
def is_master ( config ) :
""" True if the code running the given pytest.config object is running in a xdist master
node or not running xdist at all .
"""
2022-01-17 10:39:59 +03:00
return not hasattr ( config , ' workerinput ' )