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
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>
Copy file name to clipboardExpand all lines: docs/sandbox/dial-unified-config-lite/02-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
@@ -66,7 +66,7 @@ Cross-replica freshness is delivered in two layers:
66
66
67
67
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.
68
68
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.
Copy file name to clipboardExpand all lines: docs/sandbox/dial-unified-config-lite/03-api.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,7 +49,7 @@ Aligned with the existing Resource API since launch: one `PUT` upsert at the sin
49
49
50
50
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.
51
51
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).
53
53
54
54
## Operator endpoints (`/v1/admin/*`)
55
55
@@ -58,14 +58,14 @@ POST /v1/admin/apply # apply a set of resource manifes
58
58
POST /v1/admin/validate # validate manifests without applying
59
59
GET /v1/admin/schema/{type} # JSON Schema for an entity type
60
60
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)
62
62
GET /v1/admin/config/file/{type}/{name} # get single file-sourced entry (same gating)
63
63
GET /v1/admin/audit # Phase 7 — deferred
64
64
# GET /v1/admin/export # deferred — Defer.1 (design preserved)
65
65
# GET /v1/admin/export?type=models # deferred — Defer.1
66
66
```
67
67
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`.
69
69
70
70
`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.
Copy file name to clipboardExpand all lines: docs/sandbox/dial-unified-config-lite/06-rollout.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
@@ -16,7 +16,7 @@ Phase 1 ships the **read-only Configuration API plus CLI read commands** (`get`
16
16
17
17
| Audience | What changes |
18
18
|---|---|
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. |
20
20
|**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. |
21
21
|**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`). |
0 commit comments