Repository navigation
chore(hermes): update runtime to 0.20.6 #10595
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
69f133c
1c184c0
b641064
fda1835
3608065
2bbd3d3
37c47df
25f6077
8b89546
92f49da
97bdee4
6a7aafa
732dba8
7ebc0bf
7d540d4
997666e
619d344
a8a5fba
4f24bf1
2095221
28ca8c8
13574de
7d16555
c52e3da
14cdb62
65d02b7
ec0f8ca
59b3936
4f4bae5
e384bcf
216ba8b
42471ab
128522e
08aad07
3411f78
e626167
0efcebe
9d2e195
e2aedff
3dacc53
bbab740
25e1342
1354b97
ecf3708
e479c6f
91d5530
99d0863
4aa75e6
bdc726f
6bd002a
55c2682
488f1e6
ff68d77
88a7c41
02c236c
4deef0d
591483d
ebe8a9d
1d1a606
2cebf41
6de7ba8
417f8c7
07b184e
ce1c762
64b455d
0bce4a2
2ce65e7
baa9668
4599963
daffdec
d7855f9
873f470
1464849
61d0683
9ef7503
dbcf087
bbfccf0
0c3d293
cfe6178
870bc03
6c61b4c
e156cee
e49e9a0
4fea838
9d8f410
f6e8618
41eb922
75f7a33
310bd97
9aee878
45ba65f
225b150
199a45e
8489f2b
3619372
9e51d29
e6a11db
50d339b
a3ccb8c
2a3627a
33590f2
f618288
f5eeb5b
7ba3bab
1828a0e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,11 +70,11 @@ ENV DEBIAN_FRONTEND=noninteractive | |
| # pyproject.toml, HERMES_TARBALL_SHA256 the GitHub tarball checksum, and | ||
| # HERMES_NPM_INTEGRITY the `npm view hermes-agent@<semver> dist.integrity` | ||
| # sha512 used as a registry cross-check at build time. | ||
| # Calver tag v2026.7.20 = Hermes Agent v0.19.0. | ||
| ARG HERMES_VERSION=v2026.7.20 | ||
| ARG HERMES_SEMVER=0.19.0 | ||
| ARG HERMES_TARBALL_SHA256=285f3fc134ff466a90065e1517801a68993733b807158ee8f32aa01613786990 | ||
| ARG HERMES_NPM_INTEGRITY=sha512-+oVKG3lXbk2kEP+J6BXZjtmSBSaFfczIdOWQ9CUSTdTqq2uyHbk4p+kPyZ6MeGs56JU5qXzMNbqGKRVOQRGC1A== | ||
| # Calver tag v2026.8.27 = Hermes Agent v0.20.6. | ||
| ARG HERMES_VERSION=v2026.8.27 | ||
| ARG HERMES_SEMVER=0.20.6 | ||
| ARG HERMES_TARBALL_SHA256=e622723b5bf3cd6c1db974d92d32242f1cb63f61c1112b6f708b34d619ef0fc7 | ||
| ARG HERMES_NPM_INTEGRITY=sha512-s5q1IEBifCBb77QMwkse4MRaAaoZSxIa4IkicIO3jL7MIdq15YvnSyiNvsTOWNBi6t3shFpIg+H7+9MJsOiSkg== | ||
| ARG HERMES_UV_EXTRAS="anthropic messaging web pty mcp acp" | ||
| ARG NODE_VERSION=24.18.1 | ||
| ARG UV_VERSION=0.11.33 | ||
|
|
@@ -424,7 +424,10 @@ RUN printf '%s\n' \ | |
| # final image when selected. | ||
| # New Hermes integrations should be installed by the agent workflow when they | ||
| # are enabled rather than shipped in the base image by default. | ||
| # Root Node dependencies provide Hermes browser tooling such as agent-browser. | ||
| # Hermes 0.20.6 deliberately keeps agent-browser outside the root workspace | ||
| # graph and resolves the exact NemoClaw-pinned package through npx. Warm that | ||
| # package in the sandbox user's runtime cache below so browser startup does not | ||
| # require a registry fetch. | ||
| # The WhatsApp adapter ships a separate Node project under | ||
| # scripts/whatsapp-bridge whose dependencies Hermes otherwise installs lazily | ||
| # on the first `hermes whatsapp` run. That lazy `npm install` targets | ||
|
|
@@ -443,6 +446,7 @@ RUN pip3 install --no-cache-dir --break-system-packages "uv==${UV_VERSION}" \ | |
| # intentionally hostile security-test fixtures. Remove them in the extraction | ||
| # RUN so their bytes never enter a published image layer. | ||
| COPY agents/hermes/security-dependencies.patch /tmp/hermes-security-dependencies.patch | ||
| COPY agents/hermes/agent-browser-runtime/package.json agents/hermes/agent-browser-runtime/package-lock.json /tmp/nemoclaw-agent-browser-runtime/ | ||
| COPY agents/hermes/whatsapp-proxy.patch /tmp/hermes-whatsapp-proxy.patch | ||
| COPY scripts/checks/download-hermes-source-archive.sh /tmp/nemoclaw-download-hermes-source-archive.sh | ||
| RUN mkdir -p /opt/hermes \ | ||
|
|
@@ -498,16 +502,20 @@ WORKDIR /opt/hermes | |
| # workspaces disabled; this keeps browser tooling without either UI build tree. | ||
| # Root npm, Electron, and node-gyp caches are build-only. Remove them in the | ||
| # same RUN that creates them so Docker cannot retain their bytes in this layer. | ||
| # Hermes ships a `.python-version` for Python 3.11. Use the reviewed system | ||
| # Python 3.13 directly and forbid a root-private uv-managed interpreter so the | ||
| # finished virtual environment remains executable by the sandbox user. | ||
| # hadolint ignore=SC2086 | ||
| RUN set -eu; \ | ||
| set --; \ | ||
| for extra in ${HERMES_UV_EXTRAS}; do \ | ||
| set -- "$@" --extra "$extra"; \ | ||
| done; \ | ||
| uv sync --frozen --no-dev "$@" --no-cache \ | ||
| uv sync --python /usr/bin/python3.13 --no-managed-python \ | ||
| --frozen --no-dev "$@" --no-cache \ | ||
| && uv pip check --python /opt/hermes/.venv/bin/python \ | ||
| && /opt/hermes/.venv/bin/python -I -c \ | ||
| "from importlib.metadata import version; expected = {'agent-client-protocol': '0.9.0', 'aiohttp': '3.14.3', 'cryptography': '50.0.0', 'mcp': '1.28.1', 'pillow': '12.3.0', 'starlette': '1.3.1', 'tornado': '6.5.7'}; actual = {name: version(name) for name in expected}; assert actual == expected, actual" \ | ||
| "from importlib.metadata import version; expected = {'agent-client-protocol': '0.9.0', 'aiohttp': '3.14.3', 'cryptography': '50.0.0', 'mcp': '2.0.0', 'pillow': '12.3.0', 'starlette': '1.3.1', 'tornado': '6.5.7'}; actual = {name: version(name) for name in expected}; assert actual == expected, actual" \ | ||
| && npm ci --prefer-offline --no-audit --no-fund \ | ||
| && for ui_dir in ui-tui web; do \ | ||
| if [ -f "${ui_dir}/package-lock.json" ]; then \ | ||
|
|
@@ -549,11 +557,11 @@ RUN set -eu; \ | |
| # route that uses File/Form, so without python-multipart the plugin's API routes | ||
| # fail to mount ("Form data requires python-multipart to be installed"). | ||
| # | ||
| # Hermes 0.19.0 resolves 0.0.27, which is affected by the network-reachable | ||
| # GHSA-5rvq-cxj2-64vf CPU denial of service and GHSA-6jv3-5f52-599m parser | ||
| # differential. Keep this hash-verified downstream override at the first stable | ||
| # release that fixes those issues plus GHSA-v9pg-7xvm-68hf. Re-review the | ||
| # version and both hashes on every Hermes version bump. | ||
| # Hermes 0.20.6 resolves 0.0.32, the first stable release that addresses the | ||
| # reviewed network-reachable GHSA-5rvq-cxj2-64vf CPU denial of service, | ||
| # GHSA-6jv3-5f52-599m parser differential, and GHSA-v9pg-7xvm-68hf. Keep the | ||
| # hash-verified install so the final image cannot inherit a stale published | ||
| # base. Re-review the version and both hashes on every Hermes version bump. | ||
| # uv creates a phony .git cache marker even with --no-cache. Remove the cache | ||
| # after the final uv command because the root cache is not used at runtime. | ||
| # hadolint ignore=DL3059 | ||
|
|
@@ -569,6 +577,10 @@ RUN printf '%s\n' \ | |
| "import multipart; assert multipart.__version__ == '0.0.32', multipart.__version__" \ | ||
| && rm -rf /root/.cache/uv | ||
|
|
||
| # The offline lazy-package probe runs as the sandbox user. Make the finalized | ||
| # virtual environment readable before that unprivileged build-time check. | ||
| RUN chmod -R a+rX /opt/hermes/.venv | ||
|
|
||
| # Keep official-package compatibility separate from the final image's offline | ||
| # lazy-installer contract. BuildKit verifies both reviewed PyPI artifacts before | ||
| # any build command can consume them. Install only those hash-locked wheels into | ||
|
|
@@ -607,12 +619,63 @@ RUN --network=none install -d -o sandbox -g sandbox -m 0750 \ | |
| ENV PATH="/usr/local/bin:/opt/hermes/.venv/bin:${PATH}" \ | ||
| HERMES_TUI_DIR="/opt/hermes/ui-tui" \ | ||
| HERMES_WEB_DIST="/opt/hermes/hermes_cli/web_dist" | ||
|
|
||
| # Hermes 0.20.6 removed agent-browser from its root dependency graph. Prove | ||
| # that the patched source selects the exact npx fallback. Cache the exact | ||
| # registry package, bind its observed integrity to the reviewed lockfile, then | ||
| # prove the cached package works without network access. | ||
| RUN HOME=/sandbox \ | ||
| /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- \ | ||
| /opt/hermes/.venv/bin/python -c \ | ||
| 'from tools import browser_tool; assert browser_tool.AGENT_BROWSER_NPX_SPEC == "agent-browser@0.26.0"; assert browser_tool._find_agent_browser() == browser_tool.NPX_AGENT_BROWSER_SENTINEL' | ||
| RUN chown -R sandbox:sandbox /tmp/nemoclaw-agent-browser-runtime \ | ||
| && install -o sandbox -g sandbox -m 0400 /dev/null \ | ||
| /tmp/nemoclaw-agent-browser-runtime/npm-userconfig \ | ||
| && install -o sandbox -g sandbox -m 0400 /dev/null \ | ||
| /tmp/nemoclaw-agent-browser-runtime/npm-globalconfig \ | ||
| && expected_browser_integrity='sha512-pdqSfjwbFSp+qnwlb2g23e9wXveIOfMi19xpPA9xZUbzEAUp6W4YBZj6Ybj8z4M7WkcbGDDYc+oDIHDt9R3EDQ==' \ | ||
| && HOME=/sandbox npm_config_cache=/sandbox/.npm \ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Keep the npx executable outside the sandbox write boundary This creates and executes the /sandbox/.npm npx cache as the sandbox user, and no later layer makes that cache root-owned or immutable. Supported OpenShell startup also runs Hermes as sandbox, so untrusted sandbox code can replace the cached agent-browser launcher before Hermes invokes it. Hermes then passes BROWSERBASE_API_KEY, BROWSER_USE_API_KEY, FIRECRAWL_API_KEY, and related browser keys into that launcher. An exact npm 11 reproduction left the _npx launcher sandbox-owned with mode 0700 and executed a replacement offline. Install the reviewed executable in a root-owned immutable path and add a negative sandbox-mutation test. |
||
| npm_config_registry=https://registry.npmjs.org/ \ | ||
| npm_config_userconfig=/tmp/nemoclaw-agent-browser-runtime/npm-userconfig \ | ||
| npm_config_globalconfig=/tmp/nemoclaw-agent-browser-runtime/npm-globalconfig \ | ||
| npm_config_ignore_scripts=true \ | ||
| /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- \ | ||
| /usr/local/bin/npm cache add agent-browser@0.26.0 \ | ||
| && registry_browser_integrity="$( \ | ||
| HOME=/sandbox npm_config_cache=/sandbox/.npm \ | ||
| npm_config_registry=https://registry.npmjs.org/ \ | ||
| npm_config_userconfig=/tmp/nemoclaw-agent-browser-runtime/npm-userconfig \ | ||
| npm_config_globalconfig=/tmp/nemoclaw-agent-browser-runtime/npm-globalconfig \ | ||
| npm_config_ignore_scripts=true \ | ||
| /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- \ | ||
| /usr/local/bin/npm view agent-browser@0.26.0 dist.integrity \ | ||
| )" \ | ||
| && test "${registry_browser_integrity}" = "${expected_browser_integrity}" \ | ||
| && HOME=/sandbox npm_config_cache=/sandbox/.npm \ | ||
| npm_config_registry=https://registry.npmjs.org/ \ | ||
| npm_config_userconfig=/tmp/nemoclaw-agent-browser-runtime/npm-userconfig \ | ||
| npm_config_globalconfig=/tmp/nemoclaw-agent-browser-runtime/npm-globalconfig \ | ||
| npm_config_ignore_scripts=true \ | ||
| /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- \ | ||
| /usr/local/bin/npm ci \ | ||
| --prefix /tmp/nemoclaw-agent-browser-runtime \ | ||
| --ignore-scripts --no-audit --no-fund \ | ||
| && rm -rf /tmp/nemoclaw-agent-browser-runtime/node_modules | ||
| RUN --network=none agent_browser_version="$( \ | ||
| HOME=/sandbox npm_config_cache=/sandbox/.npm npm_config_offline=true \ | ||
| npm_config_registry=https://registry.npmjs.org/ \ | ||
| npm_config_userconfig=/tmp/nemoclaw-agent-browser-runtime/npm-userconfig \ | ||
| npm_config_globalconfig=/tmp/nemoclaw-agent-browser-runtime/npm-globalconfig \ | ||
| npm_config_ignore_scripts=true \ | ||
| /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- \ | ||
| /usr/local/bin/npx --ignore-scripts --prefer-offline -y \ | ||
| agent-browser@0.26.0 --version \ | ||
| )" \ | ||
| && test "${agent_browser_version}" = 'agent-browser 0.26.0' \ | ||
| && rm -rf /tmp/nemoclaw-agent-browser-runtime | ||
|
|
||
| RUN /usr/local/bin/hermes --version \ | ||
| && /usr/local/bin/hermes acp --check \ | ||
| && test -x /opt/hermes/node_modules/.bin/agent-browser \ | ||
| && /opt/hermes/node_modules/.bin/agent-browser --version \ | ||
| && /opt/hermes/.venv/bin/python -c \ | ||
| 'from tools import browser_tool; expected = "/opt/hermes/node_modules/.bin/agent-browser"; assert browser_tool._find_agent_browser() == expected' \ | ||
| && test -s "${HERMES_TUI_DIR}/dist/entry.js" \ | ||
| && test -s "${HERMES_WEB_DIST}/index.html" \ | ||
| && test ! -e /opt/hermes/.node_modules.runtime \ | ||
|
|
@@ -622,10 +685,9 @@ RUN /usr/local/bin/hermes --version \ | |
| && rmdir /opt/hermes/node_modules \ | ||
| && mv /opt/hermes/.node_modules.runtime /opt/hermes/node_modules \ | ||
| && /opt/hermes/.venv/bin/python -c \ | ||
| 'import mcp; from tools import mcp_tool; assert getattr(mcp_tool, "_MCP_AVAILABLE", False), "Hermes MCP client runtime is unavailable"; assert getattr(mcp_tool, "_MCP_HTTP_AVAILABLE", False), "Hermes MCP Streamable HTTP runtime is unavailable"' | ||
| 'import mcp; from tools import mcp_tool; assert mcp_tool._ensure_mcp_sdk(), "Hermes MCP client runtime is unavailable"; assert getattr(mcp_tool, "_MCP_AVAILABLE", False), "Hermes MCP client runtime is unavailable"; assert getattr(mcp_tool, "_MCP_HTTP_AVAILABLE", False), "Hermes MCP Streamable HTTP runtime is unavailable"' | ||
|
|
||
| RUN chmod -R a+rX /opt/hermes/.venv \ | ||
| && test -r /opt/hermes/.venv/pyvenv.cfg \ | ||
| RUN test -r /opt/hermes/.venv/pyvenv.cfg \ | ||
| && su -s /bin/sh sandbox -c '/opt/hermes/.venv/bin/python3 -c "import urllib.request"' | ||
|
|
||
| # Reject build-only paths before the base image can be published. | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "name": "nemoclaw-hermes-agent-browser-runtime", | ||
| "version": "1.0.0", | ||
| "private": true, | ||
| "dependencies": { | ||
| "agent-browser": "0.26.0" | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.