mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-09 13:21:42 +00:00
fix(secrets): make 1Password bootstrap token reliable outside systemd
The 1Password secret source resolves op:// references using OP_SERVICE_ACCOUNT_TOKEN read from os.environ. Under systemd the gateway gets that token via EnvironmentFile, but cron jobs, subprocesses, CLI runs, macOS launchd, and Docker containers spawn fresh interpreters with no inherited shell state — so they silently failed to resolve any reference and fell back to empty strings. Two patches close the gap, matching Bitwarden's reliability guarantees: 1. env_loader: auto-load ~/.hermes/.op.env after .env so the gitignored bootstrap token is available everywhere. override=False plus an explicit guard ensure it never clobbers a token already in env (e.g. from a systemd EnvironmentFile, which keeps precedence). 2. credential_pool: _get_env_prefer_dotenv() now prefers the resolved value in os.environ when .env still holds a raw op:// reference, instead of handing a URL to provider auth. Non-op:// values keep the existing .env-takes-precedence behaviour. Also gitignore .op.env, document the three bootstrap-token options, and add tests covering auto-load, no-override, and the resolved-vs-raw precedence (plus regression guards). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2dc4286e00
commit
8a76de962f
5 changed files with 220 additions and 2 deletions
|
|
@ -18,6 +18,32 @@ Hermes never authenticates on your behalf and never downloads `op`: it shells ou
|
|||
- **Service accounts** (recommended for servers/CI): create a service account in 1Password, grant it read access to the relevant vault, and export its token as `OP_SERVICE_ACCOUNT_TOKEN` in `~/.hermes/.env`. The token is the credential — treat it like any other bearer token.
|
||||
- **Desktop / interactive sessions** (laptops): run `op signin` (or enable CLI integration in the 1Password app). Hermes passes your `OP_SESSION_*` variables through to the `op` child process. The 1Password cache key includes those session variables, so signing into a different account never serves a value cached under the previous identity.
|
||||
|
||||
## Bootstrap token
|
||||
|
||||
When you authenticate with a **service-account token**, that token is itself the bootstrap credential Hermes needs *before* it can resolve any `op://` reference. It must be present in `os.environ` of every process that resolves secrets — including cron jobs (`kanban.dispatch_in_gateway: false`), subprocess invocations, CLI runs, macOS launchd agents, and Docker containers — not just the interactive gateway. There are three ways to make it available, in order of precedence:
|
||||
|
||||
1. **In `~/.hermes/.env` (recommended).** `hermes secrets onepassword setup --token <token>` writes the token to `~/.hermes/.env`, exactly like Bitwarden's `BWS_ACCESS_TOKEN`. Because `load_hermes_dotenv()` always loads `.env`, the token is available everywhere with zero extra setup. This is the simplest reliable option.
|
||||
|
||||
2. **In `~/.hermes/.op.env` (gitignored).** If you'd rather keep the service-account token out of `.env` — for example so `.env` can be checked into a private dotfiles repo while the token stays out of version control — place it in `~/.hermes/.op.env`:
|
||||
|
||||
```bash
|
||||
echo 'OP_SERVICE_ACCOUNT_TOKEN=ops_...' > ~/.hermes/.op.env
|
||||
chmod 600 ~/.hermes/.op.env
|
||||
```
|
||||
|
||||
Hermes auto-loads `.op.env` at startup, **after** `.env`, and **never** overrides a token already present in the environment. `.op.env` is gitignored so the token never enters a committed file.
|
||||
|
||||
3. **Via systemd `EnvironmentFile` (Linux gateway).** If you run the gateway under systemd, you can inject the token directly into the service environment:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
EnvironmentFile=-/home/youruser/.hermes/.op.env
|
||||
```
|
||||
|
||||
A token injected this way takes precedence — Hermes detects that `OP_SERVICE_ACCOUNT_TOKEN` is already set and skips loading `.op.env` entirely.
|
||||
|
||||
If the token is reachable only through an interactive shell (`op signin`, `OP_SESSION_*` exports in `.bashrc`, etc.), it will **not** be inherited by cron jobs or freshly spawned subprocesses, and those contexts will log a warning and fall back to whatever credentials `.env` already held. Use one of the three options above for any non-interactive workload.
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Install and sign in to `op`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue