Skip to content

Commit a45e4e2

Browse files
tastyeffectcoclaude
andcommitted
docs(config): document app config & secrets in the /v1 OpenAPI spec + changelog
Adds the four /v1/apps/{id}/config routes (and ConfigItem/CreateConfigRequest/ PatchConfigRequest schemas) to docs/openapi.yaml so the console<->sandboxd contract test stays green after merging #33. Bumps the spec to 0.3.0 and adds an Unreleased changelog entry for the v0.3.0 integration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ba240c0 commit a45e4e2

2 files changed

Lines changed: 140 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ All notable changes to sandboxd are documented here. The format is based on
55
[Semantic Versioning](https://semver.org/) (pre-1.0: a minor bump adds features,
66
a patch is fixes only).
77

8+
## [Unreleased] — v0.3.0 (integration: `console`)
9+
10+
Backend and console landing together as one incremental release. Tracked on
11+
the `console` integration branch; `main` stays at 0.2.0 until v0.3.0 is cut.
12+
13+
### Added
14+
- **App-scoped config & secrets.** Per-app key/value config under
15+
`/v1/apps/{id}/config` (`POST` / `GET`) and `/v1/apps/{id}/config/{key}`
16+
(`PATCH` / `DELETE`). Sensitive values are AES-256-GCM-encrypted at rest and
17+
write-only over the API (a `GET` returns metadata and `value_set`, never the
18+
plaintext); non-sensitive values are returned. An `access_policy`
19+
(`control_plane_only` default) records who may later read a value through the
20+
broker. Documented in `docs/openapi.yaml`. (#33)
21+
- **Web console + `/v1` OpenAPI spec.** An optional Vite/React console (served
22+
through Traefik at `console.<domain>`) over the public `/v1` API, plus
23+
`docs/openapi.yaml` and a contract test that keeps the spec and the routes in
24+
sync. The app detail screen now includes a **Config & Secrets** panel. (#32)
25+
26+
### Note
27+
- The secrets **broker** (Slice 2 — delivering values to agents/runtimes per
28+
`access_policy`) is intentionally deferred and tracked separately; it does not
29+
block this release.
30+
831
## [0.2.0] — 2026-06-22
932

1033
Reliability fixes across the core, and durable "apps" as first-class entities

docs/openapi.yaml

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
openapi: 3.0.3
22
info:
33
title: sandboxd /v1 API
4-
version: "0.2.0"
4+
version: "0.3.0"
55
description: >
66
The public, tenant-scoped API for sandboxd. This is the only surface a
77
console or external integration should use — the internal /sandbox and
@@ -115,6 +115,89 @@ paths:
115115
application/json:
116116
schema: { $ref: "#/components/schemas/Error" }
117117

118+
/v1/apps/{id}/config:
119+
parameters:
120+
- $ref: "#/components/parameters/Id"
121+
get:
122+
tags: [apps]
123+
summary: List an app's config entries (metadata; secret values redacted)
124+
description: >
125+
Returns every config key for the app. Sensitive entries never
126+
include their value (only value_set=true); non-sensitive entries
127+
include the plaintext value.
128+
responses:
129+
"200":
130+
description: OK
131+
content:
132+
application/json:
133+
schema:
134+
type: object
135+
properties:
136+
config:
137+
type: array
138+
items: { $ref: "#/components/schemas/ConfigItem" }
139+
"404": { $ref: "#/components/responses/Error" }
140+
post:
141+
tags: [apps]
142+
summary: Create a config entry (set sensitive=true to encrypt at rest)
143+
description: >
144+
Sensitive values are AES-256-GCM-encrypted at rest and are
145+
write-only — they are never returned by any GET. access_policy
146+
governs who may later read the value through the broker; the
147+
default control_plane_only never leaves sandboxd.
148+
requestBody:
149+
required: true
150+
content:
151+
application/json:
152+
schema: { $ref: "#/components/schemas/CreateConfigRequest" }
153+
responses:
154+
"201":
155+
description: Created
156+
content:
157+
application/json:
158+
schema: { $ref: "#/components/schemas/ConfigItem" }
159+
"400": { $ref: "#/components/responses/Error" }
160+
"404": { $ref: "#/components/responses/Error" }
161+
"409":
162+
description: A config entry with this key already exists; PATCH to update.
163+
content:
164+
application/json:
165+
schema: { $ref: "#/components/schemas/Error" }
166+
167+
/v1/apps/{id}/config/{key}:
168+
parameters:
169+
- $ref: "#/components/parameters/Id"
170+
- in: path
171+
name: key
172+
required: true
173+
schema: { type: string }
174+
patch:
175+
tags: [apps]
176+
summary: Update a config entry (value, sensitivity, or access policy)
177+
description: >
178+
Omit value to keep the stored value untouched (a policy-only
179+
change preserves an existing secret). Toggling sensitive
180+
re-encodes the stored value.
181+
requestBody:
182+
required: true
183+
content:
184+
application/json:
185+
schema: { $ref: "#/components/schemas/PatchConfigRequest" }
186+
responses:
187+
"200":
188+
description: OK
189+
content:
190+
application/json:
191+
schema: { $ref: "#/components/schemas/ConfigItem" }
192+
"400": { $ref: "#/components/responses/Error" }
193+
"404": { $ref: "#/components/responses/Error" }
194+
delete:
195+
tags: [apps]
196+
summary: Delete a config entry
197+
responses:
198+
"204": { description: Deleted }
199+
"404": { $ref: "#/components/responses/Error" }
200+
118201
/v1/sandboxes:
119202
post:
120203
tags: [sandboxes]
@@ -429,6 +512,39 @@ components:
429512
name: { type: string }
430513
description: { type: string }
431514
tags: { type: array, items: { type: string } }
515+
ConfigItem:
516+
type: object
517+
properties:
518+
key: { type: string }
519+
sensitive: { type: boolean }
520+
access_policy:
521+
type: string
522+
enum: [control_plane_only, agent_access, runtime_access, both]
523+
value_set: { type: boolean, description: "True when a value is stored." }
524+
value:
525+
type: string
526+
description: "Present only for non-sensitive entries; sensitive values are never returned."
527+
created_at: { type: string, format: date-time }
528+
updated_at: { type: string, format: date-time }
529+
CreateConfigRequest:
530+
type: object
531+
required: [key]
532+
properties:
533+
key: { type: string }
534+
value: { type: string }
535+
sensitive: { type: boolean, default: false }
536+
access_policy:
537+
type: string
538+
enum: [control_plane_only, agent_access, runtime_access, both]
539+
default: control_plane_only
540+
PatchConfigRequest:
541+
type: object
542+
properties:
543+
value: { type: string, description: "Omit to keep the stored value unchanged." }
544+
sensitive: { type: boolean }
545+
access_policy:
546+
type: string
547+
enum: [control_plane_only, agent_access, runtime_access, both]
432548
Sandbox:
433549
type: object
434550
properties:

0 commit comments

Comments
 (0)