Repository navigation
bug(slm): replication and backup read the Redis password from /etc/redis/redis.conf, a file roles/redis never renders #16625
Description
Activity
- addedbugSomething isn't workingSomething isn't working
on Sep 13, 2026 - added a commit that references this issue
on Sep 13, 2026 AC evidence against origin/main after #16660 (07815fd). One of three ticked.
AC status evidence / gap The SLM gets a node's Redis password from the canonical source, the SLM-managed secret, and no longer greps a config file ticked autobot-slm-backend/services/replication.py:488return ssot_config.redis.password or "".services/backup.py:528auth = redis_cli_auth(), which readsssot_config.redis.password(services/redis_cli_auth.py:46). That value is the SLM-managed secret:slm_manager/templates/slm-secrets.env.j2:38AUTOBOT_REDIS_PASSWORD={{ slm_redis_password }}is loaded byautobot-slm-backend.service.j2:48EnvironmentFile=(defaultslm-secrets.env,defaults/main.yml:20-21) and read atautobot_shared/ssot_config.py:762alias="AUTOBOT_REDIS_PASSWORD". Test:tests/test_redis_cli_auth_16627.py:90test_the_config_file_grep_is_goneasserts that no string in the callers containsgrep -E '^requirepass'.redis-replicationedits the config file the runningredis-stack-serverloads, or renders through the role templatenot ticked Not touched by #16660. The redis-replicationrole still defaultsredis_config_fileto/etc/redis/redis.conf, per the audit sweep. I did not re-read it line by line.A test pins every Redis config path the SLM reads or edits to a path that some provisioning path writes not ticked The audit sweep found no such test on origin/main. Labelling
blocked: observation-gatedbehind #17434.A cross-issue sweep found this issue's criteria depend on an environment fact that #17434 owns establishing and has not yet established: which Redis config file the running daemon actually reads, answerable by one
redis-cli INFO serveron the database-role node.Why this was not visible from reading this issue alone. A gate is a property of a pair, and it can be written in either member. #17434's AC6 names some of these issues from the outside; this one instead assumes the answer from the inside, without naming #17434. Only the first kind is findable by reading the issue being classified, which is why one-at-a-time triage missed it — not because the triage was sloppy, but because the edge is not written here.
The specific hazard, and it is worth stating because it inverts the design rather than merely delaying it: the assumed premise is that the daemon never reads
/etc/redis/redis.conf. #17434's AC1 says exactly that fact must be established byredis-cli INFO serverand must not be chosen before it. So work here would pin a path #17434 has not settled, from a premise #17434 forbids assuming. If the premise is wrong, the design does not need adjusting — it reverses.That shape is a premise with no measurement behind it, carried forward as settled. It is the same error as reading an empty apt candidate list as proof a repository is broken.
One observation unblocks six issues: #17434, #16627, #16628, #17441, #16625, and transitively whatever #13568 holds. That is currently the strongest single-command argument in the backlog.
- addedblocked: observation-gatedCode remains, but cannot be written until one observation answers a questionCode remains, but cannot be written until one observation answers a question
on Oct 3, 2026 The title asserts the answer to #17434's AC1 — proposed wording below
Labelled
blocked: observation-gated. This comment is for the implementer rather than the triager.The assertion is in the title itself: "replication and backup read the Redis password from
/etc/redis/redis.conf, a fileroles/redisnever writes." The second clause is a claim about which file the provisioning path writes, and its companion — which file the daemon reads — is exactly what #17434's AC1 holds open:AC1 Establish, with
redis-cli INFO serverfrom the actualdatabase-role node, which path that node reads. The fix depends on the answer and must not be chosen before it.Why it is load-bearing here and not incidental. The unticked criterion is:
- A test pins every Redis config path the SLM reads or edits to a path that some provisioning path writes.
That test cannot be written without knowing which path is canonical. Worse, if it is written against an assumed path and the assumption is wrong, the test pins the defect — it would pass while the SLM reads a file nothing writes, which is this issue's own complaint made permanent and green.
Proposed wording, ready to paste
Add to the body:
Unverified: which path the Redis daemon actually reads is assumed here, not measured. #17434's AC1 owns establishing it and states the fix must not be chosen before the answer. #17434's AC6 names #16627 and #16628 as needing re-checking against it; this issue depends on the same answer through its path-pinning criterion.
And for the criterion:
- A test pins every Redis config path the SLM reads or edits to a path that some provisioning path writes. The canonical path comes from security(redis): the role's Redis Stack config is never read — requirepass is empty on a provisioned node, and one path has four spellings #17434's AC1 — pinning an assumed path would make this test enforce the defect rather than catch it.
Modelled on #17537's handling of the same situation. Not editing the body; the wording is the owner's.
One note on the gate's shape: #17434's AC6 names #16627 and #16628 explicitly, so those two are discoverable by reading #17434. This issue and #17441 are not named there — they assume the answer from inside instead, which is why they were missed until the reverse direction was checked.
Premise CONFIRMED — removing
blocked: observation-gated. The gate is answered, not waiting.#17434's AC1 has been established by direct observation on the running host:
config_file:/etc/redis-stack.conf executable:/opt/redis-stack/bin/redis-serverCorroborated independently by
systemctl show redis-server, whoseExecStartpasses/etc/redis-stack.conf— so this is two surfaces agreeing, not one reading. The daemon does not read/etc/redis/redis.conf.This issue's assumed premise was right, so its design does not invert. Worth stating precisely, because the distinction survives the good outcome: the premise being correct does not make assuming it correct. What changes is the remedy — from rework to confirmation. The
Unverified:clause recorded on this issue did its job: it named the premise, named the issue that owned establishing it, and named the mechanism by which it could have been false. Had the answer gone the other way, that clause is what would have stopped the work being done on sand.Scope of the measurement, stated rather than glossed: the host carries every role directory under the install root, so it is an all-in-one deployment and this answer is for this deployment. The design-time inventory declares 7 host entries across 7 role groups and its own comment says the topology is operator-dependent, so the fleet size is between 1 and 7 and the repository cannot settle it. The canonical path for a role-separated deployment is the same by construction — the unit's argument is fixed by the Redis Stack package — but that is an inference from the packaging, not a second measurement.
One nuance that narrows the work here: the role is not uniformly wrong about the path.
roles/redis/tasks/code_only.yml:26already documents/etc/redis-stack.conf, andmain.yml:237records thatrequirepassis deliberately not touched there. So the remaining work is a consolidation of several spellings, some of which are already correct — and any guard counting them should expect the correct spelling to be present rather than treating every occurrence as a defect.Full evidence on #17434.
- removedblocked: observation-gatedCode remains, but cannot be written until one observation answers a questionCode remains, but cannot be written until one observation answers a question
on Oct 3, 2026
Found
I found this while designing #13568's Redis authentication rollout. The SLM discovers a node's Redis password by reading
/etc/redis/redis.conf, but theroles/redisrole (the SLM's own provisioning path) renders/etc/redis-stack.conf.ReplicationService._get_redis_passwordautobot-slm-backend/services/replication.py:491-505grep '^requirepass' /etc/redis/redis.conf, over SSHautobot-slm-backend/services/backup.py:524-535REDISCLI_AUTHis built from itredis-replicationroleautobot-slm-backend/ansible/roles/redis-replication/defaults/main.yml:33(redis_config_file: "/etc/redis/redis.conf") and itstasks/main.yml:46-108{{ redis_config_file }}withlineinfileroles/redis, applied byprovision-fleet-roles.yml,deploy_role.yml,provision_host.yml,recover_host.ymlanddeploy.ymlroles/redis/tasks/main.yml:159-162/etc/redis-stack.confdeploy-database.yml(legacy):124-126{{ redis_config_dir }}/redis-stack.conf(/etc/redis-stack/redis-stack.conf)deploy-native-services.yml:116/etc/redis/redis.confOn a node provisioned through
roles/redis, nothing writes/etc/redis/redis.conf.Why it matters
Today no rendered config carries
requirepass(see #13568), so both readers get""and that happens to be correct. Once authentication is enforced:redis-replicationrole configures replication in a file the running server never reads.Acceptance criteria
redis-replicationedits the config file the runningredis-stack-serveractually loads on role-provisioned nodes, or it is converted to render through the role template.Refs #13568. It blocks #13568's enforcement phase: turning on
requirepassbefore this is fixed breaks replication and backups.