diff --git a/src/PostgREST/Config.hs b/src/PostgREST/Config.hs index 6d2a856859..6471c471f6 100644 --- a/src/PostgREST/Config.hs +++ b/src/PostgREST/Config.hs @@ -58,7 +58,6 @@ import Development.GitRev (gitHash) import Numeric (readOct, showOct) import Paths_postgrest (version) import System.Environment (getEnvironment) -import System.IO.Error (IOError) import System.Posix.Types (FileMode) import Control.Applicative @@ -334,14 +333,12 @@ readAppConfig :: [(Text, Text)] -> Environment -> Maybe FilePath -> IO (Either T readAppConfig dbSettings env optPath = do -- Now read the actual config file conf <- case optPath of - Just cfgPath -> C.load cfgPath `catches` - [ Handler (\(ex :: IOError) -> panic $ "Cannot open config file: " <> show ex) - , Handler (\(C.ParseError err) -> panic $ "Error parsing config file: " <> err) - ] + -- Both C.ParseError and IOError are shown here + Just cfgPath -> mapLeft show <$> (try $ C.load cfgPath :: IO (Either SomeException C.Config)) -- if no filename provided, start with an empty map to read config from environment - Nothing -> return M.empty + Nothing -> return $ Right M.empty - pure $ mapLeft ("Error in config: " <>) $ C.runParser parseConfig conf + pure $ mapLeft ("Error in config: " <>) $ C.runParser parseConfig =<< conf where parseConfig = diff --git a/src/PostgREST/Statements.hs b/src/PostgREST/Statements.hs index 0cb5a60465..c8e38554ce 100644 --- a/src/PostgREST/Statements.hs +++ b/src/PostgREST/Statements.hs @@ -202,7 +202,7 @@ dbSettingsStatement = H.Statement sql HE.noParams decodeSettings False sql = [q| with role_setting as ( - select unnest(setconfig) as setting from pg_catalog.pg_db_role_setting where setrole = 'postgrest_test_authenticator'::regrole::oid + select unnest(setconfig) as setting from pg_catalog.pg_db_role_setting where setrole = current_user::regrole::oid ), kv_settings as ( select split_part(setting, '=', 1) as key, split_part(setting, '=', 2) as value from role_setting diff --git a/test/fixtures/roles.sql b/test/fixtures/roles.sql index 286065b7a5..64f6f61601 100644 --- a/test/fixtures/roles.sql +++ b/test/fixtures/roles.sql @@ -34,3 +34,19 @@ ALTER ROLE postgrest_test_authenticator SET pgrst."db-channel" = 'ignored'; ALTER ROLE postgrest_test_authenticator SET pgrst."db-pool" = 'ignored'; ALTER ROLE postgrest_test_authenticator SET pgrst."db-pool-timeout" = 'ignored'; ALTER ROLE postgrest_test_authenticator SET pgrst."db-load-guc-config" = 'ignored'; + +-- other authenticator reloadable config options for io tests +CREATE ROLE other_authenticator LOGIN NOINHERIT; +ALTER ROLE other_authenticator SET pgrst."jwt-aud" = 'https://otherexample.org'; +ALTER ROLE other_authenticator SET pgrst."openapi-server-proxy-uri" = 'https://otherexample.org/api'; +ALTER ROLE other_authenticator SET pgrst."raw-media-types" = 'application/vnd.pgrst.other-db-config'; +ALTER ROLE other_authenticator SET pgrst."jwt-secret" = 'ODERREALLYREALLYREALLYREALLYVERYSAFE'; +ALTER ROLE other_authenticator SET pgrst."jwt-secret-is-base64" = 'true'; +ALTER ROLE other_authenticator SET pgrst."jwt-role-claim-key" = '."other"."role"'; +ALTER ROLE other_authenticator SET pgrst."db-tx-end" = 'rollback-allow-override'; +ALTER ROLE other_authenticator SET pgrst."db-schemas" = 'test, other_tenant1, other_tenant2'; +ALTER ROLE other_authenticator SET pgrst."db-root-spec" = 'other_root'; +ALTER ROLE other_authenticator SET pgrst."db-prepared-statements" = 'false'; +ALTER ROLE other_authenticator SET pgrst."db-pre-request" = 'test.other_custom_headers'; +ALTER ROLE other_authenticator SET pgrst."db-max-rows" = '100'; +ALTER ROLE other_authenticator SET pgrst."db-extra-search-path" = 'public, extensions, other'; diff --git a/test/io-tests/configs/expected/no-defaults-with-db-other-authenticator.config b/test/io-tests/configs/expected/no-defaults-with-db-other-authenticator.config new file mode 100644 index 0000000000..604c33d6ff --- /dev/null +++ b/test/io-tests/configs/expected/no-defaults-with-db-other-authenticator.config @@ -0,0 +1,27 @@ +db-anon-role = "postgrest_test_anonymous" +db-channel = "postgrest" +db-channel-enabled = true +db-extra-search-path = "public,extensions,other" +db-max-rows = 100 +db-pool = 1 +db-pool-timeout = 100 +db-pre-request = "test.other_custom_headers" +db-prepared-statements = false +db-root-spec = "other_root" +db-schemas = "test,other_tenant1,other_tenant2" +db-load-guc-config = "true" +db-tx-end = "rollback-allow-override" +db-uri = "" +jwt-aud = "https://otherexample.org" +jwt-role-claim-key = ".\"other\".\"role\"" +jwt-secret = "ODERREALLYREALLYREALLYREALLYVERYSAFE" +jwt-secret-is-base64 = true +log-level = "info" +openapi-server-proxy-uri = "https://otherexample.org/api" +raw-media-types = "application/vnd.pgrst.other-db-config" +server-host = "0.0.0.0" +server-port = 80 +server-unix-socket = "/tmp/pgrst_io_test.sock" +server-unix-socket-mode = "777" +app.settings.test = "test" +app.settings.test2 = "test" diff --git a/test/io-tests/test_io.py b/test/io-tests/test_io.py index 03c32da21d..ac66a22cfc 100644 --- a/test/io-tests/test_io.py +++ b/test/io-tests/test_io.py @@ -154,7 +154,9 @@ def run(configpath=None, stdin=None, env=None, port=None): if configpath: command.append(configpath) - process = subprocess.Popen(command, stdin=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + process = subprocess.Popen( + command, stdin=subprocess.PIPE, stderr=subprocess.PIPE, env=env + ) try: process.stdin.write(stdin or b"") @@ -267,23 +269,34 @@ def test_expected_config_from_environment(): assert dumpconfig(env=env) == expected -def test_expected_config_from_db_settings(defaultenv): +@pytest.mark.parametrize( + "role, expectedconfig", + [ + ("postgrest_test_authenticator", "no-defaults-with-db.config"), + ("other_authenticator", "no-defaults-with-db-other-authenticator.config"), + ], +) +def test_expected_config_from_db_settings(defaultenv, role, expectedconfig): "Config should be overriden from database settings" config = CONFIGSDIR / "no-defaults.config" + + db_uri = defaultenv["PGRST_DB_URI"].replace( + "user=postgrest_test_authenticator", f"user={role}" + ) env = { **defaultenv, + "PGRST_DB_URI": db_uri, "PGRST_DB_LOAD_GUC_CONFIG": "true", } expected = ( - (CONFIGSDIR / "expected" / "no-defaults-with-db.config") + (CONFIGSDIR / "expected" / expectedconfig) .read_text() .replace("", env["PGRST_DB_URI"]) ) assert dumpconfig(configpath=config, env=env) == expected - @pytest.mark.parametrize( "config", [conf for conf in CONFIGSDIR.iterdir() if conf.suffix == ".config"], @@ -591,7 +604,7 @@ def test_max_rows_notify_reload(defaultenv): # reset max-rows config on the db postgrest.session.post("/rpc/reset_max_rows_config") -def invalid_role_claim_key_notify_reload(defaultenv): +def test_invalid_role_claim_key_notify_reload(defaultenv): "NOTIFY reload config should show an error if role-claim-key is invalid" env = { @@ -603,6 +616,8 @@ def invalid_role_claim_key_notify_reload(defaultenv): with run(env=env) as postgrest: postgrest.session.post("/rpc/invalid_role_claim_key_reload") - assert "failed to parse role-claim-key value" in str(postgrest.process.stderr.readline()) + assert "failed to parse role-claim-key value" in str( + postgrest.process.stderr.readline() + ) postgrest.session.post("/rpc/reset_invalid_role_claim_key")