diff --git a/CHANGELOG.md b/CHANGELOG.md index 6717f72a9..e4283c5f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fix jwt error returning HTTP status `400` for invalid role by @taimoorzaeem in #3601 +- Allow `db-extra-search-path` to accept empty value by @taimoorzaeem in #4074 ## [13.0.0] - 2025-05-08 diff --git a/docs/references/configuration.rst b/docs/references/configuration.rst index 4312a5898..09ccb7774 100644 --- a/docs/references/configuration.rst +++ b/docs/references/configuration.rst @@ -315,6 +315,10 @@ db-extra-search-path Multiple schemas can be added in a comma-separated string, e.g. ``public, extensions``. +.. important:: + + We default this config to ``public`` because it is the most common schema used to install PostgreSQL extensions such as :ref:`PostGIS `. You can disable this by setting this config to ``""``. + .. _db-hoisted-tx-settings: db-hoisted-tx-settings diff --git a/src/PostgREST/Config.hs b/src/PostgREST/Config.hs index e37d5e075..5709fab7f 100644 --- a/src/PostgREST/Config.hs +++ b/src/PostgREST/Config.hs @@ -256,7 +256,7 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = <*> (fmap encodeUtf8 <$> optString "db-anon-role") <*> (fromMaybe "pgrst" <$> optString "db-channel") <*> (fromMaybe True <$> optBool "db-channel-enabled") - <*> (maybe ["public"] splitOnCommas <$> optString "db-extra-search-path") + <*> (maybe ["public"] splitOnCommasEmptyable <$> optStringEmptyable "db-extra-search-path") <*> (maybe defaultHoistedAllowList splitOnCommas <$> optString "db-hoisted-tx-settings") <*> optWithAlias (optInt "db-max-rows") (optInt "max-rows") @@ -404,6 +404,9 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = optString :: C.Key -> C.Parser C.Config (Maybe Text) optString k = mfilter (/= "") <$> overrideFromDbOrEnvironment C.optional k coerceText + optStringEmptyable :: C.Key -> C.Parser C.Config (Maybe Text) + optStringEmptyable k = overrideFromDbOrEnvironment C.optional k coerceText + optInt :: (Read i, Integral i) => C.Key -> C.Parser C.Config (Maybe i) optInt k = join <$> overrideFromDbOrEnvironment C.optional k coerceInt @@ -445,6 +448,10 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = splitOnCommas :: Text -> [Text] splitOnCommas s = T.strip <$> T.splitOn "," s + splitOnCommasEmptyable :: Text -> [Text] + splitOnCommasEmptyable "" = [] + splitOnCommasEmptyable s = T.strip <$> T.splitOn "," s + defaultHoistedAllowList = ["statement_timeout","plan_filter.statement_cost_limit","default_transaction_isolation"] defaultServerHost :: Maybe Text -> Text diff --git a/test/io/test_io.py b/test/io/test_io.py index 1a7eb8f70..795316688 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -1896,3 +1896,16 @@ def test_invalidate_jwt_cache_when_secret_changes(tmp_path, defaultenv): # now the request should fail because the cached token is removed response = postgrest.session.get("/authors_only", headers=headers) assert response.status_code == 401 + + +def test_allow_configs_to_be_set_to_empty(defaultenv): + 'configs that are explicitly set to empty (= "") should not throw parse error' + + env = { + **defaultenv, + "PGRST_DB_EXTRA_SEARCH_PATH": "", + } + + with run(env=env) as postgrest: + response = postgrest.session.get("/projects") + assert response.status_code == 200