You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three server-side additions that complete the "one key" SDK contract:
Discovery (§2.6d)
- `routes/discovery.ts` — GET /agentos/api/discovery (public, no auth).
Returns { version, endpoints: { ingest, api, otel, messages } } with
absolute URLs derived from the request origin (X-Forwarded-* honoured;
AGENTOS_PUBLIC_URL pins it behind a proxy). Endpoint paths live here only
— the single source of truth — so moving a route never forces an SDK release.
- Mounted in app.ts before the auth guards (OIDC .well-known pattern).
OTLP trace gateway
- `routes/otlp.ts` — POST /agentos/api/otel/v1/{traces,metrics,logs}.
Reads the raw request stream (no body parser) and forwards verbatim to
OTEL_GATEWAY_UPSTREAM_ENDPOINT with OTEL_GATEWAY_UPSTREAM_HEADERS. Binary
protobuf/gzip pass through untouched; mirrors upstream status. 503 when
upstream unset; 16 MB cap.
- `otel-auth.ts` — fail-closed cak_ guard (invalid/missing → 401, Mongo-down → 503).
- Mounted as a SERVICE boundary before the global json parser.
cak_ ingest auth refactor
- `cak-bearer.ts` — shared `verifyCakBearer()` helper used by both
ingest-auth and otel-auth (DRY, single validation path).
- `ingest-auth.ts` — refactored to use the shared helper; behaviour unchanged.
Tests: 164 pass (21 files), typecheck clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+27-8Lines changed: 27 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -105,10 +105,10 @@ The Mongo cluster is the source of truth for AgentOS. **Only the `agentos-server
105
105
Resources stamped with `ownerGroup`/`ownerUser` are **hard-isolated**: a non-admin sees only their own or their group's; admins (`*`) see all (§2.6b).
106
106
107
107
**Credentials required:**
108
-
- On the **SDK** side: `AGENTOS_INGEST_URL` (e.g. `https://<host>/agentos/api/ingest/events`) + optional `AGENTOS_INGEST_TOKEN` (sent as `Authorization: Bearer …`). No Mongo creds.
108
+
- On the **SDK** side: **`AGENTOS_DISCOVERY_URL`** (e.g. `https://<host>/agentos/api/discovery`) + the `cak_` key (`COMPUTERAGENT_HARNESS_TOKEN`). The SDK reads the ingest URL (and api/otel) from the discovery document — no endpoint path is baked into the SDK (§2.6d). A full-URL `AGENTOS_INGEST_URL` override still wins for the ingest endpoint. No Mongo creds.
109
109
- On the **server** side: `MONGO_URL` + `MONGO_DATABASE` (this is the DB the collections above live in).
110
110
111
-
**Behaviour:** when `AGENTOS_INGEST_URL` is set, the SDK's default telemetry pipeline auto-attaches `AgentOSHttpSink` (gated on the `[agentos]` extra, which is now `httpx`-based). Each event carries a stable `event_id` so the server's writes are idempotent on retry. **Ingest auth** (`ingest-auth.ts`): the SDK presents the **same `cak_` API key it uses everywhere** as the ingest `Bearer`, and the server validates it via `apiKeyStore.verify` (the same path the CAS introspection uses). A legacy static `AGENTOS_INGEST_TOKEN` string is still accepted for back-compat. ⚠️ Only when **no `cak_` is presented AND `AGENTOS_INGEST_TOKEN` is unset** does the route fall **open** (anonymous writes) — present a key (or set the token) on any network-exposed deployment. A presented `cak_` is always validated (invalid → 401, Mongo-down → 503), never waved through.
111
+
**Behaviour:** when an ingest URL resolves (from `AGENTOS_DISCOVERY_URL` or an `AGENTOS_INGEST_URL` override), the SDK's default telemetry pipeline auto-attaches `AgentOSHttpSink` (gated on the `[agentos]` extra, which is now `httpx`-based). Each event carries a stable `event_id` so the server's writes are idempotent on retry. **Ingest auth** (`ingest-auth.ts`): the SDK presents the **same `cak_` API key it uses everywhere** as the ingest `Bearer`, and the server validates it via `apiKeyStore.verify` (the same path the CAS introspection uses). A legacy static `AGENTOS_INGEST_TOKEN` string is still accepted for back-compat. ⚠️ Only when **no `cak_` is presented AND `AGENTOS_INGEST_TOKEN` is unset** does the route fall **open** (anonymous writes) — present a key (or set the token) on any network-exposed deployment. A presented `cak_` is always validated (invalid → 401, Mongo-down → 503), never waved through.
112
112
113
113
---
114
114
@@ -147,7 +147,20 @@ Resources stamped with `ownerGroup`/`ownerUser` are **hard-isolated**: a non-adm
147
147
148
148
**Required env:**
149
149
- Server: `AGENTOS_CREDENTIALS_KEY` (base64 of 32 random bytes; **fail-closed** — credentials CRUD/resolve 503 without it). Optional `AGENTOS_CREDENTIALS_KEY_OLD` for rotation.
150
-
- SDK: `AGENTOS_API_URL` (e.g. `https://<host>/agentos/api/v1`) + the same `cak_` key it already uses (`COMPUTERAGENT_HARNESS_TOKEN` / `AGENTOS_INGEST_TOKEN`). The key's role must include `git-credentials:read`.
150
+
- SDK: `AGENTOS_DISCOVERY_URL` (the SDK reads the api endpoint from it; `AGENTOS_API_URL` overrides) + the same `cak_` key it already uses (`COMPUTERAGENT_HARNESS_TOKEN`). The key's role must include `git-credentials:read`.
> So the SDK never hardcodes an endpoint path: change a route server-side and existing SDKs follow without a release. The OIDC `.well-known` pattern. Code: `routes/discovery.ts` (server), `computeragent/agentos.py` (SDK).
157
+
158
+
-**Server.**`GET /agentos/api/discovery` — **public** (URLs only, no secrets), mounted before the auth guards (`app.ts`). Returns `{ version, endpoints: { ingest, api, otel, messages } }` with **absolute** URLs built from the request origin (honours `X-Forwarded-Proto`/`-Host`; pin with `AGENTOS_PUBLIC_URL`). The endpoint **paths live here only** — the single source of truth — kept in sync with the `app.ts`/`dashboard.ts` mounts.
159
+
-**SDK.** A consumer sets just **`AGENTOS_DISCOVERY_URL`** (the full discovery URL) + the `cak_` key. `agentos.py` GETs the document once (memoized) and resolves ingest / api / otel from it — reading the **absolute URLs verbatim**, never constructing a path. Resolution order per endpoint: explicit full-URL override env (`AGENTOS_INGEST_URL`/`AGENTOS_API_URL`/`AGENTOS_OTEL_URL`) → discovery → unconfigured (no baked fallback). The remote-harness URL is **not** discovered (separate service; `harness_url=` / `COMPUTERAGENT_HARNESS_URL`).
160
+
161
+
**Required env:**
162
+
- Server: none (derives the origin from the request; optional `AGENTOS_PUBLIC_URL` to pin it behind a proxy).
163
+
- SDK: `AGENTOS_DISCOVERY_URL` + `COMPUTERAGENT_HARNESS_TOKEN` (the `cak_`).
0 commit comments