Container Reconcile Handler — Contract & Safety Boundaries
Container Reconcile Handler — Contract & Safety Boundaries
Section titled “Container Reconcile Handler — Contract & Safety Boundaries”Overview
Section titled “Overview”cmd/gondolier/container is a standalone Go HTTP service that exposes a single
reconcile endpoint (POST /internal/reconcile) for triggering a shunt merge
queue reconciliation for a tenant’s repository. It runs inside Cloudflare
Containers as the WASI execution boundary described in
docs/architecture/shunt-container-execution.md.
Endpoint contract
Section titled “Endpoint contract”| Aspect | Detail |
|---|---|
| Path | POST /internal/reconcile |
| Method | POST only — all other methods return 405 Method Not Allowed |
| Max body | 1 KiB — larger bodies return 400 Bad Request |
| Encoding | Strict JSON — DisallowUnknownFields rejects unknown keys |
| Content-Type | Response is always application/json |
Request payload
Section titled “Request payload”type ReconcileRequest struct { TenantID string `json:"tenant_id"` // required RepoSlug string `json:"repo_slug"` // required, format "owner/name" BaseBranch string `json:"base_branch"` // required QueueName string `json:"queue_name"` // required InstanceURL string `json:"instance_url"` // required, must be https://… Token string `json:"token"` // required}Response payload
Section titled “Response payload”type ReconcileResponse struct { Status string `json:"status"` // "ok" or "error" Errors []string `json:"errors,omitempty"`}Status codes
Section titled “Status codes”| Condition | Status |
|---|---|
| Valid request, engine succeeds and result has no errors | 200 |
| Malformed / unknown fields / oversized body | 400 |
| Missing required field / invalid slug / non-https URL | 400 |
| Method not POST | 405 |
| Engine error or reconcile result with non-empty Errors | 500 |
| Unknown route | 404 |
Safety boundaries
Section titled “Safety boundaries”Token policy
Section titled “Token policy”Tokenis request-only and ephemeral. It is never:- Persisted to disk or database
- Written to logs
- Included in any response
- Reflected in error messages
- The token is passed to
engine.Config.Tokenexactly once and never re-read after that single call. - Engine and reconcile errors are genericised — no raw error strings leak to the response body.
Error redaction
Section titled “Error redaction”All engine errors become a uniform
{"status":"error","errors":["reconciliation failed"]} response at 500 Internal Server Error. The raw engine error message, stack traces, and any
token data are never included in the HTTP response.
A non-nil reconcile result with non-empty Errors (but no Go error) is
treated the same way — the handler returns 500 with the same generic
message. The result.Errors slice is never logged, persisted, or echoed
back. This is intentional: raw engine error strings may contain credential
information or internal implementation details that must not leave the service
boundary.
Input validation chain
Section titled “Input validation chain”- Method check (POST only)
- Body size cap (1 KiB via
http.MaxBytesReader) - Strict JSON decode (
DisallowUnknownFields) - Required field presence (6 fields)
InstanceURLmust be a validhttps://URI with a non-empty hostRepoSlugmust be exactlyowner/name(split on first/, both parts non-empty)
Injectable test seam
Section titled “Injectable test seam”The handler constructor accepts a reconcileFn parameter:
func reconcileHandler(reconcile reconcileFn) http.HandlerFuncWhen nil (production), it calls engine.New(cfg).Reconcile(ctx) exactly
once. When non-nil (tests), it invokes the provided function, making the
handler deterministic and independent of external services.
Health check
Section titled “Health check”GET /healthz returns 200 OK with {"status":"ok"}. No other routes exist
in this service — no index route, no dashboard, no Worker JS integration.
Relationship to Shunt Container Execution
Section titled “Relationship to Shunt Container Execution”This handler is the entry point for the container boundary. It:
- Validates and sanitises the incoming request
- Maps the request into an
engine.Config - Delegates to the shunt engine via
engine.New(cfg).Reconcile(ctx) - Returns a safe response with no credential leakage
The existing document
docs/architecture/shunt-container-execution.md
covers the broader Worker → Container orchestration flow, lease coordination,
and cron/webhook triggers. This doc focuses on the single HTTP contract and its
safety boundaries.