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
{{ message }}
Repository navigation
Commit 6231b73
Browse filesBrowse the repository at this point in the historyBrowse files
fix(auth): give a key configured without a key_id the same id on every load
A key whose configuration carries no key_id -- every key from
AGENTFLOW_API_KEYS, and a key-file entry without one -- drew a random id
from generate_key_id on every load. A key-file entry kept its id only when
load() could write it back, and docker-compose.prod.yml mounts the key file
read-only, over a config/api_keys.yaml whose two entries carry no key_id.
The id names the key's Redis bucket, its api_usage rows and the admin views
keyed by id: replicas sharing Redis each kept their own bucket for the same
key (N replicas, N times its rpm), and every restart and reload started a
fresh bucket and split its usage history.
ensure_key_ids now derives the id -- <tenant>-<name>-<8 hex of the entry's
peppered lookup digest>, from its stored key_lookup or compute_key_lookup
over its plaintext -- and _legacy_env_keys runs environment keys through
it. A clash lengthens the digest prefix, so ids stay unique and stable. A
new pepper changes only an id derived from plaintext and never written back
-- every environment key, and a plaintext entry of a key file the process
cannot write; an entry with a stored key_lookup, and a derived id already
written to a writable key file, keep theirs. A legacy hash-only entry has
nothing to derive from and keeps a random id; generate_key_id and
create_key are unchanged.
tests/unit/test_auth_key_identity.py takes each scenario of
docs/specs/api-key-identity.md (nine of its twelve tests fail against the
code before this change), with false-reject controls that load the shipped
key file and a persisted id beside a hash-only entry. The new key_rotation
helpers are killed from test_key_rotation_mutation.py, the file the
mutation gate runs; its one test that pinned a random id for entries with a
plaintext key now builds hash-only entries, the case that keeps one. The
CHANGELOG's ten LF-only lines are now CRLF like the rest of the file.
docs/architecture.md and the reload requirement of
docs/specs/api-key-rate-limiting.md now name the one key a reload still
cannot keep: a legacy hash-only entry in a key file the process cannot
write, whose random id -- and so its bucket and window -- changes on every
load. docs/specs/api-key-identity.md already specified that id.
Reviewed by opus-cli, the writer's own engine: glm-5.3 was rate-limited
until 2026-09-14 and codex until 2026-10-05.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHUBaNNPWihtsgeFWnRmaS
-`uv lock --upgrade-package nltk` only; nltk is a transitive dependency of `llama-index-core` and is not part of the `cloud`/`postgres` export, so `requirements-docker.lock` is unchanged. Closes the critical (JVM argument injection in the Stanford wrappers) and high (uncontrolled `dot` search path) advisories GitHub reported on the default branch on 2026-09-01.
Copy file name to clipboardExpand all lines: docs/architecture.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -134,7 +134,7 @@ See [Architecture Decision Records](decisions/) for detailed trade-off analysis.
134
134
## Security
135
135
136
136
### Implemented
137
-
-**API authentication**: API key via `X-API-Key` header (set `AGENTFLOW_API_KEYS` env var). Requirements for a key's id: [API key identity](specs/api-key-identity.md)
137
+
-**API authentication**: API key via `X-API-Key` header (set `AGENTFLOW_API_KEYS` env var). A key configured without a `key_id` (every environment key, and a key-file entry without one) gets an id derived from its key-lookup digest, stable across reloads, restarts and replicas (except a legacy hash-only entry, with neither a plaintext key nor a `key_lookup`: it has nothing to derive from and keeps a random id, which in a key file the process cannot write changes on every load); changing the pepper changes only an id derived from a plaintext key and never written back (every environment key, and a plaintext key-file entry in a file the process cannot write), while a writable key file keeps the id written to it on the first load and an entry with a stored `key_lookup` keeps the id derived from that digest. Requirements for a key's id: [API key identity](specs/api-key-identity.md)
138
138
-**Transport gate (audit P2-3)**: `AGENTFLOW_PROFILE=production` refuses to boot over plaintext transport to an external ClickHouse/Redis/PostgreSQL (loopback exempt; deliberate exceptions named in `AGENTFLOW_INSECURE_TRANSPORT_OK`), and refuses a wildcard CORS origin outside demo mode. The ClickHouse client supports HTTPS with hostname verification and a private-CA bundle (`CLICKHOUSE_SECURE`, `CLICKHOUSE_CA_CERT`)
139
139
-**Rate limiting**: Per-key sliding window with Redis backing when available and in-memory fallback for local/test, configurable via `AGENTFLOW_RATE_LIMIT_RPM` (default: 120/min). Requirements: [API key rate limiting](specs/api-key-rate-limiting.md)
0 commit comments