ibexharness
DocsBlogReleasesRoadmap
GitHub
ibexharness

Documentation

Architecture Decision RecordsADR-0002: Repository foundation bootstrapADR-0003: Branch protection and merge policyADR-0004: Protobuf and code generation policyADR-0005: Postgres migration strategyADR-0006: Auth protobuf contract (`ibex.auth.v1`)ADR-0007: Auth token validation implementationADR-0008: Security scanning and CI quality gatesADR-0009: Permission bitmap layoutADR-0010: Cryptography policyADR-0011: Proxy auth gRPC client and middlewareADR-0012: Proxy request normalization (OpenAI chat)ADR-0013: Proxy input validation and stable error envelopeADR-0014: Core domain migration sequencingADR-0015: Proxy rate limit skeleton (Phase 1)ADR-0016: Proxy agent identity verification (Phase 1)ADR-0017: Request ID and trace context strategy (Phase 1)ADR-0018: Graceful shutdown contract (Phase 1)ADR-0019: OpenTelemetry provider configuration (Phase 1)ADR-0020: Shared package boundaries — `packages/config` and `packages/apierror`ADR-0021: Prometheus Metric Catalog (Phase 1)ADR-0022: Health check contract (Phase 1)ADR-0023: Docs site architecture (Phase 1.5)
ADRs›ADR-0013: Proxy input validation and stable error envelope
ADRs

ADR-0013: Proxy input validation and stable error envelope

Architecture decision record 0013.

ADR-0013: Proxy input validation and stable error envelope

  • Status: Accepted
  • Date: 2026-06-02
  • Authors: IBEX Harness team

Context

Milestone 1.2.2 parses OpenAI-shaped chat JSON after auth with an unbounded body read and a minimal error envelope. Goal 1.2 requires security boundaries (body size, Content-Type), semantic validation with field_errors, and consistent response headers before rate limiting (1.2.4) and provider HTTP (Phase 2).

Decision

1) Limits (security controls; ADR amendment to change)

ConstantValue
MaxRequestBodyBytes1 MiB
MaxMessagesPerRequest1000
MaxMessageContentBytes100 KiB
MaxModelNameLength256
MaxChatMaxTokens1_048_576
Temperature (when set)0.0–2.0 inclusive

2) HTTP mapping

ConditionHTTPcode
Body exceeds limit413PAYLOAD_TOO_LARGE
Wrong Content-Type on chat POST415UNSUPPORTED_MEDIA_TYPE
Semantic / header validation400VALIDATION_ERROR + field_errors
Malformed JSON (parse)400INVALID_JSON (unchanged)
Auth failures401/403/503MISSING_TOKEN, INVALID_TOKEN, INSUFFICIENT_PERMISSIONS, SERVICE_DEGRADED (ADR-0011; no renames)
Missing agent header400MISSING_AGENT_ID (ADR-0016)
Agent not authorized403AGENT_NOT_AUTHORIZED, AGENT_SUSPENDED (ADR-0016)
Agent verify unavailable503AUTH_UNAVAILABLE (ADR-0016; distinct from token SERVICE_DEGRADED)
Valid request, no provider501PROVIDER_NOT_CONFIGURED
Rate limit exceeded429RATE_LIMITED
Wrong HTTP method (JSON routes)405METHOD_NOT_ALLOWED

3) Field error codes (canonical)

REQUIRED, TOO_LONG, TOO_MANY, INVALID_ENUM, INVALID_FORMAT

4) Content-Type

POST /v1/chat/completions requires Content-Type: application/json (allows application/json; charset=utf-8).

5) IBEX headers (chat)

  • X-IBEX-Agent-ID required; value must be a UUID (v4/v7) via github.com/google/uuid
  • Optional session header format checks deferred unless specified in API doc

6) Envelope

Single package services/proxy/internal/errors:

  • Detail includes optional docs_url, field_errors
  • All proxy JSON errors use errors.Write / WriteFromRequest
  • Optional docs URL pattern: {IBEX_ERROR_DOCS_BASE}/errors/{CODE} (empty base omits docs_url)

7) Request / trace IDs

  • RequestContextMiddleware (outer chain): accept incoming request ID header when valid UUID (v4 or v7), else generate UUID v7 via packages/reqid (ADR-0017); generate synthetic trace_id per request until OTel (1.3.1)
  • Context key owned by packages/reqid; proxy http layer delegates to reqid.FromContext
  • AuthMiddleware reuses request ID from context (fallback generate for isolated tests)
  • ResponseHeadersMiddleware: sets request ID, trace ID, and X-Response-Time (ms) on every response
  • Header names configurable: IBEX_REQUEST_ID_HEADER (default X-Request-ID), IBEX_TRACE_ID_HEADER (default X-Trace-ID)
  • Proxy → auth gRPC: x-request-id metadata via client interceptor (ADR-0017)

8) Middleware order

metrics → requestContext → responseHeaders → logging → mux

POST /v1/chat/completions:
  bodyLimit → contentType → auth → agentVerify → rateLimit → handler

GET /v1/internal/auth-probe:
  auth → agentVerify → rateLimit → handler

GET /v1/orgs/{org_id}/auth-probe:
  pathOrgUUID → auth → agentVerify → rateLimit → handler

Rate limit added in 1.2.4 (ADR-0015). Agent verify added in 1.2.5 (ADR-0016).

Amends ADR-0012 §6 footnote accordingly.

9) Packages

  • internal/validation/ — limits, chat semantic validation, header validation
  • internal/http/middleware.go — body limit, content-type, request context, response headers
  • Extend internal/errors/ — do not add internal/http/errors.go

10) Deferred / out of scope

  • OTel exporter (1.3.1)
  • Multimodal content arrays (string-only until Phase 2+)
  • Bloom/LRU auth cache (2.2.1)
  • Provider HTTP (upstream/)

Consequences

Positive

  • Completes Goal 1.2 validation and stable envelope criteria on the proxy
  • DoS risk from unbounded bodies closed before JSON decode
  • Single error writer; auth codes stable for clients

Negative

  • Platform /health and /ready success payloads remain minimal {status}; errors use stable envelope
  • Trace IDs are synthetic until 1.3.1

References

  • Milestone 1.2.3
  • ADR-0011
  • ADR-0012
  • ADR-0015
  • API_DOCUMENTATION.md
  • SECURITY.md §8.1

Was this page helpful?

Edit on GitHub

Last updated on

PreviousADR-0012: Proxy request normalization (OpenAI chat)NextADR-0014: Core domain migration sequencing

On this page

  • Context
  • Decision
  • 1) Limits (security controls; ADR amendment to change)
  • 2) HTTP mapping
  • 3) Field error codes (canonical)
  • 4) Content-Type
  • 5) IBEX headers (chat)
  • 6) Envelope
  • 7) Request / trace IDs
  • 8) Middleware order
  • 9) Packages
  • 10) Deferred / out of scope
  • Consequences
  • Positive
  • Negative
  • References
0%