mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
fix(web-app-suitecrm): keep sessions in Redis so replicas share them
With three swarm replicas the PHP session files on the shared NFS volume were read as empty under concurrent requests of one browser, so SuiteCRM answered 403 on /api/graphql and dropped the session. Sessions now live in Redis with session locking that waits like flock did; the phpredis version is pinned in services.yml with its own update source, and the engine lookup renders the save path. Refs #879 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
5c862ee53d
commit
3cefb01d71
9 files changed
+120
-7
No files matched your search
@@ -0,0 +1,49 @@
|
||||
"""phpredis reads ``auth[user]``/``auth[pass]`` and ``prefix`` from the query of
|
||||
``session.save_path``; a password with a reserved character that is not
|
||||
percent-encoded splits the query and the handler authenticates with a fragment.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import unittest
|
||||
from urllib.parse import parse_qs, urlsplit
|
||||
|
||||
plugin_module = importlib.import_module("plugins.lookup.engine")
|
||||
redis_session_path = plugin_module.redis_session_path
|
||||
|
||||
|
||||
class TestRedisSessionPath(unittest.TestCase):
|
||||
def test_an_embedded_sidecar_gets_no_credentials(self) -> None:
|
||||
self.assertEqual(
|
||||
"tcp://redis:6379?prefix=suitecrm:session:",
|
||||
redis_session_path("redis", 6379, "suitecrm", "", ""),
|
||||
)
|
||||
|
||||
def test_a_shared_redis_gets_user_and_password(self) -> None:
|
||||
query = parse_qs(
|
||||
urlsplit(
|
||||
redis_session_path("redis-central", 6379, "suitecrm", "default", "pw")
|
||||
).query
|
||||
)
|
||||
self.assertEqual(["default"], query["auth[user]"])
|
||||
self.assertEqual(["pw"], query["auth[pass]"])
|
||||
|
||||
def test_a_password_with_reserved_characters_survives_the_query(self) -> None:
|
||||
password = "a&b=c?d#e/f+g h"
|
||||
query = parse_qs(
|
||||
urlsplit(
|
||||
redis_session_path("redis-central", 6379, "suitecrm", "default", password)
|
||||
).query
|
||||
)
|
||||
self.assertEqual([password], query["auth[pass]"])
|
||||
self.assertEqual(["suitecrm:session:"], query["prefix"])
|
||||
|
||||
def test_a_user_without_a_password_is_not_sent(self) -> None:
|
||||
self.assertNotIn(
|
||||
"auth", redis_session_path("redis", 6379, "suitecrm", "default", "")
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user