Skip to content

awc-control reference

awc-control is the control-plane API server (spec §8.1). It is a stateless service that runs behind a load balancer. It owns the external REST API and the trusted internal gRPC API. It MUST NOT proxy ordinary file reads or writes (spec §8.1).

The binary serves two listeners concurrently until shutdown:

  • the awc-api::v1 REST surface over HTTP (axum);
  • the internal awc-api::control gRPC surface over tonic.

Listeners

Surface Env var Default Transport
REST AWC_CONTROL_LISTEN 127.0.0.1:8080 HTTP (plaintext)
gRPC AWC_CONTROL_GRPC_LISTEN 127.0.0.1:8081 mTLS outside dev; plaintext in dev

Both listeners bind before the server accepts traffic. The process blocks on a single ctrl-c or SIGTERM; both surfaces drain and exit together.

Startup sequence

  1. Read DATABASE_URL. Exit with an error if it is unset.
  2. Connect the Postgres pool (see Database pool).
  3. Apply pending migrations (see Migrations).
  4. Load the project membership graph from the project_memberships table.
  5. Load active token revocations from the token_revocations table.
  6. Build the object store from AWC_CAS_URL.
  7. Bind the REST and gRPC listeners and serve both until shutdown.

Environment variables

Variable Default Meaning
DATABASE_URL (none) Postgres connection string. Required.
AWC_CONTROL_LISTEN 127.0.0.1:8080 REST listen address.
AWC_CONTROL_GRPC_LISTEN 127.0.0.1:8081 gRPC listen address.
AWC_DEV_MODE unset Set to 1 for local dev. Disables gRPC mTLS and relaxes the secret requirements below.
AWC_SERVICE_TOKEN_KEY (none) HMAC key for service-account tokens. Required when AWC_DEV_MODE is not 1.
AWC_MOUNT_TICKET_SEED (none) 64 hex chars (32 bytes). Signs mount tickets (spec §9.11). Required when AWC_DEV_MODE is not 1.
AWC_MOUNT_TARGET_ROOTS /opt/sandboxes Comma-separated allow-list of mount target roots (spec §13.9).
AWC_CAS_URL memory:// Object-store transport. One of memory:// or s3://.
AWC_CONTROL_TLS_CERT (none) Server certificate path for gRPC mTLS. Required outside dev.
AWC_CONTROL_TLS_KEY (none) Server private key path for gRPC mTLS. Required outside dev.
AWC_CONTROL_TLS_CLIENT_CA (none) Trusted client CA path for gRPC mTLS. Required outside dev.

s3:// for AWC_CAS_URL selects the durable object store, but the s3 cargo feature is off in the default build (default = []). Rebuild with --features s3 to enable it; without the feature, an s3:// URL is rejected at startup.

Local-dev bootstrap

These variables only take effect when AWC_DEV_BOOTSTRAP=1. They never apply to a production deployment.

Variable Default Meaning
AWC_DEV_BOOTSTRAP unset Set to 1 to grant the dev principal the Admin role and mint a dev service token.
AWC_DEV_TENANT ten_01arz3ndektsv4rrffq69g5fav Tenant for the bootstrap grant.
AWC_DEV_PROJECT prj_01arz3ndektsv4rrffq69g5fav Project for the bootstrap grant.
AWC_DEV_PRINCIPAL prin_01arz3ndektsv4rrffq69g5fav Principal that receives Admin.

When AWC_SERVICE_TOKEN_KEY is also set, the bootstrap logs a full-scope service token for the dev principal. The token is a dev-only credential with a fixed 24-hour lifetime.

Database pool

The database layer builds a single Postgres connection pool and shares it across every repository. Each repository clones the pool; the pool is reference-counted.

Setting Value Override
max_connections 16 None (fixed in code).
min_connections sqlx default None.
acquire_timeout sqlx default None.

The pool size is not exposed as an environment variable. It is fixed in code and requires a rebuild to change.

Migrations

Migrations are forward-only. The SQL migration files are embedded at compile time. There are no down or rollback files. The server applies pending migrations on startup before it accepts requests.

awc-control runs repos.migrate() after it connects. awc-worker also runs repos.migrate() on its own startup, so either binary can bring a fresh database up to the current schema.

The embedded set, in order:

Version file Adds
20260807000001_init.sql Core schema (see table below).
20260807000002_job_dedupe.sql jobs.dedupe_key.
20260807000003_gc_runs.sql gc_runs, gc_deletion_plans.
20260807000004_gc_integrity_holds.sql gc_integrity_holds.
20260808000005_project_memberships.sql project_memberships.
20260808000006_token_revocations.sql token_revocations.

The init migration creates these tables: tenants, projects, principals, hosts, snapshots, workspaces, workspace_leases, mount_sessions, mount_tickets, import_sessions, jobs, idempotency_keys, audit_events, retention_policies.

REST surface

All /v1/* routes except /v1/health require a bearer token and pass through the per-principal rate limiter. Every mutation accepts an Idempotency-Key header (spec §13.1). Every response echoes an x-request-id header.

Method Path Spec Purpose
POST /v1/import-sessions §13.3 Open an import session.
POST /v1/import-sessions/:id:batchCheckObjects §13.4 Check which declared objects are missing.
POST /v1/import-sessions/:id:complete §13.5 Complete an import; creates a VALIDATING snapshot.
GET /v1/snapshots — List snapshot metadata. Requires project_id. No dedicated spec section.
GET /v1/snapshots/:id — Get one snapshot's metadata. No dedicated spec section.
GET /v1/snapshots/:id:diff §13.14 Compare two root trees. Only the inline json format is implemented.
POST /v1/workspaces §13.6 Create a workspace from a READY snapshot.
GET /v1/workspaces/:id — Get one workspace's metadata. No dedicated spec section (§13.6 defines the resource shape).
POST /v1/workspaces/:id:fork §13.7 Fork one or more workspaces.
POST /v1/workspaces/:id:issueMountTicket §13.8 Issue a signed mount ticket.
GET /v1/health — Unauthenticated liveness probe. Returns ok.

Action verbs travel in the path segment after a colon (for example, /v1/import-sessions/import_01...:complete).

gRPC surface

Both services are privileged internal RPCs. They are served with mutual TLS outside dev mode (spec §13.1). Each handler binds the client certificate fingerprint to the registered host that owns the mount session.

Service RPC Spec
LeaseService ActivateWorkspaceLease —
LeaseService RenewWorkspaceLease §13.10
LeaseService ReleaseWorkspaceLease —
CheckpointService PublishCheckpoint §13.12

Only RenewWorkspaceLease (§13.10) and PublishCheckpoint (§13.12) have dedicated spec sections. ActivateWorkspaceLease and ReleaseWorkspaceLease are implemented in the control plane but not separately specified.

RenewWorkspaceLease is clock-independent. The control plane sets the new expiry from its own policy. The default renewal TTL is 90 seconds. A renewal returns one of: extend, remount read-only, revoke, or workspace gone.

PublishCheckpoint maps onto the control-plane checkpoint publish path. The control plane completes every mutable update for a checkpoint in a single PostgreSQL transaction (spec §13.12).

Authentication

The REST authenticator reads an Authorization: Bearer <token> header.

Credential Recognized by Verified with
Service-account token awcsat1_ prefix AWC_SERVICE_TOKEN_KEY (HMAC).
OIDC id token Any other bearer The configured OIDC verifier.

Project RBAC is loaded once at startup from the project_memberships table and held as an immutable serving snapshot. Restart the process to pick up durable membership changes.

mTLS requirement

Outside dev mode, the gRPC listener requires mutual TLS. The mTLS setup configures a server identity and a required client CA, so a connection without a trusted client certificate never reaches a service handler.

AWC_DEV_MODE=1 disables mTLS. In dev mode the server serves plaintext gRPC and the handlers accept requests that carry no client certificate.

Failure behavior

Database failure (spec §17.6)

PostgreSQL MUST be deployed with automated failover and point-in-time recovery in production. The system MUST never reconstruct a mutable workspace head by guessing from object-store contents. Object-store snapshots are immutable candidates; PostgreSQL determines which one is the acknowledged head.

After a database restore, reconciliation compares published snapshot records, workspace versions, audit events, object-store snapshot manifests, and host-reported mount sessions. Unreferenced immutable objects stay safe and are reaped by garbage collection.

Control-plane outage (spec §17.5)

Existing immutable reads and local writes do not require the control plane. During an outage:

  • a writer lease cannot be renewed authoritatively;
  • a checkpoint cannot be published;
  • a new mount ticket cannot be issued;
  • a workspace cannot be forked or deleted.

awcd MAY continue a writable mount through a bounded lease grace period. After grace expiration it MUST deny checkpoint publication and SHOULD remount the workspace read-only or pause the sandbox.

Current scope

The following are specified but not yet implemented or exposed in the current build:

  • REST TLS. Spec §13.1 requires the external API to be HTTPS. The binary serves REST as plaintext HTTP and expects TLS termination upstream (for example, at a load balancer). There is no in-process REST TLS option.
  • Rate limiting. Spec §16.10 describes admission throttling. The server constructs an unlimited limiter. There is no environment variable to set a limit.
  • OIDC discovery. The server wires a static OIDC verifier with an empty trusted set. Real OIDC discovery is a follow-up. Until then, only service-account tokens authenticate, and only when AWC_SERVICE_TOKEN_KEY is set.
  • gRPC request id. PublishCheckpoint does not yet surface an x-request-id from gRPC metadata into the audit record.
  • Durable membership seeding. The in-memory membership store loads only from project_memberships at startup. There is no admin API to mutate it at runtime.