fix(docker): include anthropic, bedrock, azure-identity extras in image#30504
Conversation
Docker containers often run in isolated networks without access to PyPI. The lazy-install mechanism fails silently in these environments, causing ImportError when users try to use Anthropic, Bedrock, or Azure providers. Add --extra anthropic, --extra bedrock, and --extra azure-identity to the Dockerfile's uv sync command so these provider packages are pre-installed in the published image. Fixes NousResearch#30394
keegoid-codex
left a comment
There was a problem hiding this comment.
Verdict
VERDICT: approve
codex-review posting override: forced to --comment because reviewer lacks verified write permission (viewerPermission=READ; was --approve). GitHub only counts approvals from WRITE, MAINTAIN, or ADMIN reviewers.
|
[DEV SecOps] verdict: PASS Scope: #30504, base main, changed file: Dockerfile only.
Residual risk: Docker image size and provider import behavior are functional/ops concerns outside this security gate; registry ownership-transfer history is not directly exposed by PyPI APIs, but package identity, repository provenance, upload metadata, hashes, and download health checked clean for the pinned versions above. |
keegoid-codex
left a comment
There was a problem hiding this comment.
Severity
- low. Dockerfile-only install selection; no runtime code path changed.
VERDICT: approve
codex-review posting override: forced to --comment because reviewer lacks verified write permission (viewerPermission=READ; was --approve). GitHub only counts approvals from WRITE, MAINTAIN, or ADMIN reviewers.
|
[DEV SecOps] verdict: PASS Categories:
Read-only checks used: GitHub PR metadata/API diff pinned to the SHA above; Dockerfile/pyproject/uv.lock static inspection; prompt-injection trigger scan; PyPI + pypistats direct-package registry spot-check. No PR code executed. Residual risk: PyPI ownership-transfer history is not exposed by the public PyPI JSON API; mitigated by official vendor package identities, high package age/downloads, and existing |
benbarclay
left a comment
There was a problem hiding this comment.
Thanks for the fix — the bug is real and the scope is right.
I verified the premise against current origin/main (1e71b71):
pyproject.toml's[all]extra (line 179) explicitly excludesanthropic,bedrock,azure-identityper the 2026-05-12 lazy-install policy.- Dockerfile currently runs
uv sync --frozen --no-install-project --extra all --extra messaging, so those provider packages are not in the published image. tools/lazy_deps.pyregistersprovider.anthropic,provider.bedrock,provider.azure_identity— these install from PyPI at first use, which is exactly what air-gapped Docker users can't do. Issue #30394 (Rocky9 docker) reproduces this cleanly.
The diff itself (5 added, 1 removed) is minimal and correct.
One blocking concern: this ships a CVE-vulnerable anthropic pin
There's a latent version drift on main that this PR would expose to all Docker users:
| Path | Version | Status |
|---|---|---|
tools/lazy_deps.py line 81 |
anthropic==0.87.0 |
CVE-patched (per the inline comment + PR #26830) |
pyproject.toml [anthropic] extra (line 72) |
anthropic==0.86.0 |
CVE-2026-34450, CVE-2026-34452 |
uv.lock |
anthropic 0.86.0 |
matches the extra |
This drift was introduced when the v0.14.0 release commit (a91a57f) accidentally reverted the [anthropic] extra from 0.87.0 back to 0.86.0. The lazy-install path stayed on the patched 0.87.0, so host users using lazy-install today get the fix.
But this PR routes Docker users through the [anthropic] extra — i.e. they would get baked-in 0.86.0, with both CVEs present. That's a security regression versus the current behavior where Docker users either: (a) don't use Anthropic at all (today's broken case), or (b) lazy-install and pick up 0.87.0.
The fix is small and parallels what #26830 already did:
-anthropic = ["anthropic==0.86.0"]
+anthropic = ["anthropic==0.87.0"] # CVE-2026-34450, CVE-2026-34452…plus a uv lock regeneration (only the anthropic entry + its hashes should move; see the uv.lock portion of d725407 for the shape).
Could you fold that into this PR? Once [anthropic] is back at 0.87.0, the Docker include is unambiguously a safety improvement.
Other observations (non-blocking)
- Image size: adding
bedrockpulls in boto3 (~50–80MB unpacked). That's the right tradeoff for an "include common providers" change, just worth being explicit so a future image-size audit doesn't try to revert this. The Dockerfile comment you added covers the rationale well. - Scope: I considered whether
exa,firecrawl,fal, etc. should also be pulled in for the same air-gapped argument. I think keeping this PR narrowly scoped to the providers from the linked issue is right — pulling in more lazy-install extras is a separate policy conversation (andmessaging,matrix,slackare even more loaded sincematrixhas the python-olm Windows-build issue called out in pyproject.toml's[all]comment). The current scope is defensible. - Secops bot flagged this as PASS on supply-chain grounds and I agree with that read — the extras are already declared, already locked, and the diff doesn't churn the lockfile.
LGTM modulo the anthropic pin bump. Once that's in I'll re-review and land it.
benbarclay
left a comment
There was a problem hiding this comment.
Approving to unblock the merge.
Confirmed with @teknium1 offline that the anthropic 0.86.0 → 0.87.0 bump (CVE-2026-34450, CVE-2026-34452) is being handled separately. That keeps this PR cleanly scoped to the air-gapped-Docker fix from #30394, where it belongs.
For posterity: the relevant CVEs are SDK filesystem-memory-tool issues that aren't directly exploitable from hermes-agent's call paths (per Teknium's commit message on the original bump in d725407 / #26830 — "Not directly exploitable since hermes-agent doesn't use the SDK's filesystem memory tool"), so shipping 0.86.0 in a published image for the short window between this merge and the version bump is acceptable hygiene-level exposure, not a directly exploitable vulnerability.
Thanks for the clean fix. Merging.
…394-docker-anthropic-package fix(docker): include anthropic, bedrock, azure-identity extras in image Fixes NousResearch#30394. Air-gapped/restricted-network Docker containers can't reach PyPI for lazy-install, so `--extra anthropic --extra bedrock --extra azure-identity` are now added to the Dockerfile's `uv sync` so these provider packages are baked into the published image. The [all] extra deliberately excludes these (per the 2026-05-12 lazy-install policy on [all]) to keep `uv sync --locked` from breaking when one of their pinned versions gets PyPI-quarantined. The Dockerfile adds them back via additive --extra flags, mirroring the existing --extra messaging pattern (issue NousResearch#24698 / test_dockerfile_pid1_reaping.py). Follow-up: separate PR will bump pyproject.toml's [anthropic] extra from 0.86.0 to 0.87.0 to converge with tools/lazy_deps.py's CVE-patched pin (CVE-2026-34450, CVE-2026-34452).
The native Hindsight memory provider lazy-installs hindsight-client into
/opt/hermes/.venv at first use (tools/lazy_deps.py: memory.hindsight).
That venv lives inside the immutable image layer, not the mounted
/opt/data volume, so the dependency is wiped on every container recreate
/ image update. After an update, profile config still points at Hindsight
and the Hindsight server is healthy, but recall/retain fails with:
ModuleNotFoundError: No module named 'hindsight_client'
The manual workaround (uv pip install hindsight-client inside the running
container) doesn't survive the next recreate, and pip-install-into-.venv
is not an officially supported durable Docker workflow.
Fix: add --extra hindsight to the image's uv sync line, same pattern as
the --extra anthropic/bedrock/azure-identity providers (#30504) and
--extra messaging (#24698) — bake the optional dependency into the build
layer so it survives container recreate. The pyproject [hindsight] pin
(hindsight-client==0.6.1) already matches tools/lazy_deps.py and uv.lock,
so this is a pure additive --extra with no lockfile churn.
Verified: 'uv sync --frozen --no-install-project --extra hindsight'
against the committed uv.lock installs hindsight-client 0.6.1 and the
module imports cleanly.
Adds a regression test (mirrors test_dockerfile_preinstalls_gateway_
messaging_dependencies) so a future Dockerfile cleanup can't silently
drop the extra.
NousResearch#38530) The native Hindsight memory provider lazy-installs hindsight-client into /opt/hermes/.venv at first use (tools/lazy_deps.py: memory.hindsight). That venv lives inside the immutable image layer, not the mounted /opt/data volume, so the dependency is wiped on every container recreate / image update. After an update, profile config still points at Hindsight and the Hindsight server is healthy, but recall/retain fails with: ModuleNotFoundError: No module named 'hindsight_client' The manual workaround (uv pip install hindsight-client inside the running container) doesn't survive the next recreate, and pip-install-into-.venv is not an officially supported durable Docker workflow. Fix: add --extra hindsight to the image's uv sync line, same pattern as the --extra anthropic/bedrock/azure-identity providers (NousResearch#30504) and --extra messaging (NousResearch#24698) — bake the optional dependency into the build layer so it survives container recreate. The pyproject [hindsight] pin (hindsight-client==0.6.1) already matches tools/lazy_deps.py and uv.lock, so this is a pure additive --extra with no lockfile churn. Verified: 'uv sync --frozen --no-install-project --extra hindsight' against the committed uv.lock installs hindsight-client 0.6.1 and the module imports cleanly. Adds a regression test (mirrors test_dockerfile_preinstalls_gateway_ messaging_dependencies) so a future Dockerfile cleanup can't silently drop the extra.
NousResearch#38530) The native Hindsight memory provider lazy-installs hindsight-client into /opt/hermes/.venv at first use (tools/lazy_deps.py: memory.hindsight). That venv lives inside the immutable image layer, not the mounted /opt/data volume, so the dependency is wiped on every container recreate / image update. After an update, profile config still points at Hindsight and the Hindsight server is healthy, but recall/retain fails with: ModuleNotFoundError: No module named 'hindsight_client' The manual workaround (uv pip install hindsight-client inside the running container) doesn't survive the next recreate, and pip-install-into-.venv is not an officially supported durable Docker workflow. Fix: add --extra hindsight to the image's uv sync line, same pattern as the --extra anthropic/bedrock/azure-identity providers (NousResearch#30504) and --extra messaging (NousResearch#24698) — bake the optional dependency into the build layer so it survives container recreate. The pyproject [hindsight] pin (hindsight-client==0.6.1) already matches tools/lazy_deps.py and uv.lock, so this is a pure additive --extra with no lockfile churn. Verified: 'uv sync --frozen --no-install-project --extra hindsight' against the committed uv.lock installs hindsight-client 0.6.1 and the module imports cleanly. Adds a regression test (mirrors test_dockerfile_preinstalls_gateway_ messaging_dependencies) so a future Dockerfile cleanup can't silently drop the extra.
NousResearch#38530) The native Hindsight memory provider lazy-installs hindsight-client into /opt/hermes/.venv at first use (tools/lazy_deps.py: memory.hindsight). That venv lives inside the immutable image layer, not the mounted /opt/data volume, so the dependency is wiped on every container recreate / image update. After an update, profile config still points at Hindsight and the Hindsight server is healthy, but recall/retain fails with: ModuleNotFoundError: No module named 'hindsight_client' The manual workaround (uv pip install hindsight-client inside the running container) doesn't survive the next recreate, and pip-install-into-.venv is not an officially supported durable Docker workflow. Fix: add --extra hindsight to the image's uv sync line, same pattern as the --extra anthropic/bedrock/azure-identity providers (NousResearch#30504) and --extra messaging (NousResearch#24698) — bake the optional dependency into the build layer so it survives container recreate. The pyproject [hindsight] pin (hindsight-client==0.6.1) already matches tools/lazy_deps.py and uv.lock, so this is a pure additive --extra with no lockfile churn. Verified: 'uv sync --frozen --no-install-project --extra hindsight' against the committed uv.lock installs hindsight-client 0.6.1 and the module imports cleanly. Adds a regression test (mirrors test_dockerfile_preinstalls_gateway_ messaging_dependencies) so a future Dockerfile cleanup can't silently drop the extra.
…nthropic-package fix(docker): include anthropic, bedrock, azure-identity extras in image Fixes #30394. Air-gapped/restricted-network Docker containers can't reach PyPI for lazy-install, so `--extra anthropic --extra bedrock --extra azure-identity` are now added to the Dockerfile's `uv sync` so these provider packages are baked into the published image. The [all] extra deliberately excludes these (per the 2026-05-12 lazy-install policy on [all]) to keep `uv sync --locked` from breaking when one of their pinned versions gets PyPI-quarantined. The Dockerfile adds them back via additive --extra flags, mirroring the existing --extra messaging pattern (issue #24698 / test_dockerfile_pid1_reaping.py). Follow-up: separate PR will bump pyproject.toml's [anthropic] extra from 0.86.0 to 0.87.0 to converge with tools/lazy_deps.py's CVE-patched pin (CVE-2026-34450, CVE-2026-34452).
The native Hindsight memory provider lazy-installs hindsight-client into
/opt/hermes/.venv at first use (tools/lazy_deps.py: memory.hindsight).
That venv lives inside the immutable image layer, not the mounted
/opt/data volume, so the dependency is wiped on every container recreate
/ image update. After an update, profile config still points at Hindsight
and the Hindsight server is healthy, but recall/retain fails with:
ModuleNotFoundError: No module named 'hindsight_client'
The manual workaround (uv pip install hindsight-client inside the running
container) doesn't survive the next recreate, and pip-install-into-.venv
is not an officially supported durable Docker workflow.
Fix: add --extra hindsight to the image's uv sync line, same pattern as
the --extra anthropic/bedrock/azure-identity providers (#30504) and
--extra messaging (#24698) — bake the optional dependency into the build
layer so it survives container recreate. The pyproject [hindsight] pin
(hindsight-client==0.6.1) already matches tools/lazy_deps.py and uv.lock,
so this is a pure additive --extra with no lockfile churn.
Verified: 'uv sync --frozen --no-install-project --extra hindsight'
against the committed uv.lock installs hindsight-client 0.6.1 and the
module imports cleanly.
Adds a regression test (mirrors test_dockerfile_preinstalls_gateway_
messaging_dependencies) so a future Dockerfile cleanup can't silently
drop the extra.
Fixes #30394
Problem
Docker containers often run in isolated networks without access to PyPI. The lazy-install mechanism fails silently in these environments, causing ImportError when users try to use Anthropic, Bedrock, or Azure providers.
Error message:
Root Cause
The
[all]extra was intentionally slimmed down on 2026-05-12 to avoid quarantined PyPI packages breaking installs. Provider packages likeanthropic,bedrock, andazure-identitywere moved to lazy-install.However, Docker containers in air-gapped or restricted networks cannot reach PyPI at runtime, so lazy-install fails.
Solution
Add
--extra anthropic,--extra bedrock, and--extra azure-identityto the Dockerfile'suv synccommand so these provider packages are pre-installed in the published image.This ensures Docker users can use these common providers without requiring runtime network access to PyPI.