Changelog
Unreleased: the AI and agent gateway upgrade
A broad rework of Rustybin, from an httpbin-style echo service into an upstream for API, AI and agent gateway demos.
Foundation
- axum 0.8, a library plus a thin binary, a shared
AppState, and a middleware stack with request ids, CORS, a time-to-headers timeout, a request body limit and the request inspector. - The route catalogue as the single source of truth for the landing page, the eight collection exports, the README tables and the console's API explorer, with tests that keep routes, catalogue and OpenAPI in sync.
- Fault injection on every route (
X-Rustybin-Delay,X-Rustybin-Fail), sessions (X-Rustybin-Session), public mode, an admin token for global mutations, and a control plane under/_rustybin/. - Graceful shutdown; the HTTPS and gRPC listeners are optional; invalid settings warn instead of failing; bounded state everywhere.
New
- Mock LLM (
/ai/*): OpenAI (Chat Completions, Responses, completions, embeddings, moderations, images, audio), Azure OpenAI, Anthropic, Gemini, AWS Bedrock (with binary event streams), Ollama and Cohere, with modes, scripted rules, tool calls, structured output, deterministic tokens, native errors and rate-limit headers, latency and pace controls, credential checks and request inspection. - Guardrail mocks: Azure AI Content Safety, Bedrock ApplyGuardrail, generic check and PII redaction.
- MCP server: Streamable HTTP for 2026-07-28 and the 2025 handshake versions, legacy HTTP+SSE, OAuth 2.1 protected and API key variants, named servers.
- A2A agents: seven agents over A2A v1.0 and v0.3, JSON-RPC and HTTP+JSON, with streaming, multi-turn, auth-required and SSRF-safe push notifications.
- Identity provider: authorization code + PKCE with a login page, refresh token rotation, password, client credentials, token exchange, introspection, revocation, dynamic client registration.
- Real auth checks: JWT validation (HS256 and RS256), HMAC signatures (hmac-auth and draft-cavage, with digests), mTLS on the HTTPS listener or forwarded in a header, with a persisted demo CA.
- Request bins, generic SSE streams, webhook signing and verification (Standard Webhooks, GitHub and Stripe styles), compression (gzip, deflate, Brotli, zstd), ranges, data transfer helpers, generic JSON-RPC, GraphQL subscriptions and automatic persisted queries, gRPC reflection, health and gRPC-Web.
- The web console at
/ui. - OpenAPI mocks (
/mock/{name}): upload an OpenAPI 3.0 / 3.1 spec and get a named mock API answering with spec examples or deterministic data generated from the schemas (path parameters echoed), with rules, per-operation overrides, thePreferheader, request validation (warn or enforce), deploy checks with a report, drafts, rollback, an on/off switch, captured traffic, and mocked security from the spec (API key, basic, bearer, OAuth 2.0 / OpenID Connect scopes against the built-in identity provider, mTLS) or a fixed scheme. Managed in the console, through/_rustybin/mocks*, fromrustybin.yaml(RUSTYBIN_CONFIG_FILE,--config, reload onSIGHUP, JSON Schema for editors) or a directory of specs (RUSTYBIN_MOCKS_DIR), and with therustybin mockCLI. Apetstoresample is built in (RUSTYBIN_MOCKS_SAMPLE). - Plan limits for hosted offerings (
RUSTYBIN_PLAN,RUSTYBIN_LIMIT_*,RUSTYBIN_USAGE_FILE): rate, concurrency, streams and daily or monthly request and egress quotas, per instance or per session, with IETF RateLimit headers on 429s andGET /_rustybin/usage. Off by default. - This documentation site, with every example tested in CI, and SDK conformance suites for the mock LLM, MCP, A2A and OAuth.
Operations and hosting
- Control-plane authentication (
RUSTYBIN_CONTROL_AUTH):token(admin token) orjwt(admin token or Ed25519 JWTs withaud,expand the scopesinspector,console,admin) for every/_rustybin/*route except the new readiness probe. The web console signs in with a token from the URL fragment or a sign-in screen and reads its live feed withfetchso the bearer header is sent.RUSTYBIN_HOSTED_MODE=truepresetsjwtand JSON logs. GET /_rustybin/ready: readiness, always 200 while serving, independent of the/healthdemo toggle, exempt from auth, plan limits and capture.GET /_rustybin/metrics: Prometheus metrics with bounded labels (route templates, status classes, protocols, mock LLM tokens by model family, injected faults, open streams, egress, build info).- More metrics:
rustybin_limit_rejections_total{dimension}(plan limiter 429s and gRPCRESOURCE_EXHAUSTED),rustybin_llm_requests_total{provider,model_family,streaming}andrustybin_llm_faults_total{provider,kind}(mock LLM faults by kind), and latency buckets from 1 ms to 60 s onrustybin_request_duration_secondsso p50 and p99 can be computed withhistogram_quantile(PromQL examples in the docs). RUSTYBIN_LOG_FORMAT=json: one JSON object per line with the request id.RUSTYBIN_GRPC_ON_HTTP=true: the gRPC services on the HTTP and HTTPS listeners (h2c and ALPNh2) for a TLS-terminating proxy.RUSTYBIN_CONSOLE_TITLEandRUSTYBIN_CONSOLE_BACKLINKin the console header./_rustybin/version,/_rustybin/statusand/_rustybin/usagereport the build commit (git_sha) and the control auth mode.- Shared mode (
RUSTYBIN_SHARED_MODE=true): one instance for many API keys (X-Rustybin-Keyor?rb_key=) from a registry file or URL, per-key limits and daily quotas (429rustybin_quota_exceededuntil 00:00 UTC), inspector and usage scoped by key, keys redacted in captures, readiness waiting for the registry, andGET /_rustybin/keys/usagefor collectors.RUSTYBIN_REQUIRE_KEY=truerequires a key on a normal instance. - Optional cargo feature
quota-postgres: replicas share daily quotas through PostgreSQL (RUSTYBIN_QUOTA_STORE), withrustybin_quota_store_upin the metrics.
Changed
- Open redirects and other abuse-prone endpoints were removed or made safe
(
/redirect-toonly redirects to the same host). - Content negotiation serves JSON to browsers by default.
- The Docker image no longer generates certificates with OpenSSL at startup: Rustybin generates and persists its own demo PKI (the old script produced a CA that the server replaced, which broke mTLS and HTTPS verification in containers).
tests/smoke_test.shwas replaced by the documentation examples (docs/examples/run.sh).- The Docker image runs as an unprivileged user (uid 10001) and supports a
read-only root filesystem;
docker-compose.ymlkeeps the demo PKI in a named volume, andfly.tomluses ports 8080 / 8443 and the readiness probe. - MCP
tools/list(and the other list methods) render their result once per server and protocol version instead of on every request: about 7x the throughput, same bytes on the wire. - Minimum supported Rust version is now 1.88 (was 1.86), to take security fixes in
ruzstd(zstd request bodies, RUSTSEC-2026-0344) andtime(used when parsing client certificates, RUSTSEC-2026-0009). - Security updates: rustls 0.23.46 (RUSTSEC-2026-0285, -0346, -0347, -0348, -0349),
rustls-webpki 0.103.15 (RUSTSEC-2026-0104), h2 0.4.20 (RUSTSEC-2026-0258) and
quick-xml 0.42 (RUSTSEC-2026-0194, -0195: memory exhaustion in the namespace reader
used by the SOAP endpoint). SOAP field values still decode
&, character references and the other predefined entities; unknown entities are a Sender fault. - CI runs
cargo auditon every push.