Skip to content

v0.1.25.15 — canonical ScopeValidator

Choose a tag to compare

@amavashev amavashev released this 13 Apr 16:22
· 281 commits to main since this release
a220dfe

Bug fix release. Reported during v0.1.25.14 end-to-end testing: user created a budget with scope `tenant:acme/agentic:codex` ("agentic" is a typo for "agent") and the server 201'd. Server was doing essentially no canonical scope validation — `workspace:eng` without tenant prefix also worked.

What's new

`ScopeValidator` utility enforces the canonical grammar per `cycles-protocol-v0.yaml` SCOPE DERIVATION:

  • First segment must be `tenant:`
  • Each segment `:` with kind from tenant → workspace → app → workflow → agent → toolset in canonical order
  • Ids non-empty, ≤128 chars, alphanumeric-bookended (rejects `.foo`, `foo-`)
  • Cross-field: scope's tenant must match request `tenant_id` (admin-on-behalf-of routing integrity)

Policy `scope_pattern` also allows terminal wildcards (`tenant:acme/`, `tenant:acme/agent:`) per spec examples.

All rejections return 400 INVALID_REQUEST with a specific message pinpointing which segment broke which rule.

Affected endpoints

  • `POST /v1/admin/budgets`
  • `POST /v1/admin/policies`
  • `PATCH /v1/admin/policies/{id}` (via forward-guard comment; `scope_pattern` is not in update body by design)

Backward compatibility

Existing non-canonical scopes in Redis keep working — read paths don't re-validate. Only new creates must be canonical; clients sending non-canonical now get 400 with a clear error message instead of silent success.

Tests

497/497 pass (was 459 at v0.1.25.14; +38 net) including 36 `ScopeValidatorTest` cases covering every rule + pre-merge review hardening (tightened regex, regression locks, equality-branch test).

Image

`ghcr.io/runcycles/cycles-server-admin:0.1.25.15` (also `:latest`).