Skip to content

Commit 69c8656

Browse files
SiarheiFedziukovichclaude
andcommitted
docs(dial-unified-config-lite): sync file-config surface with U.4 keys deny-all
The lite docs still described the pre-U.4 security-admin tier gating file-sourced keys; U.4 retired that tier and denies type=keys for every caller including admin. Also document the names-only stub shape of the file-config list endpoint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 690b5b8 commit 69c8656

3 files changed

Lines changed: 5 additions & 5 deletions

File tree

docs/sandbox/dial-unified-config-lite/02-architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Cross-replica freshness is delivered in two layers:
6666

6767
Per-entity validation runs on each rebuild. The default is **strict abort** (matching today's `FileConfigStore` reload semantics); an opt-in `config.reload.onInvalidEntity: skip` switches to per-entity skip-with-visibility, so a single corrupt blob doesn't block scale-up. The same posture applies to writes: cross-references that don't resolve **block the write with `422`** by default; an opt-in `config.write.softValidation: true` accepts dangling references and surfaces them via `status: "invalid"` for gradual file→API migration. "No broken entities accepted" is the headline contract across both paths.
6868

69-
**Operator surface vs runtime resolution.** The union lives in the runtime `Config` for chat-completion routing — `findDeployment`, `RateLimiter`, the route matcher, and the interceptor chain resolver all keep using both simple-name (file) and canonical-ID (API) keys. The Configuration API operator surface is **not** the union: per-entity GET (`/v1/{type}/{bucket}/{name}`) and metadata listing (`/v1/metadata/...`) are blob-only — file entries do not appear on either. Operators inspect file entries via a dedicated read-only path, `/v1/admin/config/file/{type}[/{name}]`, with the security-admin role gating the `keys` type because file `Config.keys` map keys equal secrets (see [`04-security.md`](04-security.md)). Splitting the surface this way keeps the operator-facing API clean (one source per endpoint, no per-entity `source` field to disambiguate, no name-collision corner cases like file `gpt-4` vs API `models/public/gpt-4`) while runtime resolution remains untouched.
69+
**Operator surface vs runtime resolution.** The union lives in the runtime `Config` for chat-completion routing — `findDeployment`, `RateLimiter`, the route matcher, and the interceptor chain resolver all keep using both simple-name (file) and canonical-ID (API) keys. The Configuration API operator surface is **not** the union: per-entity GET (`/v1/{type}/{bucket}/{name}`) and metadata listing (`/v1/metadata/...`) are blob-only — file entries do not appear on either. Operators inspect file entries via a dedicated read-only path, `/v1/admin/config/file/{type}[/{name}]`, with the `keys` type denied for every caller (admin included) because file `Config.keys` map keys equal secrets — slice U.4 retired the security-admin tier that previously gated it (see [`04-security.md`](04-security.md)). Splitting the surface this way keeps the operator-facing API clean (one source per endpoint, no per-entity `source` field to disambiguate, no name-collision corner cases like file `gpt-4` vs API `models/public/gpt-4`) while runtime resolution remains untouched.
7070

7171
## Bucket strategy: `public/` vs `platform/`
7272

docs/sandbox/dial-unified-config-lite/03-api.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Aligned with the existing Resource API since launch: one `PUT` upsert at the sin
4949

5050
A typo on `PUT … If-None-Match: *` (entity exists) or on `DELETE` (entity missing) surfaces as a clean structured error instead of a silent stub creation. Bulk upsert lives only on `POST /v1/admin/apply` — that is the canonical declarative path.
5151

52-
The singleton `/v1/settings/platform/global` follows the same shape and the same blob-only rule as every other per-entity endpoint. `PUT` is upsert — sets or replaces the API blob. `GET` returns the blob if present, `404` otherwise. `DELETE` clears the blob (idempotent — `204` whether or not a blob was present). `POST` returns `405` with `Allow: GET, PUT, DELETE`. On the metadata route (`GET /v1/metadata/settings/platform/`) the controller is read-only — `POST` / `PUT` / `DELETE` there return `405` with `Allow: GET`. File-defined fields and schema defaults for the singleton are inspected via `/v1/admin/config/file/settings/global` (admin-gated — settings carries no secrets, so the security-admin carve-out for `keys` does not apply).
52+
The singleton `/v1/settings/platform/global` follows the same shape and the same blob-only rule as every other per-entity endpoint. `PUT` is upsert — sets or replaces the API blob. `GET` returns the blob if present, `404` otherwise. `DELETE` clears the blob (idempotent — `204` whether or not a blob was present). `POST` returns `405` with `Allow: GET, PUT, DELETE`. On the metadata route (`GET /v1/metadata/settings/platform/`) the controller is read-only — `POST` / `PUT` / `DELETE` there return `405` with `Allow: GET`. File-defined fields and schema defaults for the singleton are inspected via `/v1/admin/config/file/settings/global` (admin-gated — settings carries no secrets, so the deny-all carve-out for `keys` does not apply).
5353

5454
## Operator endpoints (`/v1/admin/*`)
5555

@@ -58,14 +58,14 @@ POST /v1/admin/apply # apply a set of resource manifes
5858
POST /v1/admin/validate # validate manifests without applying
5959
GET /v1/admin/schema/{type} # JSON Schema for an entity type
6060
GET /v1/admin/health/config # status: ok | degraded + skipped[]
61-
GET /v1/admin/config/file/{type} # list file-sourced entries (admin; security-admin for type=keys)
61+
GET /v1/admin/config/file/{type} # list file-sourced entry names (admin; type=keys denied for all)
6262
GET /v1/admin/config/file/{type}/{name} # get single file-sourced entry (same gating)
6363
GET /v1/admin/audit # Phase 7 — deferred
6464
# GET /v1/admin/export # deferred — Defer.1 (design preserved)
6565
# GET /v1/admin/export?type=models # deferred — Defer.1
6666
```
6767

68-
`/v1/admin/config/file/*` is the operator-facing read-only surface for file-sourced entries. File entries are no longer addressable on the per-entity Configuration API (`/v1/{type}/{bucket}/{name}`) — that surface is blob-only, symmetric with the metadata listings. Admin gates every type **except** `keys`, which requires the existing security-admin tier (the same role that gates `?reveal_secrets=true` for plaintext secret reads — see [`04-security.md`](04-security.md)). The carve-out exists because file-sourced `Config.keys` keeps the legacy map-key-as-secret format per OQ-12, so leaking even the *names* of file keys via URL or listing would expose secrets to anyone with the admin role; security-admin is the operator-vetted tier we already use for similar exposure. No `PUT` / `DELETE` — file remains operator-managed via `aidial.config.json`.
68+
`/v1/admin/config/file/*` is the operator-facing read-only surface for file-sourced entries. File entries are no longer addressable on the per-entity Configuration API (`/v1/{type}/{bucket}/{name}`) — that surface is blob-only, symmetric with the metadata listings. The list form returns a names-only stub listing (`{"items": [{"name": "…"}]}`) — no entity bodies and no `ResourceItemMetadata` fields (file entries carry no blob, so there is no `etag` / timestamps / `author`); the full entity body is returned only by the single-entry GET. Admin gates every type **except** `keys`, which is **denied for every caller including admin** — slice U.4 retired the security-admin tier along with the `?reveal_secrets=true` flow (see [`04-security.md`](04-security.md)). The carve-out exists because file-sourced `Config.keys` keeps the legacy map-key-as-secret format per OQ-12, so leaking even the *names* of file keys via URL or listing would expose secrets; operators with strict need read `aidial.config.json` directly off the deployment. No `PUT` / `DELETE` — file remains operator-managed via `aidial.config.json`.
6969

7070
`export` was originally the single source of truth for runtime state — it returns the effective merged config DIAL Core is actually serving (file + API entries). **Deferred from MVP at core-team request 2026-05-20** — see `../dial-unified-config/IMPLEMENTATION.md` §5.5 Defer.1; design preserved. Until it ships, operators consult `aidial.config.json` directly for file-sourced entries. `health/config` exposes invalid-entity skip state separately from the unauthenticated Kubernetes `/health` liveness probe, which is unchanged.
7171

docs/sandbox/dial-unified-config-lite/06-rollout.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Phase 1 ships the **read-only Configuration API plus CLI read commands** (`get`
1616

1717
| Audience | What changes |
1818
|---|---|
19-
| **DevOps teams** | A first-class CLI replaces hand-edited JSON + Helm push. `dial-cli apply -f` with dry-run and validation lands in Phase 4; reads (`get` / `diff`) land in Phase 1 and are already useful in isolation (`export` deferred — see `../dial-unified-config/IMPLEMENTATION.md` §5.5 Defer.1). Per-entity reads target blob-sourced entries only; file-sourced entries are inspected via a separate read-only `/v1/admin/config/file/*` path — admin role for most types, security-admin for `keys` (file map keys equal secrets per OQ-12). CLI integration on top of that path is post-MVP. Per-entity promotion (`<type> promote --from … --to …`) lands in Phase 2 for models and Phase 3 for other types; full-environment declarative promotion via `apply -f` lands in Phase 4 — no more per-field manual substitution. CI/CD pipelines start using API calls with deterministic exit codes instead of polling the file-watcher. |
19+
| **DevOps teams** | A first-class CLI replaces hand-edited JSON + Helm push. `dial-cli apply -f` with dry-run and validation lands in Phase 4; reads (`get` / `diff`) land in Phase 1 and are already useful in isolation (`export` deferred — see `../dial-unified-config/IMPLEMENTATION.md` §5.5 Defer.1). Per-entity reads target blob-sourced entries only; file-sourced entries are inspected via a separate read-only `/v1/admin/config/file/*` path — admin role for most types, `keys` denied for every caller (file map keys equal secrets per OQ-12; slice U.4 retired the security-admin tier). CLI integration on top of that path is post-MVP. Per-entity promotion (`<type> promote --from … --to …`) lands in Phase 2 for models and Phase 3 for other types; full-environment declarative promotion via `apply -f` lands in Phase 4 — no more per-field manual substitution. CI/CD pipelines start using API calls with deterministic exit codes instead of polling the file-watcher. |
2020
| **DIAL Admin Backend operators** | Phase 5 migrates the Admin Backend to consume the Configuration API. End-to-end propagation drops from 60–180 s to immediate on the writer pod, ≤ 60 s cross-replica (or near-instant after Phase 1.5). The Admin UI will be updated to use the new Configuration API. |
2121
| **DIAL Core deployment** | New resource types in `ResourceService`. One additional listener on the existing `ResourceTopic` from Phase 1.5. No new infrastructure — no database, no event bus, no consensus system. Static settings gain a small number of new opt-in keys (`config.reload.onInvalidEntity`, `config.write.softValidation`). |
2222

0 commit comments

Comments
 (0)