fix(handlers): reject PATCH runtime with template variant slugs #2958

Merged
devops-engineer merged 1 commits from fix/seo-agent-runtime-patch-validation into main 2026-06-15 18:57:07 +00:00
Member

A live customer conversion (JRS seo-template) set runtime="seo-agent" on PATCH /workspaces/:id. "seo-agent" is a claude-code template variant, not a runtime; persisting it wedges the workspace because no adapter recognizes the pseudo-runtime.

Changes

  • manifest.json: add optional "runtime":"claude-code" to the seo-agent workspace_template entry so variant templates resolve to their base runtime.
  • runtime_registry.go: add Runtime to manifestEntry; loadRuntimesFromManifest uses the explicit base runtime when present. Add isKnownRuntime helper.
  • workspace_crud.go: PATCH /workspaces/:id now validates that runtime is a known runtime before the (runtime, model) compatibility check, returning 422 RUNTIME_UNSUPPORTED for unknown/template-variant slugs.
  • Tests cover manifest variant normalization and PATCH rejection.

Test plan

  • go test ./workspace-server/internal/handlers/ -count=1
  • go vet ./... && go build ./...

🤖 Generated with Claude Code

A live customer conversion (JRS seo-template) set `runtime="seo-agent"` on `PATCH /workspaces/:id`. `"seo-agent"` is a `claude-code` template variant, not a runtime; persisting it wedges the workspace because no adapter recognizes the pseudo-runtime. ## Changes - `manifest.json`: add optional `"runtime":"claude-code"` to the `seo-agent` `workspace_template` entry so variant templates resolve to their base runtime. - `runtime_registry.go`: add `Runtime` to `manifestEntry`; `loadRuntimesFromManifest` uses the explicit base runtime when present. Add `isKnownRuntime` helper. - `workspace_crud.go`: `PATCH /workspaces/:id` now validates that `runtime` is a known runtime before the `(runtime, model)` compatibility check, returning `422 RUNTIME_UNSUPPORTED` for unknown/template-variant slugs. - Tests cover manifest variant normalization and PATCH rejection. ## Test plan - `go test ./workspace-server/internal/handlers/ -count=1` - `go vet ./... && go build ./...` 🤖 Generated with [Claude Code](https://claude.com/claude-code)
agent-dev-a added 1 commit 2026-06-15 18:33:57 +00:00
fix(handlers): reject PATCH runtime with template variant slugs
E2E Workspace Lifecycle (staginge2e) / E2E Workspace Lifecycle (staging) (pull_request) Has been skipped
CI / Python Lint & Test (pull_request) Successful in 7s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 8s
E2E Peer Visibility (literal MCP list_peers) / detect-changes (pull_request) Successful in 7s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (local) (pull_request) Has been skipped
Harness Replays / detect-changes (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 8s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
reserved-path-review / reserved-path-review (pull_request_target) Successful in 9s
sop-checklist / na-declarations (pull_request) N/A: (none)
E2E Workspace Lifecycle (staginge2e) / E2E Workspace Lifecycle (compile+skip) (pull_request) Successful in 14s
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (pull_request) Successful in 7s
sop-checklist / all-items-acked (pull_request_target) Successful in 9s
E2E Chat / detect-changes (pull_request) Successful in 21s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 19s
PR Diff Guard / PR diff guard (pull_request) Successful in 17s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 20s
CI / Detect changes (pull_request) Successful in 26s
E2E Chat / E2E Chat (pull_request) Successful in 3s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 3s
E2E API Smoke Test / detect-changes (pull_request) Successful in 27s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
CI / Canvas (Next.js) (pull_request) Successful in 3s
CI / Canvas Deploy Status (pull_request) Successful in 1s
gate-check-v3 / gate-check (pull_request_target) Failing after 27s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 50s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 50s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 34s
Harness Replays / Harness Replays (pull_request) Successful in 1m20s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m22s
CI / Platform (Go) (pull_request) Successful in 4m9s
CI / all-required (pull_request) Successful in 3s
reserved-path-review / reserved-path-review (pull_request_review) Successful in 7s
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_review) Successful in 11s
security-review / approved (pull_request_review) Successful in 10s
audit-force-merge / audit (pull_request_target) Successful in 9s
44469f9835
A live customer conversion (JRS seo-template) set runtime="seo-agent"
on PATCH /workspaces/:id. "seo-agent" is a claude-code template
variant, not a runtime; persisting it wedges the workspace because no
adapter recognizes the pseudo-runtime.

Changes:
- manifest.json: add optional "runtime":"claude-code" to the
  seo-agent workspace_template entry so variant templates resolve to
  their base runtime.
- runtime_registry.go: add Runtime to manifestEntry; loadRuntimesFromManifest
  uses the explicit base runtime when present. Add isKnownRuntime helper.
- workspace_crud.go: PATCH /workspaces/:id now validates runtime is a
  known runtime before the (runtime, model) compatibility check,
  returning 422 RUNTIME_UNSUPPORTED for unknown/template-variant slugs.
- Tests cover manifest variant normalization and PATCH rejection.

Test plan:
- go test ./workspace-server/internal/handlers/ -count=1
- go vet ./... && go build ./...

Co-Authored-By: Claude <noreply@anthropic.com>
agent-reviewer-cr2 approved these changes 2026-06-15 18:56:38 +00:00
agent-reviewer-cr2 left a comment
Member

APPROVE — clean, correct hardening of the PATCH-runtime path; Go CI passes (the red checks are ceremony gates: qa/security/sop/gate-check, not Platform(Go)).

5-axis:

  • Correctness — rejects an unrecognized runtime (e.g. the seo-agent template slug, which is a claude-code variant, not a runtime) before it can be persisted and wedge the workspace at boot (no adapter resolves a pseudo-runtime). Matches the create-boundary's knownRuntimes gate. The manifest "runtime":"claude-code" field + loadRuntimesFromManifest change correctly map the variant to its base so seo-agent never registers as a standalone runtime; isKnownRuntime("seo-agent") → false → 422, while claude-code → proceeds.
  • Robustness — and a real latent-bug fix: the prior code did runtime.(string) unchecked, which would panic on a non-string PATCH body ({"runtime": 5}). The new typeOK guard returns 400 instead. isKnownRuntime is fallback-safe (works before initKnownRuntimes via the compile-time fallback set).
  • Security — pure input-validation hardening; closes the panic-on-malformed-body and the persist-invalid-runtime states. No secret/auth surface.
  • Performance/Readability — O(1) map lookups; the runtimeStr refactor removes repeated assertions; clear error code (RUNTIME_UNSUPPORTED).
  • Tests TestLoadRuntimesFromManifest_UsesExplicitRuntimeForVariants pins the variant→base mapping; workspace_crud_test additions cover the reject paths; Go CI green.

Non-blocking note (sequencing): this and #2957 both edit Update's runtime block (this adds the known-runtime gate before the model-read that #2957 rewrites from the workspaces.model column to the MODEL workspace_secret). They'll need rebasing against each other — whichever lands first, rebase the other. They're complementary (this rejects the bad slug; #2957 fixes the model-read for the good runtime), both needed for the JRS conversion.

Ships the PATCH-runtime guard. 👍

**APPROVE** — clean, correct hardening of the PATCH-runtime path; Go CI passes (the red checks are ceremony gates: qa/security/sop/gate-check, not Platform(Go)). 5-axis: - **Correctness** ✅ — rejects an unrecognized runtime (e.g. the `seo-agent` template slug, which is a claude-code *variant*, not a runtime) before it can be persisted and wedge the workspace at boot (no adapter resolves a pseudo-runtime). Matches the create-boundary's `knownRuntimes` gate. The manifest `"runtime":"claude-code"` field + `loadRuntimesFromManifest` change correctly map the variant to its base so `seo-agent` never registers as a standalone runtime; `isKnownRuntime("seo-agent")` → false → 422, while `claude-code` → proceeds. - **Robustness** ✅ — and a real latent-bug fix: the prior code did `runtime.(string)` unchecked, which would **panic** on a non-string PATCH body (`{"runtime": 5}`). The new `typeOK` guard returns 400 instead. `isKnownRuntime` is fallback-safe (works before `initKnownRuntimes` via the compile-time fallback set). - **Security** ✅ — pure input-validation hardening; closes the panic-on-malformed-body and the persist-invalid-runtime states. No secret/auth surface. - **Performance/Readability** ✅ — O(1) map lookups; the `runtimeStr` refactor removes repeated assertions; clear error code (`RUNTIME_UNSUPPORTED`). - **Tests** ✅ — `TestLoadRuntimesFromManifest_UsesExplicitRuntimeForVariants` pins the variant→base mapping; workspace_crud_test additions cover the reject paths; Go CI green. **Non-blocking note (sequencing):** this and #2957 both edit `Update`'s runtime block (this adds the known-runtime gate *before* the model-read that #2957 rewrites from the `workspaces.model` column to the `MODEL` workspace_secret). They'll need rebasing against each other — whichever lands first, rebase the other. They're complementary (this rejects the bad slug; #2957 fixes the model-read for the good runtime), both needed for the JRS conversion. Ships the PATCH-runtime guard. 👍
devops-engineer merged commit e0e30b7684 into main 2026-06-15 18:57:07 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2958