Add an optional auth-token (bearer) field and a custom-headers textarea to
the MCP 'Add server' pane. URL-mode servers are now registered by writing
hermes config directly via the venv's config helpers (save_env_value +
save_config) instead of shelling into the interactive, network-probing
'hermes mcp add --url' flow that hung/504'd on auth challenges.
- Token is stored in ~/.hermes/.env (mode 600) and referenced in config.yaml
as 'Authorization: Bearer ${MCP_<NAME>_API_KEY}' — never plaintext config.
- Registration is non-blocking: no live probe, so a slow/unreachable server
can't hang the request.
- Add a per-server 'Test' button (POST /api/mcp/test -> hermes mcp test).
- Contract tests for the new fields, payload, no-probe path, and test route.
- Fix payload field names (snake_case → camelCase) so creates/updates
actually reach the server correctly
- Fix reveal dialog not opening after create/rotate (plain_key → plaintextKey)
- Add GET /api/admin/api-users/:id so the edit button loads existing data
- Show server errors inline in the dialog instead of silently succeeding
- Add 30d/90d/1y/Never expiration preset buttons
- Default new keys to pre+post access, 60 rpm, 1M monthly tokens
- Surface errors on revoke, reactivate, rotate, and delete actions
- Add client-side validation for required numeric fields
- Add contract tests covering all the above fixes
- Ports now bind to HERMES_PUBLISHED_BIND_IP (default 127.0.0.1) so
NPM on the same host proxies to 127.0.0.1:7843/8645/8646 and direct
LAN/internet access is blocked without firewall rules
- runHermes: settle promise immediately on timeout (SIGKILL) instead of
waiting for close event — prevents hanging when hermes spawns children
that keep stdout/stderr open after the parent is killed
- Add HERMES_ADMIN_COOKIE_SECURE env var to set Secure flag on admin
session cookie when the admin UI is served over HTTPS
- Document NPM deployment shapes in README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without timeouts, a postgres connection or query that hangs causes the
entire authenticated request to hang indefinitely, making the reverse
proxy return 502. Now fails fast at 5s connect / 10s query.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents /api/status from holding a response for 30s when the hermes
binary is absent or stalling, which caused reverse proxies to 502.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The hardcoded file list missed any file not named authEmma/authMom.
Now reads the directory and derives hints from the filename suffix
(authZach.json → hint "zach"; auth.json → ["main","default"]) so
the hints-based matching still wins over Hermes auth label matching.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
serveStatic looked for a file literally named "login" — adding the same
extensionless → .html mapping that / → index.html already has.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On first deploy postgres must initialize the data directory before it
can accept connections. 10s start_period was too tight; bumped to 30s
with 10 retries to give it enough runway on slower hosts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
node:20-bookworm-slim ships with a node user at UID 1000; useradd fails
with exit 4 when the UID is already taken. Use usermod/groupmod to
rename the existing node user/group to hermes instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Embed a postgres:16-alpine service so operators don't need an external
database. DATABASE_URL is now constructed internally via a YAML anchor
from POSTGRES_PASSWORD (default: hermes-change-me). Removed the manual
PostgreSQL setup section from README and updated backup instructions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents hanging connections when the upstream response stream errors
after headers have already been sent to the client.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the 3-service compose with a 5-service architecture that puts
api-gateway.cjs (hermes-pre-api, hermes-post-api) in front of internal
upstream services (hermes-pre-upstream, hermes-post-upstream), ensuring
all public API traffic passes through the auth/audit layer. Update
Dockerfile, .env.example, .dockerignore, and add a compose contract test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds §21 API Users pane with full CRUD, key rotation, log download, revoke/reactivate, and one-time key reveal dialog. Includes static UI contract test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements api-gateway.cjs — a standalone HTTP server that authenticates
API keys, enforces rate/token limits, records usage events, and proxies
requests to an internal upstream (pre or post route). Adds integration
tests covering auth failures, rate limiting, non-streaming, SSE streaming,
and upstream connection errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements authorizeUsage (rate limit + monthly token limit with FOR UPDATE locking), beginUsageEvent, completeUsageEvent, failUsageEvent, streamJsonlLogs, and cleanupExpiredMessageLogs in lib/audit-store.cjs, with integration tests in test/audit.integration.test.cjs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements lib/api-users-store.cjs with full CRUD + auth, 7 admin REST
endpoints in server.cjs, and integration tests for all store functions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional admin auth (enabled when DATABASE_URL is set) with
session-cookie login, logout, requireAdmin middleware, login UI,
and a skippable integration test (TEST_DATABASE_URL required).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>