Skip to content

feat!: log in as a Redis ACL user with connection.username - #49

Merged
AlexeyShalaev merged 2 commits into
masterfrom
feat/acl-username
Oct 9, 2026
Merged

AlexeyShalaev merged 2 commits into
masterfrom
feat/acl-username

Conversation

@AlexeyShalaev

@AlexeyShalaev AlexeyShalaev commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Closes #48

RedisConnectionSettings gains username: str | None = None, and build_base_redis_kwargs passes it to redis-py next to password, so every client the factories build — sync and asyncio, single node and cluster — logs in as that ACL user.

Why this matters beyond "can't use ACL users"

On master, an ACL user's password in connection.password does not just fail. Against redis:7-alpine with a nopass default user:

  • RESP2: AUTH <password> called without any password configured for the default user.
  • RESP3: redis-py sends HELLO 3 AUTH default <password>, the server accepts it, and the client runs as default with full access — GET other:x and FLUSHDB both succeed.

Breaking change

username: str | None is a member of RedisConnectionProtocol, and the kwargs builder reads settings.connection.username directly. BaseRedisSettings users get the field with a None default and see no difference. A hand-written connection object (as in the README and the configuration guide) now needs username = None; without it the factories raise AttributeError. Those examples are updated. The README one also lacked client_name and protocol, so it already failed before this change.

Pre-1.0 with bump-minor-pre-major, feat! still releases as 0.4.0. The only sibling that depends on the kit, idempotency-kit (>=0.2.0, no cap), builds its settings from BaseRedisSettings.

Docs

The configuration guide gets an "ACL Users" section with a rule that works with the kit. The rule in the issue (-@all +@read +@write) is not enough, each point below checked on a live server:

  • the health check, the provider's startup check and health_check_interval send PING, so +ping;
  • client_name needs +client|setname, and db != 0 needs +select; without them every connection fails;
  • +@write still allows FLUSHDB/FLUSHALL (a key pattern does not stop a command with no key), so -@dangerous;
  • SCAN still lists other apps' key names; -scan if they are private.

docs/agents.md gets the new field and the updated hand-written example.

Tests

  • unit: kwargs with and without a username, the username surviving mask_redis_kwargs, the sync and asyncio factories passing it to Redis and RedisCluster, the default, and REDIS__CONNECTION__USERNAME read through an app-level settings model;
  • integration (tests/integration/test_redis_acl.py): an ACL user limited to ~app:* under the documented rule can SET app:x, gets NoPermissionError on GET other:x and FLUSHDB (RESP2 and RESP3, async; RESP2 sync), and passes check_async_redis_health with and without the write probe.

With master's utils.py swapped back in, the 10 tests that go through the kwargs fail; with the fix all pass.

make check is clean; make test gives 185 passed, coverage 99.66%; the docs build passes.

CHANGELOG is left to release-please; the ! puts the break under BREAKING CHANGES.

@codecov

codecov Bot commented Oct 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

BREAKING CHANGE: a hand-written connection object now needs a username attribute (None for the default user); without it the factories raise AttributeError.
@AlexeyShalaev AlexeyShalaev changed the title feat: log in as a Redis ACL user with connection.username feat!: log in as a Redis ACL user with connection.username Oct 9, 2026
@AlexeyShalaev
AlexeyShalaev merged commit 53b09e5 into master Oct 9, 2026
9 checks passed
@AlexeyShalaev
AlexeyShalaev deleted the feat/acl-username branch October 9, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Redis ACL users: connection.username

1 participant