hermes: load tool credentials before s6
This commit is contained in:
parent
f7492defdd
commit
846c890527
@ -255,26 +255,6 @@ spec:
|
||||
resources:
|
||||
requests: {cpu: 25m, memory: 64Mi}
|
||||
limits: {cpu: 250m, memory: 256Mi}
|
||||
- name: patch-main-wrapper
|
||||
image: registry.bstein.dev/bstein/hermes-agent@sha256:81970563e542f0720773e72297810b3a844b83e381e278f25c0916c78d930107
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- /opt/hermes/.venv/bin/python
|
||||
- /opt/coordinator/patch_main_wrapper.py
|
||||
- /opt/hermes/docker/main-wrapper.sh
|
||||
- /patched/main-wrapper.sh
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsUser: 10000
|
||||
runAsGroup: 10000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
volumeMounts:
|
||||
- {name: coordinator, mountPath: /opt/coordinator, readOnly: true}
|
||||
- {name: main-wrapper-patch, mountPath: /patched}
|
||||
resources:
|
||||
requests: {cpu: 25m, memory: 32Mi}
|
||||
limits: {cpu: 100m, memory: 64Mi}
|
||||
- name: patch-auth
|
||||
image: registry.bstein.dev/bstein/hermes-agent@sha256:81970563e542f0720773e72297810b3a844b83e381e278f25c0916c78d930107
|
||||
imagePullPolicy: IfNotPresent
|
||||
@ -476,8 +456,13 @@ spec:
|
||||
- name: hermes
|
||||
image: registry.bstein.dev/bstein/hermes-agent@sha256:81970563e542f0720773e72297810b3a844b83e381e278f25c0916c78d930107
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: [/init, /opt/hermes/docker/main-wrapper.sh]
|
||||
args: [gateway, run]
|
||||
command: [/bin/sh, -ec]
|
||||
args:
|
||||
- |
|
||||
set -a
|
||||
. /opt/data/.env
|
||||
set +a
|
||||
exec /init /opt/hermes/docker/main-wrapper.sh gateway run
|
||||
ports:
|
||||
- {name: api, containerPort: 8642, protocol: TCP}
|
||||
- {name: dashboard, containerPort: 9119, protocol: TCP}
|
||||
@ -512,7 +497,6 @@ spec:
|
||||
- {name: home, mountPath: /opt/data}
|
||||
- {name: provider-auth, mountPath: /shared-auth}
|
||||
- {name: coordinator, mountPath: /opt/coordinator, readOnly: true}
|
||||
- {name: main-wrapper-patch, mountPath: /opt/hermes/docker/main-wrapper.sh, subPath: main-wrapper.sh, readOnly: true}
|
||||
- {name: auth-patch, mountPath: /opt/hermes/hermes_cli/auth.py, subPath: auth.py}
|
||||
- {name: codex-runtime-patch, mountPath: /opt/hermes/hermes_cli/runtime_provider.py, subPath: runtime_provider.py}
|
||||
- {name: codex-runtime-patch, mountPath: /opt/hermes/agent/transports/codex_app_server_session.py, subPath: codex_app_server_session.py}
|
||||
@ -962,8 +946,6 @@ spec:
|
||||
defaultMode: 0444
|
||||
- name: auth-patch
|
||||
emptyDir: {}
|
||||
- name: main-wrapper-patch
|
||||
emptyDir: {}
|
||||
- name: tui-gateway-patch
|
||||
emptyDir: {}
|
||||
- name: api-server-patch
|
||||
|
||||
@ -76,7 +76,6 @@ configMapGenerator:
|
||||
- migrate_api_session_lineage.py=scripts/migrate_api_session_lineage.py
|
||||
- patch_api_server_sessions.py=scripts/patch_api_server_sessions.py
|
||||
- patch_hermes_auth.py=scripts/patch_hermes_auth.py
|
||||
- patch_main_wrapper.py=scripts/patch_main_wrapper.py
|
||||
- patch_codex_runtime.py=scripts/patch_codex_runtime.py
|
||||
- patch_stream_recovery.py=scripts/patch_stream_recovery.py
|
||||
- patch_tui_gateway.py=scripts/patch_tui_gateway.py
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Load the Vault-derived tool environment in Hermes's main gateway."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
BEFORE = """# HOME comes through with-contenv as /root (the /init context). Override
|
||||
"""
|
||||
AFTER = """# The init container writes Vault-derived tool credentials here. Load them
|
||||
# after with-contenv restores the container environment so dashboard-spawned
|
||||
# terminal tools receive the same Git identity as durable CLI workers.
|
||||
if [ -r /opt/data/.env ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
. /opt/data/.env
|
||||
set +a
|
||||
fi
|
||||
|
||||
# HOME comes through with-contenv as /root (the /init context). Override
|
||||
"""
|
||||
|
||||
|
||||
def patch(source: Path, destination: Path) -> None:
|
||||
"""Apply the narrow environment load and fail on upstream drift."""
|
||||
content = source.read_text(encoding="utf-8")
|
||||
if BEFORE not in content:
|
||||
raise RuntimeError("Hermes main-wrapper patch context changed")
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
destination.write_text(content.replace(BEFORE, AFTER, 1), encoding="utf-8")
|
||||
shutil.copymode(source, destination)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Patch the wrapper path supplied by the deployment init container."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("source", type=Path)
|
||||
parser.add_argument("destination", type=Path)
|
||||
args = parser.parse_args()
|
||||
patch(args.source, args.destination)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@ -639,8 +639,10 @@ def test_agent_root_is_stock_dashboard_and_terminal_is_a_separate_path():
|
||||
|
||||
assert "dashboard" not in containers
|
||||
hermes = containers["hermes"]
|
||||
assert hermes["command"] == ["/init", "/opt/hermes/docker/main-wrapper.sh"]
|
||||
assert hermes["args"] == ["gateway", "run"]
|
||||
assert hermes["command"] == ["/bin/sh", "-ec"]
|
||||
startup = hermes["args"][0]
|
||||
assert ". /opt/data/.env" in startup
|
||||
assert "exec /init /opt/hermes/docker/main-wrapper.sh gateway run" in startup
|
||||
hermes_env = {item["name"]: item["value"] for item in hermes["env"]}
|
||||
assert hermes_env["HERMES_DASHBOARD"] == "1"
|
||||
assert hermes_env["HERMES_DASHBOARD_HOST"] == "127.0.0.1"
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
"""Hermes gateway tool-environment patch and manifest tests."""
|
||||
"""Hermes gateway tool-environment and recovery manifest tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
@ -11,46 +9,20 @@ import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
HERMES = ROOT / "services/hermes"
|
||||
SCRIPT = HERMES / "scripts/patch_main_wrapper.py"
|
||||
|
||||
|
||||
def _patch_module():
|
||||
spec = importlib.util.spec_from_file_location("patch_main_wrapper", SCRIPT)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def _deployment() -> dict:
|
||||
return yaml.safe_load((HERMES / "agent-deployment.yaml").read_text())
|
||||
|
||||
|
||||
def test_wrapper_loads_tool_environment_after_s6_restore(tmp_path: Path) -> None:
|
||||
module = _patch_module()
|
||||
source = tmp_path / "main-wrapper.sh"
|
||||
destination = tmp_path / "patched.sh"
|
||||
source.write_text("#!/bin/sh\n" + module.BEFORE + "export HOME=/opt/data\n")
|
||||
source.chmod(0o755)
|
||||
|
||||
module.patch(source, destination)
|
||||
|
||||
patched = destination.read_text()
|
||||
assert ". /opt/data/.env" in patched
|
||||
assert patched.index(". /opt/data/.env") < patched.index("export HOME=/opt/data")
|
||||
assert destination.stat().st_mode & stat.S_IXUSR
|
||||
|
||||
|
||||
def test_gateway_retains_stock_entrypoint_with_patched_wrapper() -> None:
|
||||
def test_gateway_loads_tool_environment_before_s6_entrypoint() -> None:
|
||||
pod = _deployment()["spec"]["template"]["spec"]
|
||||
init = {item["name"]: item for item in pod["initContainers"]}
|
||||
containers = {item["name"]: item for item in pod["containers"]}
|
||||
|
||||
assert "repair-cassandra-kanban" in init
|
||||
assert "patch-main-wrapper" in init
|
||||
assert containers["hermes"]["command"] == [
|
||||
"/init",
|
||||
"/opt/hermes/docker/main-wrapper.sh",
|
||||
]
|
||||
mounts = {item["name"]: item for item in containers["hermes"]["volumeMounts"]}
|
||||
assert mounts["main-wrapper-patch"]["subPath"] == "main-wrapper.sh"
|
||||
hermes = containers["hermes"]
|
||||
assert hermes["command"] == ["/bin/sh", "-ec"]
|
||||
startup = hermes["args"][0]
|
||||
assert startup.index(". /opt/data/.env") < startup.index("exec /init")
|
||||
assert "exec /init /opt/hermes/docker/main-wrapper.sh gateway run" in startup
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user