Honor INFRAHUB_CACHE_TLS_* in Prefect result storage block#9218
Conversation
Background flows hung in RUNNING against TLS-only Redis because setup_blocks() built the Prefect RedisStorageContainer via from_host(), whose internal client path constructs redis.Redis(...) with no ssl= argument. INFRAHUB_CACHE_TLS_* settings were silently ignored for this one client even though lock.py and the cache adapter honored them. Always construct a connection_string URL from cache settings. Scheme selects rediss:// when tls_enabled is set; ssl_cert_reqs / ssl_check_hostname / ssl_ca_certs propagate as query params through redis.Redis.from_url onto the underlying SSLConnection. Single deterministic code path; brings the block in parity with the rest of the codebase's Redis clients. Closes #9217 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
There was a problem hiding this comment.
1 issue found across 3 files
Confidence score: 3/5
- There is a concrete connectivity risk in
backend/infrahub/workflows/initialization.py: composing the Redis URL without IPv6 brackets can produce an invalid connection string for valid IPv6 hosts. - Given the issue is medium severity (5/10) but high confidence (9/10) and can affect cache initialization behavior in IPv6 environments, this introduces some user-impacting regression risk.
- Pay close attention to
backend/infrahub/workflows/initialization.py- ensure IPv6 cache hosts are wrapped in[]when building the Redis URL.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/infrahub/workflows/initialization.py">
<violation number="1" location="backend/infrahub/workflows/initialization.py:53">
P2: Wrap IPv6 addresses in `[]` before composing the Redis URL, otherwise valid IPv6 cache hosts generate an invalid connection string.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
| query["ssl_ca_certs"] = cache.tls_ca_file | ||
|
|
||
| qs = f"?{urlencode(query)}" if query else "" | ||
| return f"{scheme}://{userinfo}{cache.address}:{cache.service_port}/{cache.database}{qs}" |
There was a problem hiding this comment.
P2: Wrap IPv6 addresses in [] before composing the Redis URL, otherwise valid IPv6 cache hosts generate an invalid connection string.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/infrahub/workflows/initialization.py, line 53:
<comment>Wrap IPv6 addresses in `[]` before composing the Redis URL, otherwise valid IPv6 cache hosts generate an invalid connection string.</comment>
<file context>
@@ -17,6 +21,38 @@
+ query["ssl_ca_certs"] = cache.tls_ca_file
+
+ qs = f"?{urlencode(query)}" if query else ""
+ return f"{scheme}://{userinfo}{cache.address}:{cache.service_port}/{cache.database}{qs}"
+
+
</file context>
| return f"{scheme}://{userinfo}{cache.address}:{cache.service_port}/{cache.database}{qs}" | |
| host = cache.address | |
| if ":" in host and not host.startswith("["): | |
| host = f"[{host}]" | |
| return f"{scheme}://{userinfo}{host}:{cache.service_port}/{cache.database}{qs}" |
|
This PR has been inactive for 2 weeks and has been marked as stale. If you're still working on this, please:
The stale label will be removed automatically when there's new activity. |
| same INFRAHUB_CACHE_TLS_* settings directly. | ||
| """ | ||
| if cache.username and not cache.password: | ||
| raise ValueError("INFRAHUB_CACHE_USERNAME is set but INFRAHUB_CACHE_PASSWORD is not. Both are required.") |
There was a problem hiding this comment.
I would expect something like this to be a validator on https://github.com/opsmill/infrahub/blob/infrahub-v1.9.6/backend/infrahub/config.py#L398 instead.
Summary
RUNNINGagainst TLS-only Redis becausesetup_blocks()built the PrefectRedisStorageContainerviafrom_host(), whose internal client path constructsredis.Redis(...)with nossl=argument.INFRAHUB_CACHE_TLS_ENABLED/INFRAHUB_CACHE_TLS_INSECURE/INFRAHUB_CACHE_TLS_CA_FILEwere silently ignored for this one client, whilelock.pyand the cache adapter honored them.setup_blocks()now always builds aconnection_stringURL fromCacheSettings. Scheme switches betweenredis://andrediss://based ontls_enabled;tls_insecureencodes asssl_cert_reqs=none&ssl_check_hostname=False;tls_ca_fileencodes asssl_ca_certs=<path>.redis.Redis.from_urlparses these query params and applies them to the underlyingSSLConnection, so all three TLS knobs become deterministic across every Redis client in the codebase.if/elsebetween two constructors, no Prefect upstream change, no follow-on "doesn't apply here" warning needed.Behavior change
Previously, setting
INFRAHUB_CACHE_USERNAMEwithoutINFRAHUB_CACHE_PASSWORDproduced a Prefect block-construction error. The new helper raisesValueErrorwith an explicit message before reaching Prefect — same outcome (startup fails), clearer diagnostic.Test plan
uv run pytest backend/tests/unit/workflows/— 276 passed (18 new tests intest_initialization.py)uv run mypy backend/infrahub/workflows/initialization.py— cleanuv run ruff check backend/infrahub/workflows/initialization.py backend/tests/unit/workflows/test_initialization.py— cleanNew test coverage
backend/tests/unit/workflows/test_initialization.pycovers:tls_insecure,tls_ca_file, both TLS flags combined, and the negative case thattls_insecure/tls_ca_fileare ignored whentls_enabled=False.ValueErrorwith explicit message.redis.ConnectionPool.from_url(6 parametrized cases): proves the URL we build resolves to the expectedconnection_class(ConnectionvsSSLConnection) and propagates host / port / db / username / password /ssl_cert_reqs/ssl_check_hostname/ssl_ca_certscorrectly. This guards against silent regressions in redis-py's URL parser.Closes #9217
🤖 Generated with Claude Code
Summary by cubic
Fixes Prefect result storage against TLS-only Redis by honoring
INFRAHUB_CACHE_TLS_*settings via aredis:///rediss://connection string. Unifies TLS behavior across all Redis clients and prevents background flows from hanging.CacheSettings; userediss://whenINFRAHUB_CACHE_TLS_ENABLEDis true.INFRAHUB_CACHE_TLS_INSECURE→ssl_cert_reqs=none&ssl_check_hostname=False;INFRAHUB_CACHE_TLS_CA_FILE→ssl_ca_certs=<path>. Parsed byredis.Redis.from_urland applied toSSLConnection.RedisStorageContainer.from_hostwithRedisStorageContainer(connection_string=...)for a single, consistent path.INFRAHUB_CACHE_USERNAMEwithoutINFRAHUB_CACHE_PASSWORDnow raises aValueErrorwith an explicit message.Written for commit 2ae4c39. Summary will update on new commits.