diff --git a/api/app/settings/common.py b/api/app/settings/common.py index 027d029f085d..25b9669a8037 100644 --- a/api/app/settings/common.py +++ b/api/app/settings/common.py @@ -648,7 +648,7 @@ CACHE_FLAGS_SECONDS = env.int("CACHE_FLAGS_SECONDS", default=0) FLAGS_CACHE_LOCATION = "environment-flags" CHARGEBEE_CACHE_LOCATION = "chargebee-objects" - +CACHE_KEY_PREFIX = env.str("CACHE_KEY_PREFIX", default="") ENVIRONMENT_CACHE_SECONDS = env.int("ENVIRONMENT_CACHE_SECONDS", default=60) ENVIRONMENT_CACHE_BACKEND = env.str( "ENVIRONMENT_CACHE_BACKEND", @@ -1037,7 +1037,11 @@ subcast=str, default=[], ) - +# Apply key prefix to all Redis-backed caches to support +# ACL-based multi-tenancy on shared Redis instances. +for _cache_config in CACHES.values(): + if "redis" in _cache_config.get("BACKEND", "").lower(): # type: ignore[attr-defined] + _cache_config["KEY_PREFIX"] = CACHE_KEY_PREFIX # type: ignore[index] WORKFLOWS_LOGIC_INSTALLED = importlib.util.find_spec("workflows_logic") is not None diff --git a/api/tests/unit/app/test_unit_app_settings.py b/api/tests/unit/app/test_unit_app_settings.py new file mode 100644 index 000000000000..9cc5a1e0e552 --- /dev/null +++ b/api/tests/unit/app/test_unit_app_settings.py @@ -0,0 +1,51 @@ +import pytest + + +def test_cache_key_prefix__redis_backend__key_prefix_applied( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Given + prefix = "flagsmith" + caches = { + "redis_cache": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://localhost:6379/1", + }, + "locmem_cache": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + "LOCATION": "test", + }, + "db_cache": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": "cache_table", + }, + } + + # When - same logic as settings + for cache_config in caches.values(): + if "redis" in cache_config.get("BACKEND", "").lower(): + cache_config["KEY_PREFIX"] = prefix + + # Then + assert caches["redis_cache"]["KEY_PREFIX"] == prefix + assert "KEY_PREFIX" not in caches["locmem_cache"] + assert "KEY_PREFIX" not in caches["db_cache"] + + +def test_cache_key_prefix__empty_prefix__redis_backend_gets_empty_prefix() -> None: + # Given + prefix = "" + caches = { + "redis_cache": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://localhost:6379/1", + }, + } + + # When + for cache_config in caches.values(): + if "redis" in cache_config.get("BACKEND", "").lower(): + cache_config["KEY_PREFIX"] = prefix + + # Then + assert caches["redis_cache"]["KEY_PREFIX"] == ""