Skip to content

bug(slm): replication and backup read the Redis password from /etc/redis/redis.conf, a file roles/redis never renders #16625

Description

@mrveiss

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 the roles/redis role (the SLM's own provisioning path) renders /etc/redis-stack.conf.

Reader file:line Reads
ReplicationService._get_redis_password autobot-slm-backend/services/replication.py:491-505 grep '^requirepass' /etc/redis/redis.conf, over SSH
Redis backup auth discovery autobot-slm-backend/services/backup.py:524-535 the same grep; the backup's REDISCLI_AUTH is built from it
redis-replication role autobot-slm-backend/ansible/roles/redis-replication/defaults/main.yml:33 (redis_config_file: "/etc/redis/redis.conf") and its tasks/main.yml:46-108 edits {{ redis_config_file }} with lineinfile
Writer file:line Writes
roles/redis, applied by provision-fleet-roles.yml, deploy_role.yml, provision_host.yml, recover_host.yml and deploy.yml roles/redis/tasks/main.yml:159-162 /etc/redis-stack.conf
deploy-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.conf

On 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:

  • replication and backups on role-provisioned nodes silently get no password and fail against an authenticated server;
  • the redis-replication role configures replication in a file the running server never reads.

Acceptance criteria

Refs #13568. It blocks #13568's enforcement phase: turning on requirepass before this is fixed breaks replication and backups.

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.

Activity

  1. mrveiss commented on Sep 14, 2026

    @mrveiss
    OwnerAuthor

    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:488 return ssot_config.redis.password or "". services/backup.py:528 auth = redis_cli_auth(), which reads ssot_config.redis.password (services/redis_cli_auth.py:46). That value is the SLM-managed secret: slm_manager/templates/slm-secrets.env.j2:38 AUTOBOT_REDIS_PASSWORD={{ slm_redis_password }} is loaded by autobot-slm-backend.service.j2:48 EnvironmentFile= (default slm-secrets.env, defaults/main.yml:20-21) and read at autobot_shared/ssot_config.py:762 alias="AUTOBOT_REDIS_PASSWORD". Test: tests/test_redis_cli_auth_16627.py:90 test_the_config_file_grep_is_gone asserts that no string in the callers contains grep -E '^requirepass'.
    redis-replication edits the config file the running redis-stack-server loads, or renders through the role template not ticked Not touched by #16660. The redis-replication role still defaults redis_config_file to /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.
  2. added this to the v0.11.0 milestone on Sep 14, 2026
  3. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Labelling blocked: observation-gated behind #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 server on 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 by redis-cli INFO server and 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.

  4. added
    blocked: observation-gatedCode remains, but cannot be written until one observation answers a question
    on Oct 3, 2026
  5. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    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 file roles/redis never 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 server from the actual database-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:

    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.

  6. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    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-server
    

    Corroborated independently by systemctl show redis-server, whose ExecStart passes /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:26 already documents /etc/redis-stack.conf, and main.yml:237 records that requirepass is 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.

  7. removed
    blocked: observation-gatedCode remains, but cannot be written until one observation answers a question
    on Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions