diff --git a/.github/workflows/update-license-year.yml b/.github/workflows/update-license-year.yml index 33245da6..884edbe9 100644 --- a/.github/workflows/update-license-year.yml +++ b/.github/workflows/update-license-year.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -24,7 +24,7 @@ jobs: run: "echo PREVIOUS=$(($CURRENT-1)) >> $GITHUB_ENV" - name: Update LICENSE - uses: jacobtomlinson/gha-find-replace@v2 + uses: jacobtomlinson/gha-find-replace@v3 with: find: ${{ env.PREVIOUS }} replace: ${{ env.CURRENT }} @@ -38,7 +38,7 @@ jobs: git commit -m "Updated License Year" -a - name: Create Pull Request - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v5 with: token: ${{ secrets.GITHUB_TOKEN }} title: Update License Year diff --git a/CHANGES.txt b/CHANGES.txt index eee840fd..df26cc5c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +9.6.1 (Feb 15, 2024) +- Added redisUsername configuration parameter for Redis connection to set the username for accessing redis when not using the default `root` username + 9.6.0 (Nov 3, 2023) - Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation): - Added new variations of the get treatment methods to support evaluating flags in given flag set/s. diff --git a/LICENSE.txt b/LICENSE.txt index 65f5999d..c022e920 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright © 2023 Split Software, Inc. +Copyright © 2024 Split Software, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/splitio/client/config.py b/splitio/client/config.py index 92388edf..1789e0b9 100644 --- a/splitio/client/config.py +++ b/splitio/client/config.py @@ -31,6 +31,7 @@ 'redisHost': 'localhost', 'redisPort': 6379, 'redisDb': 0, + 'redisUsername': None, 'redisPassword': None, 'redisSocketTimeout': None, 'redisSocketConnectTimeout': None, diff --git a/splitio/client/factory.py b/splitio/client/factory.py index 67c57e68..5ac809cc 100644 --- a/splitio/client/factory.py +++ b/splitio/client/factory.py @@ -441,7 +441,7 @@ def _build_redis_factory(api_key, cfg): cache_enabled = cfg.get('redisLocalCacheEnabled', False) cache_ttl = cfg.get('redisLocalCacheTTL', 5) storages = { - 'splits': RedisSplitStorage(redis_adapter, cache_enabled, cache_ttl, cfg['flagSetsFilter'] if cfg['flagSetsFilter'] is not None else []), + 'splits': RedisSplitStorage(redis_adapter, cache_enabled, cache_ttl, []), 'segments': RedisSegmentStorage(redis_adapter), 'impressions': RedisImpressionsStorage(redis_adapter, sdk_metadata), 'events': RedisEventsStorage(redis_adapter, sdk_metadata), @@ -524,7 +524,7 @@ def _build_pluggable_factory(api_key, cfg): pluggable_adapter = cfg.get('storageWrapper') storage_prefix = cfg.get('storagePrefix') storages = { - 'splits': PluggableSplitStorage(pluggable_adapter, storage_prefix, cfg['flagSetsFilter'] if cfg['flagSetsFilter'] is not None else []), + 'splits': PluggableSplitStorage(pluggable_adapter, storage_prefix, []), 'segments': PluggableSegmentStorage(pluggable_adapter, storage_prefix), 'impressions': PluggableImpressionsStorage(pluggable_adapter, sdk_metadata, storage_prefix), 'events': PluggableEventsStorage(pluggable_adapter, sdk_metadata, storage_prefix), diff --git a/splitio/storage/adapters/redis.py b/splitio/storage/adapters/redis.py index 8657b317..25ecb8dc 100644 --- a/splitio/storage/adapters/redis.py +++ b/splitio/storage/adapters/redis.py @@ -357,6 +357,7 @@ def _build_default_client(config): # pylint: disable=too-many-locals host = config.get('redisHost', 'localhost') port = config.get('redisPort', 6379) database = config.get('redisDb', 0) + username = config.get('redisUsername', None) password = config.get('redisPassword', None) socket_timeout = config.get('redisSocketTimeout', None) socket_connect_timeout = config.get('redisSocketConnectTimeout', None) @@ -382,6 +383,7 @@ def _build_default_client(config): # pylint: disable=too-many-locals port=port, db=database, password=password, + username=username, socket_timeout=socket_timeout, socket_connect_timeout=socket_connect_timeout, socket_keepalive=socket_keepalive, @@ -435,6 +437,7 @@ def _build_sentinel_client(config): # pylint: disable=too-many-locals raise SentinelConfigurationException('redisMasterService must be specified.') database = config.get('redisDb', 0) + username = config.get('redisUsername', None) password = config.get('redisPassword', None) socket_timeout = config.get('redisSocketTimeout', None) socket_connect_timeout = config.get('redisSocketConnectTimeout', None) @@ -452,6 +455,7 @@ def _build_sentinel_client(config): # pylint: disable=too-many-locals sentinels, db=database, password=password, + username=username, socket_timeout=socket_timeout, socket_connect_timeout=socket_connect_timeout, socket_keepalive=socket_keepalive, diff --git a/splitio/version.py b/splitio/version.py index 17781f45..c02fe413 100644 --- a/splitio/version.py +++ b/splitio/version.py @@ -1 +1 @@ -__version__ = '9.6.0' +__version__ = '9.6.1' diff --git a/tests/client/test_factory.py b/tests/client/test_factory.py index 644fe6fd..5ea32c9c 100644 --- a/tests/client/test_factory.py +++ b/tests/client/test_factory.py @@ -99,6 +99,7 @@ def test_redis_client_creation(self, mocker): 'redisPort': 1234, 'redisDb': 1, 'redisPassword': 'some_password', + 'redisUsername': 'redis_user', 'redisSocketTimeout': 123, 'redisSocketConnectTimeout': 123, 'redisSocketKeepalive': 123, @@ -115,6 +116,7 @@ def test_redis_client_creation(self, mocker): 'redisSslCertReqs': 'some_cert_req', 'redisSslCaCerts': 'some_ca_cert', 'redisMaxConnections': 999, + 'flagSetsFilter': ['set_1'] } factory = get_factory('some_api_key', config=config) assert isinstance(factory._get_storage('splits'), redis.RedisSplitStorage) @@ -122,6 +124,8 @@ def test_redis_client_creation(self, mocker): assert isinstance(factory._get_storage('impressions'), redis.RedisImpressionsStorage) assert isinstance(factory._get_storage('events'), redis.RedisEventsStorage) + assert factory._get_storage('splits').flag_set_filter.flag_sets == set([]) + adapter = factory._get_storage('splits')._redis assert adapter == factory._get_storage('segments')._redis assert adapter == factory._get_storage('impressions')._redis @@ -131,6 +135,7 @@ def test_redis_client_creation(self, mocker): host='some_host', port=1234, db=1, + username='redis_user', password='some_password', socket_timeout=123, socket_connect_timeout=123, @@ -569,13 +574,15 @@ def test_pluggable_client_creation(self, mocker): 'labelsEnabled': False, 'impressionListener': 123, 'storageType': 'pluggable', - 'storageWrapper': StorageMockAdapter() + 'storageWrapper': StorageMockAdapter(), + 'flagSetsFilter': ['set_1'] } factory = get_factory('some_api_key', config=config) assert isinstance(factory._get_storage('splits'), pluggable.PluggableSplitStorage) assert isinstance(factory._get_storage('segments'), pluggable.PluggableSegmentStorage) assert isinstance(factory._get_storage('impressions'), pluggable.PluggableImpressionsStorage) assert isinstance(factory._get_storage('events'), pluggable.PluggableEventsStorage) + assert factory._get_storage('splits').flag_set_filter.flag_sets == set([]) adapter = factory._get_storage('splits')._pluggable_adapter assert adapter == factory._get_storage('segments')._pluggable_adapter diff --git a/tests/integration/test_redis_integration.py b/tests/integration/test_redis_integration.py index 279b45a5..f76faf0f 100644 --- a/tests/integration/test_redis_integration.py +++ b/tests/integration/test_redis_integration.py @@ -8,7 +8,7 @@ from splitio.models import splits, impressions, events from splitio.storage.redis import RedisSplitStorage, RedisSegmentStorage, RedisImpressionsStorage, \ RedisEventsStorage -from splitio.storage.adapters.redis import _build_default_client +from splitio.storage.adapters.redis import _build_default_client, StrictRedis from splitio.client.config import DEFAULT_CONFIG @@ -17,7 +17,11 @@ class SplitStorageTests(object): def test_put_fetch(self): """Test storing and retrieving splits in redis.""" - adapter = _build_default_client({}) + redis = StrictRedis(host="localhost") + redis.acl_setuser(username='redis_user', enabled=True, passwords=["+split"], categories=["+admin"], + commands=["+@all"], keys=["~*"]) + redis.close() + adapter = _build_default_client({'redisUsername': 'redis_user', 'redisPassword': 'split'}) try: storage = RedisSplitStorage(adapter) with open(os.path.join(os.path.dirname(__file__), 'files', 'split_changes.json'), 'r') as flo: @@ -73,10 +77,12 @@ def test_put_fetch(self): ] for item in to_delete: adapter.delete(item) - storage = RedisSplitStorage(adapter) assert storage.is_valid_traffic_type('user') is False assert storage.is_valid_traffic_type('account') is False + redis = StrictRedis(host="localhost") + redis.acl_deluser("redis_user") + redis.close() def test_get_all(self): """Test get all names & splits.""" diff --git a/tests/storage/adapters/test_redis_adapter.py b/tests/storage/adapters/test_redis_adapter.py index cb81dfb9..ec7ddaf4 100644 --- a/tests/storage/adapters/test_redis_adapter.py +++ b/tests/storage/adapters/test_redis_adapter.py @@ -87,6 +87,7 @@ def test_adapter_building(self, mocker): 'redisHost': 'some_host', 'redisPort': 1234, 'redisDb': 0, + 'redisUsername': 'redis_user', 'redisPassword': 'some_password', 'redisSocketTimeout': 123, 'redisSocketConnectTimeout': 456, @@ -113,6 +114,7 @@ def test_adapter_building(self, mocker): host='some_host', port=1234, db=0, + username='redis_user', password='some_password', socket_timeout=123, socket_connect_timeout=456, @@ -137,6 +139,7 @@ def test_adapter_building(self, mocker): 'redisSentinels': [('123.123.123.123', 1), ('456.456.456.456', 2), ('789.789.789.789', 3)], 'redisMasterService': 'some_master', 'redisDb': 0, + 'redisUsername': 'redis_user', 'redisPassword': 'some_password', 'redisSocketTimeout': 123, 'redisSocketConnectTimeout': 456, @@ -162,6 +165,7 @@ def test_adapter_building(self, mocker): assert sentinel_mock.mock_calls[0] == mocker.call( [('123.123.123.123', 1), ('456.456.456.456', 2), ('789.789.789.789', 3)], db=0, + username='redis_user', password='some_password', socket_timeout=123, socket_connect_timeout=456,