Skip to content

v0.21.0

Choose a tag to compare

@ryanwi ryanwi released this 02 Jun 05:00
· 37 commits to main since this release

Security

Seven security hardening fixes across three severity tiers, guided by a formal security review of the 0.20.x codebase.

Critical — fixed:

  • Resilient budget gate is now fail-closed — BUDGET in MIXED mode previously returned True on any DB exception. Budget operations now fail closed (raise). Opt out via category_overrides={OperationCategory.BUDGET: ResilienceMode.FAIL_OPEN}.

  • McpGatewayConfig.auto_create_sessions defaults to False — previously True, silently creating sessions with max_cost=10000/max_action_count=100. Callers must now supply session_id explicitly.

  • increment_budget (sync backend) is now a single atomic UPDATE — eliminates the check/increment TOCTOU race via UPDATE … WHERE used_cost + cost ≤ max_cost ….

High — fixed:

  • EventConfig.unknown_event_policy defaults to RAISE — ControlPlaneSetup previously passed IGNORE, silently dropping unmapped app events.

  • UnknownAppEventError is never swallowed by resilient wrappers — re-raised before the TELEMETRY fail-open handler in both sync and async.

  • TokenUsage.estimated_cost_usd rejects negative values — @model_validator raises ValidationError for negative costs.

Medium — fixed:

  • Agent-abort kill switch events are now state-bearing — KillSwitch._abort_agent now emits KILL_SWITCH_TRIGGERED with state_bearing=True.

  • Evaluator plugins cannot override built-in names — EvaluatorRegistry._discover warns and skips any plugin whose name collides with an already-registered evaluator.

Breaking (pre-1.0)

  • McpGatewayConfig.auto_create_sessions: True → False. Supply session_id explicitly or pass McpGatewayConfig(auto_create_sessions=True) to restore.
  • EventConfig.unknown_event_policy: IGNORE → RAISE. Add all event names to event_map, or pass EventConfig(unknown_event_policy=UnknownAppEventPolicy.IGNORE) to restore.
  • MIXED resilience mode BUDGET: FAIL_OPEN → FAIL_CLOSED. Pass category_overrides={OperationCategory.BUDGET: ResilienceMode.FAIL_OPEN} to restore.