feat(orchestrator): update a single egress secret in place (0081)
prd-number-check / require-numbered-prds (pull_request) Successful in 8s
tracker-policy-pr / check-pr (pull_request) Successful in 22s
test / unit (pull_request) Successful in 58s
lint / lint (push) Successful in 1m7s
test / integration-docker (pull_request) Successful in 1m12s
test / coverage (pull_request) Successful in 46s
prd-number-check / require-numbered-prds (pull_request) Successful in 8s
tracker-policy-pr / check-pr (pull_request) Successful in 22s
test / unit (pull_request) Successful in 58s
lint / lint (push) Successful in 1m7s
test / integration-docker (pull_request) Successful in 1m12s
test / coverage (pull_request) Successful in 46s
Add a single-secret counterpart to reprovision_from_secret's restore-all: update ONE egress token for a running bottle without a relaunch, for refreshing a short-lived host credential (e.g. the Codex access token) whose launch-time snapshot has expired. - registry_store.store_agent_secret: per-key upsert (delete+insert of the one row), the counterpart of store_agent_secrets' replace-all. - OrchestratorCore.update_agent_secret: set the in-memory token AND upsert the re-encrypted row under the bottle's env_var_secret, leaving other tokens untouched. - POST /bottles/<id>/secret (cli-only) + client.update_agent_secret. Refs #510, #512 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -200,6 +200,35 @@ def dispatch( # pylint: disable=too-many-return-statements,too-many-branches
|
||||
return 200, {"reprovisioned": True}
|
||||
return 404, {"error": "no stored secrets for this bottle"}
|
||||
|
||||
if (
|
||||
method == "POST"
|
||||
and route.startswith("/bottles/")
|
||||
and route.endswith("/secret")
|
||||
):
|
||||
# Update ONE egress token for a running bottle in place — the
|
||||
# single-secret form of reprovision, for refreshing a short-lived host
|
||||
# credential (e.g. the Codex access token) without a relaunch. cli-only
|
||||
# (not in _GATEWAY_ROUTES): a bottle must never set its own tokens.
|
||||
bottle_id = route[len("/bottles/") : -len("/secret")]
|
||||
try:
|
||||
data = _parse_json_object(body)
|
||||
except ValueError as e:
|
||||
return 400, {"error": f"invalid JSON: {e}"}
|
||||
name = data.get("name")
|
||||
value = data.get("value")
|
||||
env_var_secret = data.get("env_var_secret")
|
||||
if (
|
||||
not isinstance(name, str) or not name
|
||||
or not isinstance(value, str) or not value
|
||||
or not isinstance(env_var_secret, str) or not env_var_secret
|
||||
):
|
||||
return 400, {
|
||||
"error": "name, value, and env_var_secret (non-empty strings) are required"
|
||||
}
|
||||
if orch.update_agent_secret(bottle_id, name, value, env_var_secret):
|
||||
return 200, {"updated": True}
|
||||
return 404, {"error": "no such bottle"}
|
||||
|
||||
if method == "DELETE" and route.startswith("/bottles/"):
|
||||
bottle_id = route[len("/bottles/"):]
|
||||
if orch.teardown_bottle(bottle_id):
|
||||
|
||||
Reference in New Issue
Block a user