Skip to main content

GCP Sandbox Provider

@smthrs/gcp is a first-class Smithers SandboxProvider for Google Cloud. It executes a <Sandbox> child workflow’s request on Cloud Run Jobs and ships the request/result bundle through a Cloud Storage bucket, since Cloud Run Jobs give the caller no shared filesystem. The shared provider-kit owns the request/result protocol, egress, secret scrubbing, and cleanup; this package supplies just the GCS transport and the Cloud Run runner. The provider id is gcp-sandbox (exported as GCP_SANDBOX_PROVIDER_ID).

Credentials

Authentication is Application Default Credentials: GOOGLE_APPLICATION_CREDENTIALS (a service-account key file) or workload identity, plus GOOGLE_CLOUD_PROJECT. Local credentials never reach the container; its env is options.env plus the Smithers, egress, and GCS-transport variables. @google-cloud/run and @google-cloud/storage are optional, lazily-imported dependencies, so the package loads without them; install both to use the real provider:

Prerequisites

The provider doesn’t create the bucket; set these up first:
  • A pre-existing Cloud Storage bucket (the transport). Set a short lifecycle TTL on the smithers/sandbox/ prefix to reap crash leftovers.
  • A Cloud Run jobName to run, or createJob to create and tear down a per-run Job. createJob also requires a container image (Cloud Run needs one to create the Job). The job’s service account needs read/write on the bucket prefix.

Required options

createGcpSandboxProvider({ projectId, location, bucket, jobName }): all four are required and missing ones throw INVALID_INPUT. projectId falls back to GOOGLE_CLOUD_PROJECT. Other knobs: prefix (default smithers/sandbox), command, workdir (default /workspace), env, cleanup ("destroy" or "keep"), timeoutSec, createJob, sandboxId(request), and client/clients/clientOptions for SDK injection.

Usage

Or register it once and reference it by id with registerGcpSandboxProvider(...) then <Sandbox provider="gcp-sandbox" />.

Request/result contract

The kit writes .smithers/sandbox-request.json and expects .smithers/sandbox-result.json back, handing the container SMITHERS_SANDBOX_REQUEST_PATH and SMITHERS_SANDBOX_RESULT_PATH. Since there’s no shared filesystem, the container round-trips those files through GCS via four extra vars the runner injects:
  • SMITHERS_SANDBOX_GCS_BUCKET: the transport bucket.
  • SMITHERS_SANDBOX_GCS_PREFIX: object-name prefix.
  • SMITHERS_SANDBOX_REQUEST_GCS_OBJECT: object holding the request JSON.
  • SMITHERS_SANDBOX_RESULT_GCS_OBJECT: object the entry must write result JSON to.
Every workdir-relative path maps to <prefix>/<runId>/<sandboxId>/<percent-encoded workdir-relative path> (the full path, not just the basename, so same-named files never collide). Cloud Run reports task counts and conditions, not a numeric exit code: a succeeded task is exit 0 and a failed task is exit 1. An infra failure (execution failed, no result written) throws; a run that writes status: "failed" result JSON is just a normal failed bundle the kit materializes.

Cleanup and cost

cleanup: "destroy" (default) deletes the transient GCS objects and, when createJob made a per-run job, that job too; cleanup: "keep" leaves everything. The bucket itself is never created or deleted. You pay for Cloud Run Job execution time plus GCS storage of the small transient objects. Compute Engine execution is future work. createMockGcpSandboxEnvironment(handler, config?) provides in-memory Cloud Storage and Cloud Run doubles for tests, needing zero real GCP credentials or bucket, so unit tests run in CI without touching GCP.