From c10a34b1c076e24cc4a1c568dadb601ad6ac9728 Mon Sep 17 00:00:00 2001 From: Daniel M Date: Fri, 20 Dec 2024 16:50:54 -0500 Subject: [PATCH] chore:add redis-py 5.3.0b3 to test matrix --- fakeredis/_basefakesocket.py | 6 +- fakeredis/_connection.py | 2 +- fakeredis/_fakesocket.py | 6 +- fakeredis/_msgs.py | 2 + fakeredis/commands_mixins/acl_mixin.py | 3 +- fakeredis/model/_acl.py | 6 +- poetry.lock | 76 +++++++++++++------------- test/test_mixins/test_acl_commands.py | 49 +++++++++++++++-- 8 files changed, 101 insertions(+), 49 deletions(-) diff --git a/fakeredis/_basefakesocket.py b/fakeredis/_basefakesocket.py index ae9614fe..4f97812f 100644 --- a/fakeredis/_basefakesocket.py +++ b/fakeredis/_basefakesocket.py @@ -87,7 +87,11 @@ def __init__(self, server: "FakeServer", db: int, *args: Any, **kwargs: Any) -> self._pubsub: int self._transaction_failed: bool self._current_user: bytes = b"default" - self._client_info: bytes = b"" # todo pass client info from connection + # TODO fix + self._client_info: bytes = kwargs.pop( + "client_info", + b"id=3 addr=127.0.0.1:57275 laddr=127.0.0.1:6379 fd=8 name= age=16 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=48 qbuf-free=16842 argv-mem=25 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=18737 events=r cmd=auth user=default redir=-1 resp=2", + ) @property def version(self) -> Tuple[int, ...]: diff --git a/fakeredis/_connection.py b/fakeredis/_connection.py index 75f7f2b5..1d8cc4f5 100644 --- a/fakeredis/_connection.py +++ b/fakeredis/_connection.py @@ -28,7 +28,7 @@ def connect(self) -> None: def _connect(self) -> FakeSocket: if not self._server.connected: raise redis.ConnectionError(msgs.CONNECTION_ERROR_MSG) - return FakeSocket(self._server, db=self.db, lua_modules=self._lua_modules) + return FakeSocket(self._server, db=self.db, lua_modules=self._lua_modules, client_info=self) def can_read(self, timeout: Optional[float] = 0) -> bool: if not self._server.connected: diff --git a/fakeredis/_fakesocket.py b/fakeredis/_fakesocket.py index eff49d52..af55aa65 100644 --- a/fakeredis/_fakesocket.py +++ b/fakeredis/_fakesocket.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Optional, Set, Any from fakeredis.commands_mixins import ( BitmapCommandsMixin, @@ -62,5 +62,7 @@ def __init__( server: "FakeServer", db: int, lua_modules: Optional[Set[str]] = None, # noqa: F821 + *args: Any, + **kwargs, ) -> None: - super(FakeSocket, self).__init__(server, db, lua_modules=lua_modules) + super(FakeSocket, self).__init__(server, db, *args, lua_modules=lua_modules, **kwargs) diff --git a/fakeredis/_msgs.py b/fakeredis/_msgs.py index 49646d69..5dbe720a 100644 --- a/fakeredis/_msgs.py +++ b/fakeredis/_msgs.py @@ -123,6 +123,8 @@ MISSING_ACLFILE_CONFIG = "ERR This Redis instance is not configured to use an ACL file. You may want to specify users via the ACL SETUSER command and then issue a CONFIG REWRITE (assuming you have a Redis configuration file set) in order to store users in the Redis configuration." +NO_PERMISSION_ERROR = "NOPERM User {} has no permissions to run the '{}' command" + # Command flags FLAG_NO_SCRIPT = "s" # Command not allowed in scripts FLAG_LEAVE_EMPTY_VAL = "v" diff --git a/fakeredis/commands_mixins/acl_mixin.py b/fakeredis/commands_mixins/acl_mixin.py index d04e1176..f1b0ac7f 100644 --- a/fakeredis/commands_mixins/acl_mixin.py +++ b/fakeredis/commands_mixins/acl_mixin.py @@ -16,6 +16,7 @@ def __init(self, *args: Any, **kwargs: Any) -> None: self.version: Tuple[int] self._server: Any self._current_user: bytes + self._client_info: bytes @property def _server_config(self) -> Dict[bytes, bytes]: @@ -91,7 +92,7 @@ def auth(self, *args: bytes) -> bytes: raise SimpleError(msgs.WRONG_ARGS_MSG6.format("AUTH")) username = None if len(args) == 1 else args[0] password = args[1] if len(args) == 2 else args[0] - if (username is None or username == b"default") and (password == self._server_config.get(b"requirepass", None)): + if (username is None or username == b"default") and (password == self._server_config.get(b"requirepass", b"")): self._current_user = b"default" return OK if len(args) >= 1 and self._check_user_password(username, password): diff --git a/fakeredis/model/_acl.py b/fakeredis/model/_acl.py index aa4e4dab..2ae2a190 100644 --- a/fakeredis/model/_acl.py +++ b/fakeredis/model/_acl.py @@ -1,6 +1,7 @@ import hashlib from typing import Dict, Set, List, Union, Optional +from fakeredis import _msgs as msgs from ._command_info import get_commands_by_category from .._helpers import SimpleError, current_time @@ -66,7 +67,7 @@ def set_nopass(self) -> None: self._passwords.clear() def check_password(self, password: Optional[bytes]) -> bool: - if self._nopass and not password: + if self._nopass: return True if not password: return False @@ -301,4 +302,7 @@ def validate_command(self, username: bytes, fields: List[bytes]): if not user_acl.enabled: raise SimpleError("User disabled") + command, args = fields[0], fields[1:] + if command.lower() not in user_acl._commands: + raise SimpleError(msgs.NO_PERMISSION_ERROR.format(username.decode(), command.lower().decode())) # todo diff --git a/poetry.lock b/poetry.lock index f2f8de98..1a82d129 100644 --- a/poetry.lock +++ b/poetry.lock @@ -511,13 +511,13 @@ dev = ["pyTest", "pyTest-cov"] [[package]] name = "hypothesis" -version = "6.122.3" +version = "6.122.5" description = "A library for property-based testing" optional = false python-versions = ">=3.9" files = [ - {file = "hypothesis-6.122.3-py3-none-any.whl", hash = "sha256:f0f57036d3b95b979491602b32c95b6725c3af678cccb6165d8de330857f3c83"}, - {file = "hypothesis-6.122.3.tar.gz", hash = "sha256:f4c927ce0ec739fa6266e4572949d0b54e24a14601a2bc5fec8f78e16af57918"}, + {file = "hypothesis-6.122.5-py3-none-any.whl", hash = "sha256:c50b104d9d5163ebdeb09ccd93626343664942570bcb067c41adf10394a81caf"}, + {file = "hypothesis-6.122.5.tar.gz", hash = "sha256:e0994f04331251d51e18040f497c839a52b37669b422fe4cfef85a54d41405bf"}, ] [package.dependencies] @@ -797,49 +797,49 @@ files = [ [[package]] name = "mypy" -version = "1.13.0" +version = "1.14.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, - {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, - {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, - {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, - {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, - {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, - {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, - {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, - {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, - {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, - {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, - {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, - {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, - {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, - {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, - {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, - {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, - {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, - {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, - {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, - {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, - {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, - {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, - {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, - {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, - {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, - {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e971c1c667007f9f2b397ffa80fa8e1e0adccff336e5e77e74cb5f22868bee87"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e86aaeaa3221a278c66d3d673b297232947d873773d61ca3ee0e28b2ff027179"}, + {file = "mypy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1628c5c3ce823d296e41e2984ff88c5861499041cb416a8809615d0c1f41740e"}, + {file = "mypy-1.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fadb29b77fc14a0dd81304ed73c828c3e5cde0016c7e668a86a3e0dfc9f3af3"}, + {file = "mypy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:3fa76988dc760da377c1e5069200a50d9eaaccf34f4ea18428a3337034ab5a44"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc"}, + {file = "mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015"}, + {file = "mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb"}, + {file = "mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1"}, + {file = "mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63"}, + {file = "mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d"}, + {file = "mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7"}, + {file = "mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8"}, + {file = "mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc"}, + {file = "mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b16738b1d80ec4334654e89e798eb705ac0c36c8a5c4798496cd3623aa02286"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10065fcebb7c66df04b05fc799a854b1ae24d9963c8bb27e9064a9bdb43aa8ad"}, + {file = "mypy-1.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbb7d683fa6bdecaa106e8368aa973ecc0ddb79a9eaeb4b821591ecd07e9e03c"}, + {file = "mypy-1.14.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3498cb55448dc5533e438cd13d6ddd28654559c8c4d1fd4b5ca57a31b81bac01"}, + {file = "mypy-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:c7b243408ea43755f3a21a0a08e5c5ae30eddb4c58a80f415ca6b118816e60aa"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14117b9da3305b39860d0aa34b8f1ff74d209a368829a584eb77524389a9c13e"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af98c5a958f9c37404bd4eef2f920b94874507e146ed6ee559f185b8809c44cc"}, + {file = "mypy-1.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b343a1d3989547024377c2ba0dca9c74a2428ad6ed24283c213af8dbb0710b"}, + {file = "mypy-1.14.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cdb5563c1726c85fb201be383168f8c866032db95e1095600806625b3a648cb7"}, + {file = "mypy-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:74e925649c1ee0a79aa7448baf2668d81cc287dc5782cff6a04ee93f40fb8d3f"}, + {file = "mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab"}, + {file = "mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6"}, ] [package.dependencies] -mypy-extensions = ">=1.0.0" +mypy_extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.6.0" +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] diff --git a/test/test_mixins/test_acl_commands.py b/test/test_mixins/test_acl_commands.py index 811760fb..60191ef8 100644 --- a/test/test_mixins/test_acl_commands.py +++ b/test/test_mixins/test_acl_commands.py @@ -253,8 +253,45 @@ def test_acl_whoami(r: redis.Redis): r.config_set("requirepass", "") +def test_acl_log_auth_exist(r: redis.Redis, request): + username = "fredis-py-user" + + def teardown(): + r.auth("", username="default") + r.acl_deluser(username) + + request.addfinalizer(teardown) + r.acl_setuser( + username, + enabled=True, + reset=True, + commands=["+get", "+set", "+select"], + keys=["cache:*"], + passwords=["+pass1"], + ) + r.acl_log_reset() + + with pytest.raises(exceptions.AuthenticationError): + r.auth("xxx", username=username) + r.auth("pass1", username=username) + + # Valid operation and key + assert r.set("cache:0", 1) + assert r.get("cache:0") == b"1" + + r.auth("", "default") + log = r.acl_log() + assert isinstance(log, list) + assert len(log) == 1 + assert len(r.acl_log(count=1)) == 1 + assert isinstance(log[0], dict) + + expected = r.acl_log(count=1)[0] + assert expected["username"] == username + + @pytest.mark.usefixtures("create_redis") -def test_acl_log(r: redis.Redis, request, create_redis): +def test_acl_log_invalid_key(r: redis.Redis, request, create_redis): username = "fredis-py-user" def teardown(): @@ -277,14 +314,16 @@ def teardown(): assert r.set("cache:0", 1) assert r.get("cache:0") == b"1" + # Invalid operation + with pytest.raises(exceptions.NoPermissionError) as command_not_permitted: + r.hset("cache:0", "hkey", "hval") + + assert str(command_not_permitted.value) == "User fredis-py-user has no permissions to run the 'hset' command" + # Invalid key with pytest.raises(exceptions.NoPermissionError): r.get("violated_cache:0") - # Invalid operation - with pytest.raises(exceptions.NoPermissionError): - r.hset("cache:0", "hkey", "hval") - r.auth("", "default") log = r.acl_log() assert isinstance(log, list)