diff --git a/hermesagent/Chart.yaml b/hermesagent/Chart.yaml index eb52110b7..463f5a3c4 100644 --- a/hermesagent/Chart.yaml +++ b/hermesagent/Chart.yaml @@ -3,4 +3,4 @@ appVersion: '0.15.2' description: The self-improving AI agent built by Nous Research name: hermesagent type: application -version: 1.3.10 \ No newline at end of file +version: 1.3.14 \ No newline at end of file diff --git a/hermesagent/OlaresManifest.yaml b/hermesagent/OlaresManifest.yaml index bc753eca4..7a39d3697 100644 --- a/hermesagent/OlaresManifest.yaml +++ b/hermesagent/OlaresManifest.yaml @@ -6,7 +6,7 @@ metadata: description: The agent that grows with you appid: hermesagent title: Hermes Agent - version: 1.3.10 + version: 1.3.14 categories: - Productivity_v112 - Developer Tools @@ -62,16 +62,11 @@ spec: - Localized into 7 languages (中文 / 日本語 / Deutsch / Español / Français / Українська / Türkçe) plus a Chinese dashboard. upgradeDescription: | - Hermes Agent app upgrade to v0.15.2 (2026.5.29.2): - - Major changes: - - Core architecture refactor: run_agent.py was reduced from 16,083 to 3,821 lines and split across 14 agent/* modules to improve maintainability and development velocity. - - Significant performance gains: Cold start was further optimized, hermes --version cold start dropped by 63%, per-turn function calls fell by 47%, and session_search was rebuilt to be LLM-free, cost-free, and about 4,500× faster. - - Kanban becomes a multi-agent platform: It adds task auto-decomposition, Swarm topology, scheduled tasks, per-task model overrides, worktree-per-task support, and worker/run inspection endpoints. - - Security and secrets improved: Hermes adds defenses against Promptware/Brainworm-style attacks, while Bitwarden Secrets Manager can replace multiple provider API keys with one bootstrap token and support source labeling plus effective rotation. - - Ecosystem and integrations expanded: New additions include skill bundles, ntfy notifications, OpenHands orchestration, a Nous-approved MCP catalog, Krea/FAL image generation providers, and deeper xAI integration. - - view full release notes: https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.29.2 + Config changes: Change HERMUES_UID 1000:1000 + + Change Details: + - Align Hermes runtime identity to Olares UID 1000:1000 (replacing 10000), with automatic ownership migration on upgrade. + - Fix Terminal and Dashboard access: unified shell privilege drop for interactive sessions, persistent brew PATH, and Home/External volume mounts on the dashboard container. developer: Nous Research website: https://hermes-agent.nousresearch.com diff --git a/hermesagent/i18n/en-US/OlaresManifest.yaml b/hermesagent/i18n/en-US/OlaresManifest.yaml index c3f7e377e..0188bc9a4 100644 --- a/hermesagent/i18n/en-US/OlaresManifest.yaml +++ b/hermesagent/i18n/en-US/OlaresManifest.yaml @@ -30,13 +30,8 @@ spec: - Localized into 7 languages (中文 / 日本語 / Deutsch / Español / Français / Українська / Türkçe) plus a Chinese dashboard. upgradeDescription: | - Hermes Agent app upgrade to v0.15.2 (2026.5.29.2): - - Major changes: - - Core architecture refactor: run_agent.py was reduced from 16,083 to 3,821 lines and split across 14 agent/* modules to improve maintainability and development velocity. - - Significant performance gains: Cold start was further optimized, hermes --version cold start dropped by 63%, per-turn function calls fell by 47%, and session_search was rebuilt to be LLM-free, cost-free, and about 4,500× faster. - - Kanban becomes a multi-agent platform: It adds task auto-decomposition, Swarm topology, scheduled tasks, per-task model overrides, worktree-per-task support, and worker/run inspection endpoints. - - Security and secrets improved: Hermes adds defenses against Promptware/Brainworm-style attacks, while Bitwarden Secrets Manager can replace multiple provider API keys with one bootstrap token and support source labeling plus effective rotation. - - Ecosystem and integrations expanded: New additions include skill bundles, ntfy notifications, OpenHands orchestration, a Nous-approved MCP catalog, Krea/FAL image generation providers, and deeper xAI integration. - - view full release notes: https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.29.2 \ No newline at end of file + Config changes: Change HERMUES_UID 1000:1000 + + Change Details: + - Align Hermes runtime identity to Olares UID 1000:1000 (replacing 10000), with automatic ownership migration on upgrade. + - Fix Terminal and Dashboard access: unified shell privilege drop for interactive sessions, persistent brew PATH, and Home/External volume mounts on the dashboard container. \ No newline at end of file diff --git a/hermesagent/i18n/zh-CN/OlaresManifest.yaml b/hermesagent/i18n/zh-CN/OlaresManifest.yaml index 2eca69d0c..0c0f17281 100644 --- a/hermesagent/i18n/zh-CN/OlaresManifest.yaml +++ b/hermesagent/i18n/zh-CN/OlaresManifest.yaml @@ -30,13 +30,8 @@ spec: - 已本地化为 7 种语言(中文 / 日本語 / Deutsch / Español / Français / Українська / Türkçe),Dashboard 已支持中文。 upgradeDescription: | - Hermes Agent 应用升级到 v0.15.2(2026.5.29.2) + 配置变更:将 HERMES_UID 更改为 1000:1000 - 主要变更: - - 核心架构重构:run_agent.py 从 16,083 行精简至 3,821 行,并拆分为 14 个 agent/* 模块,提升可维护性与开发效率。 - - 显著性能提升:冷启动再优化,hermes --version 冷启动耗时降低 63%,每回合函数调用减少 47%,session_search 重写为无 LLM、零成本、速度提升约 4,500×。 - - Kanban 进化为多 Agent 平台:新增任务自动拆解、Swarm 拓扑、定时任务、任务级模型覆盖、每任务工作区、任务执行/运行检测端点。 - - 安全性与密钥管理增强:Hermes 新增防御 Promptware/Brainworm 风格攻击机制,Bitwarden Secrets Manager 支持以单一引导令牌替代多平台 API 密钥,实现来源标签和高效轮换。 - - 生态与集成扩展:加入技能包、ntfy 通知、OpenHands 编排、Nous 官方批准的 MCP 目录、Krea/FAL 图像生成提供商和更深入的 xAI 集成。 - - 查看完整更新日志:https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.29.2 \ No newline at end of file + 具体变更说明: + - 统一 Hermes 运行身份为 Olares 平台的 UID 1000:1000(由原 10000 替换),升级时自动迁移已有文件属主。 + - 修复终端和 Dashboard 访问:统一交互式会话降权方案,brew 路径永久有效,Dashboard 容器支持 Home/External 卷挂载。 \ No newline at end of file diff --git a/hermesagent/templates/deployment.yaml b/hermesagent/templates/deployment.yaml index 158948dea..d2792d075 100644 --- a/hermesagent/templates/deployment.yaml +++ b/hermesagent/templates/deployment.yaml @@ -3,11 +3,12 @@ # as the single source of truth (SQLite, config, .env, skills, memories). # # The s6-overlay v3 image (/init as PID 1) MUST start as root: s6 chowns /run + -# /opt/data and drops every service to the hermes user (uid 10000) via -# s6-setuidgid. Pinning runAsUser:10000 breaks that drop (setgroups EPERM), so -# we start as root like the upstream docker-compose (HERMES_UID/HERMES_GID). -# `kubectl exec` then attaches as root, but /opt/hermes/bin/hermes (first on -# PATH) re-execs the CLI as hermes so files stay uid-10000-owned. +# /opt/data and drops every service to the hermes user via s6-setuidgid. +# Pinning runAsUser breaks that drop (setgroups EPERM), so we start as root +# and pass HERMES_UID/HERMES_GID=1000 to match Olares userData ownership. +# `kubectl exec` attaches as root; interactive shells source drop-to-hermes +# (profile.d + $HOME/.bashrc) to re-exec as hermes (uid 1000). The hermes +# CLI shim at /opt/hermes/bin/hermes does the same for non-interactive calls. --- apiVersion: apps/v1 kind: Deployment @@ -29,14 +30,14 @@ spec: io.kompose.service: hermesagent bytetrade.io/terminal: hermesagent spec: - # Start as root so s6 can drop services to uid 10000 itself; do NOT set + # Start as root so s6 can drop services to uid 1000 itself; do NOT set # runAsUser (breaks s6's privilege drop). fsGroup keeps volumes group- - # accessible to 10000. + # accessible to 1000 (Olares platform default). securityContext: - fsGroup: 10000 + fsGroup: 1000 initContainers: - # Chown /opt/data to 10000 before runtime (hostPath may start root-owned). + # Chown /opt/data to 1000 before runtime (hostPath may start root-owned). - name: init-chmod-data image: "beclab/aboveos-busybox:1.37.0" securityContext: @@ -46,10 +47,35 @@ spec: - sh - "-c" - | - mkdir -p /opt/data - chown -R 10000:10000 /opt/data || true + mkdir -p /opt/data/.olares-cli/data + chown -R 1000:1000 /opt/data || true chmod -R u+rwX,g+rwX /opt/data || true - echo "[init] /opt/data ready (owner=10000:10000)" + # Hook interactive shells into drop-to-hermes (kubectl exec is root). + MARKER="# hermesagent: drop-to-hermes" + for rc in /opt/data/.bashrc /opt/data/.profile; do + if [ ! -f "$rc" ] || ! grep -qF "$MARKER" "$rc" 2>/dev/null; then + { + echo "" + echo "$MARKER" + echo '[ -f /etc/profile.d/99-drop-to-hermes.sh ] && . /etc/profile.d/99-drop-to-hermes.sh' + } >> "$rc" + fi + done + # Keep brew + hermes on PATH after bash -l resets profile (hermes uid shells). + PATH_MARKER="# hermesagent: brew-path" + for rc in /opt/data/.bashrc /opt/data/.profile; do + if ! grep -qF "$PATH_MARKER" "$rc" 2>/dev/null; then + { + echo "" + echo "$PATH_MARKER" + echo 'export HOMEBREW_PREFIX="${HOMEBREW_PREFIX:-/home/linuxbrew/.linuxbrew}"' + echo 'export HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE:-1}"' + echo 'export PATH="/opt/hermes/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/hermes/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' + } >> "$rc" + fi + done + chown 1000:1000 /opt/data/.bashrc /opt/data/.profile 2>/dev/null || true + echo "[init] /opt/data ready (owner=1000:1000, .olares-cli seeded)" resources: {} volumeMounts: - mountPath: /opt/data @@ -79,16 +105,45 @@ spec: cp -a /brew-staging/.linuxbrew/. /home/linuxbrew/.linuxbrew/ fi - # Stage olares-cli into brew bin. + # Stage olares-cli into the persistent brew-volume bin dir. OLARES_CLI="" - for p in /usr/local/bin/olares-cli /brew-staging/.linuxbrew/bin/olares-cli /opt/olares-cli/olares-cli /olares-cli; do + for p in /usr/local/bin/olares-cli \ + /brew-staging/.linuxbrew/bin/olares-cli \ + /brew-staging/olares-cli \ + /opt/olares-cli/olares-cli \ + /olares-cli; do [ -x "$p" ] && OLARES_CLI="$p" && break done - [ -z "$OLARES_CLI" ] && OLARES_CLI="$(command -v olares-cli 2>/dev/null || find / -maxdepth 5 -type f -name olares-cli -perm -u+x 2>/dev/null | head -1)" + if [ -z "$OLARES_CLI" ]; then + OLARES_CLI="$(find /brew-staging /usr/local /opt -maxdepth 8 -type f \ + \( -name 'olares-cli' -o -name 'olares-cli-*' \) -perm -u+x 2>/dev/null | head -1)" + fi + if [ -z "$OLARES_CLI" ] && command -v curl >/dev/null 2>&1; then + case "$(uname -m)" in + x86_64|amd64) + OLARES_CLI_URL="https://cdn.olares.com/olares-cli-v1.12.7-20260510_linux_amd64.8705e94.tar.gz" + ;; + aarch64|arm64) + OLARES_CLI_URL="https://cdn.olares.com/olares-cli-v1.12.7-20260510_linux_arm64.8705e94.tar.gz" + ;; + esac + if [ -n "${OLARES_CLI_URL:-}" ]; then + echo "[init-brew] fetching olares-cli from CDN (${OLARES_CLI_URL})..." + mkdir -p /tmp/olares-cli-extract + if curl -fsSL -o /tmp/olares-cli.tgz "$OLARES_CLI_URL"; then + tar -xzf /tmp/olares-cli.tgz -C /tmp/olares-cli-extract + OLARES_CLI="$(find /tmp/olares-cli-extract -maxdepth 4 -type f \ + \( -name 'olares-cli' -o -name 'olares-cli-*' \) -perm -u+x 2>/dev/null | head -1)" + fi + fi + fi if [ -n "$OLARES_CLI" ]; then + mkdir -p /home/linuxbrew/.linuxbrew/bin install -m 0755 "$OLARES_CLI" /home/linuxbrew/.linuxbrew/bin/olares-cli + rm -f /home/linuxbrew/.linuxbrew/bin/olares-cli.real + echo "[init-brew] olares-cli staged to /home/linuxbrew/.linuxbrew/bin from $OLARES_CLI" else - echo "[init-brew] WARN: olares-cli not found" + echo "[init-brew] WARN: olares-cli not found (image + CDN)" fi # python3 shim -> hermes venv. @@ -112,7 +167,35 @@ spec: printf '#!/bin/sh\nF=/opt/hermes/hermes_cli/web_server.py\n[ -f "$F" ] && sed -i "s/return client_host in _LOOPBACK_HOSTS/return True/" "$F"\nexit 0\n' > /cli-bin/03-allow-dashboard-ws chmod 0755 /cli-bin/03-allow-dashboard-ws - chown -R 10000:10000 /home/linuxbrew || true + # Repair olares-cli state after legacy root kubectl exec writes. + printf '#!/bin/sh\nD="/opt/data/.olares-cli"\nmkdir -p "$D/data" 2>/dev/null || true\nchown -R 1000:1000 "$D" 2>/dev/null || true\nchmod -R u+rwX,g+rwX "$D" 2>/dev/null || true\nexit 0\n' \ + > /cli-bin/04-fix-olares-cli-perms + chmod 0755 /cli-bin/04-fix-olares-cli-perms + + # Interactive kubectl exec drops root → hermes (uid 1000) once per session. + # Mounted on the hermesagent container only; $HOME/.bashrc sources it too. + printf '%s\n' \ + '#!/bin/sh' \ + '# Olares: drop interactive root shells to hermes (UID 1000).' \ + '[ "${_HERMES_DROP_TO_HERMES:-}" = 1 ] && return 0' \ + '[ "$(id -u)" != 0 ] && return 0' \ + 'case "$-" in *i*) ;; *) [ -z "${PS1:-}" ] && return 0 ;; esac' \ + 'S6_SUID=/command/s6-setuidgid' \ + '[ -x "$S6_SUID" ] || return 0' \ + 'export _HERMES_DROP_TO_HERMES=1' \ + 'export HOME=/opt/data' \ + 'export OLARES_CLI_HOME="${OLARES_CLI_HOME:-/opt/data/.olares-cli}"' \ + 'export OLARES_CLI_DATA_DIR="${OLARES_CLI_DATA_DIR:-/opt/data/.olares-cli/data}"' \ + 'export HOMEBREW_PREFIX="${HOMEBREW_PREFIX:-/home/linuxbrew/.linuxbrew}"' \ + 'export HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE:-1}"' \ + 'export PATH="/opt/hermes/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/hermes/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' \ + 'DROP_SHELL=/bin/bash' \ + '[ -x "$DROP_SHELL" ] || DROP_SHELL=/bin/sh' \ + 'exec "$S6_SUID" hermes "$DROP_SHELL" -l' \ + > /cli-bin/drop-to-hermes + chmod 0755 /cli-bin/drop-to-hermes + + chown -R 1000:1000 /home/linuxbrew || true echo "[init-brew] done" resources: {} volumeMounts: @@ -138,12 +221,12 @@ spec: exit 0 fi mkdir -p /opt/data/skills - chown 10000:10000 /opt/data/skills || true + chown 1000:1000 /opt/data/skills || true for d in /skills-staging/*/; do name="$(basename "$d")" rm -rf "/opt/data/skills/$name" cp -a "$d" "/opt/data/skills/$name" - chown -R 10000:10000 "/opt/data/skills/$name" + chown -R 1000:1000 "/opt/data/skills/$name" done echo "[init-skills] Olares skills flattened into /opt/data/skills:" ls -1 /skills-staging @@ -290,12 +373,11 @@ spec: # HOME on /opt/data so HOME-respecting CLIs persist + share config. - name: HOME value: /opt/data - # uid/gid s6 maps the hermes user to and drops services to (image - # default 10000; matches the chown + hostPath ownership). + # uid/gid s6 maps the hermes user to (Olares platform default 1000). - name: HERMES_UID - value: "10000" + value: "1000" - name: HERMES_GID - value: "10000" + value: "1000" - name: HERMES_HOME value: /opt/data - name: HERMES_GATEWAY_RESTART_DELAY_SECONDS @@ -365,6 +447,10 @@ spec: name: cli-bin subPath: 02-reconcile-profiles readOnly: true + - mountPath: /etc/cont-init.d/04-fix-olares-cli-perms + name: cli-bin + subPath: 04-fix-olares-cli-perms + readOnly: true - mountPath: /dev/shm name: dshm {{- if eq (toString .Values.olaresEnv.ALLOW_HOME_DIR_ACCESS) "true" }} @@ -398,12 +484,11 @@ spec: env: - name: HOME value: /opt/data - # uid/gid s6 maps the hermes user to and drops services to (image - # default 10000; matches the chown + hostPath ownership). + # uid/gid s6 maps the hermes user to (Olares platform default 1000). - name: HERMES_UID - value: "10000" + value: "1000" - name: HERMES_GID - value: "10000" + value: "1000" - name: GATEWAY_HEALTH_URL value: "http://localhost:8642" # Match gateway PATH so dashboard-side `hermes ...` sees brew. @@ -458,6 +543,18 @@ spec: name: cli-bin subPath: 03-allow-dashboard-ws readOnly: true + - mountPath: /etc/cont-init.d/04-fix-olares-cli-perms + name: cli-bin + subPath: 04-fix-olares-cli-perms + readOnly: true + {{- if eq (toString .Values.olaresEnv.ALLOW_HOME_DIR_ACCESS) "true" }} + - mountPath: /home/userdata/home/ + name: olares-home-dir + {{- end }} + {{- if eq (toString .Values.olaresEnv.ALLOW_EXTERNAL_DIR_ACCESS) "true" }} + - mountPath: /home/userdata/external/ + name: olares-external-dir + {{- end }} securityContext: allowPrivilegeEscalation: false @@ -473,12 +570,11 @@ spec: value: xterm-256color - name: HOME value: /opt/data - # uid/gid s6 maps the hermes user to and drops services to (image - # default 10000; matches the chown + hostPath ownership). + # uid/gid s6 maps the hermes user to (Olares platform default 1000). - name: HERMES_UID - value: "10000" + value: "1000" - name: HERMES_GID - value: "10000" + value: "1000" - name: HERMES_HOME value: /opt/data - name: HOMEBREW_PREFIX @@ -491,6 +587,9 @@ spec: value: /opt/data/.olares-cli - name: OLARES_CLI_DATA_DIR value: /opt/data/.olares-cli/data + # dash reads $ENV before interactive input (kubectl exec sh). + - name: ENV + value: /etc/profile.d/99-drop-to-hermes.sh resources: limits: cpu: "2" @@ -515,6 +614,14 @@ spec: name: cli-bin subPath: 02-reconcile-profiles readOnly: true + - mountPath: /etc/profile.d/99-drop-to-hermes.sh + name: cli-bin + subPath: drop-to-hermes + readOnly: true + - mountPath: /etc/cont-init.d/04-fix-olares-cli-perms + name: cli-bin + subPath: 04-fix-olares-cli-perms + readOnly: true {{- if eq (toString .Values.olaresEnv.ALLOW_HOME_DIR_ACCESS) "true" }} - mountPath: /home/userdata/home/ name: olares-home-dir