Local cloud service emulator for development and E2E inspection.
devcloud runs a local dashboard plus compatible development endpoints for Mail, S3, GCS, DynamoDB, BigQuery, SQS, Google Cloud Pub/Sub, Redshift, Redis, Application Auto Scaling, AWS Lambda, and Cloud Run. It is designed for deterministic local tests and manual inspection, not for production workloads or full cloud-provider parity.
Initialize local configuration and start all enabled services:
cargo run -p devcloud-orchestrator -- init
cargo run -p devcloud-orchestrator -- upOpen the dashboard:
http://127.0.0.1:18025/
http://127.0.0.1:18025/dashboard/
Default local endpoints:
| Service | Endpoint | Dashboard |
|---|---|---|
| Mail SMTP | 127.0.0.1:11025 |
http://127.0.0.1:18025/dashboard/mail |
| S3 | http://127.0.0.1:14566 |
http://127.0.0.1:18025/dashboard/s3 |
| GCS | http://127.0.0.1:14443 |
http://127.0.0.1:18025/dashboard/gcs |
| DynamoDB | http://127.0.0.1:18000 |
http://127.0.0.1:18025/dashboard/dynamodb |
| BigQuery | http://127.0.0.1:19050 |
http://127.0.0.1:18025/dashboard/bigquery |
| SQS | http://127.0.0.1:19324 |
http://127.0.0.1:18025/dashboard/sqs |
| Pub/Sub gRPC | 127.0.0.1:18085 |
http://127.0.0.1:18025/dashboard/pubsub |
| Pub/Sub REST | http://127.0.0.1:18086 |
http://127.0.0.1:18025/dashboard/pubsub |
| Redshift SQL | 127.0.0.1:15439 |
http://127.0.0.1:18025/dashboard/redshift |
| Redshift API | http://127.0.0.1:19099 |
http://127.0.0.1:18025/dashboard/redshift |
| Redis | redis://127.0.0.1:16379 |
http://127.0.0.1:18025/dashboard/redis |
| Application Auto Scaling | http://127.0.0.1:18030 |
http://127.0.0.1:18025/dashboard/applicationautoscaling |
| Lambda | http://127.0.0.1:19010 |
http://127.0.0.1:18025/dashboard/lambda |
| Cloud Run | http://127.0.0.1:18095 (services: http://<svc>.<region>.<project>.run.localhost:18095) |
http://127.0.0.1:18025/dashboard/cloudrun |
Useful commands:
cargo run -p devcloud-orchestrator -- help
cargo run -p devcloud-orchestrator -- init
cargo run -p devcloud-orchestrator -- up
cargo run -p devcloud-orchestrator -- dashboard
cargo run -p devcloud-orchestrator -- reset/dashboard/bigquery includes a compact local management console for BigQuery development workflows. It keeps the existing catalog browser for projects, datasets, tables, rows, schemas, and jobs, and adds a SQL query runner with useLegacySql=false, dry run, max results, result table, selected result JSON, and job reference.
The dashboard can create local datasets and tables and insert local table rows through guarded datasets.insert, tables.insert, and tabledata.insertAll flows. Guided forms cover common fields, raw JSON mode is available for request-shape testing, and the row editor validates JSON before calling insertAll while showing partial insert errors.
Dashboard API clients can also start local BigQuery jobs.insert workflows through /api/bigquery/projects/{projectId}/jobs, including GCS-backed load/import and extract/export jobs that use devcloud GCS gs:// URIs.
Safety boundaries: dashboard mutations go through /api/bigquery/* or the local BigQuery REST API path, never direct storage calls. The UI does not persist or log row payloads, credentials, Authorization headers, bearer tokens, or full request bodies. When BigQuery is disabled, query and mutation controls remain unavailable.
The dashboard frontend source lives in web/dashboard/. The Vite build output
is written to services/dashboard/assets/react, which the Rust dashboard
crate embeds at compile time.
cd web/dashboard
npm install
npm run buildDo not edit files under services/dashboard/assets/react by hand; rebuild
the React app instead.
Configuration lives at .devcloud/config.yaml. Runtime data is stored under .devcloud/data by default.
project: dev
server:
smtpPort: 11025
mailHttpPort: 11080
dashboardPort: 18025
eventRelayPort: 18027
s3Port: 14566
gcsPort: 14443
dynamodbPort: 18000
bigqueryPort: 19050
sqsPort: 19324
pubsubGrpcPort: 18085
pubsubRestPort: 18086
redshiftPort: 15439
redshiftAPIPort: 19099
redisPort: 16379
redisHttpPort: 16380
appAutoScalingPort: 18030
lambdaPort: 19010
cloudRunPort: 18095
auth:
smtp:
mode: relaxed
user: dev
password: dev
s3:
mode: relaxed
accessKeyId: dev
secretAccessKey: dev
gcs:
mode: relaxed
project: devcloud
dynamodb:
mode: relaxed
accessKeyId: dev
secretAccessKey: dev
bigquery:
mode: relaxed
project: devcloud
bearerToken: dev
sqs:
mode: relaxed
accessKeyId: dev
secretAccessKey: dev
accountId: "000000000000"
pubsub:
mode: relaxed
projectID: devcloud
bearerToken: dev
redshift:
mode: relaxed
user: dev
password: dev
accessKeyId: dev
secretAccessKey: dev
accountId: "000000000000"
redis:
mode: relaxed
password: ""
appAutoScaling:
mode: relaxed
accessKeyId: dev
secretAccessKey: dev
accountId: "000000000000"
lambda:
mode: relaxed
accessKeyId: dev
secretAccessKey: dev
accountId: "000000000000"
cloudRun:
mode: relaxed
bearerToken: dev
storage:
path: .devcloud/data
services:
mail:
enabled: true
maxMessageBytes: 10485760
s3:
enabled: true
region: us-east-1
pathStyle: true
virtualHostStyle: false
maxObjectBytes: 5368709120
multipart:
minPartBytes: 5242880
gcs:
enabled: true
project: devcloud
location: US
dynamodb:
enabled: true
region: us-east-1
billingMode: PAY_PER_REQUEST
maxItemBytes: 400000
maxTables: 256
bigquery:
enabled: true
project: devcloud
location: US
maxRowsPerTable: 1000000
maxRequestBytes: 10485760
query:
maxResultRows: 10000
maxExecutionSeconds: 30
defaultUseLegacySql: false
sqs:
enabled: true
region: us-east-1
queueUrlHost: 127.0.0.1
maxQueues: 256
maxMessageBytes: 1048576
maxReceiveBatchSize: 10
defaultVisibilityTimeoutSeconds: 30
defaultDelaySeconds: 0
defaultMessageRetentionSeconds: 345600
defaultReceiveWaitTimeSeconds: 0
schedulerIntervalSeconds: 1
pubsub:
enabled: true
project: devcloud
dataDir: .devcloud/data/pubsub
messageDataDir: .devcloud/data/message
defaultAckDeadlineSeconds: 10
messageRetentionSeconds: 604800
maxAckDeadlineSeconds: 600
maxPullMessages: 1000
pullWaitTimeoutSeconds: 1
enableREST: true
enableStreamingPull: true
enablePush: false
redshift:
enabled: true
region: us-east-1
clusterIdentifier: devcloud
database: dev
dataDir: redshift
nodeType: dc2.large
numberOfNodes: 1
maxStatementBytes: 16777216
backend:
kind: postgres
mode: managed
managed: true
externalDsn: ""
dataAPI:
enabled: true
maxResultBytes: 524288000
maxResultRows: 10000
statementRetentionSeconds: 86400
sessionRetentionSeconds: 86400
sql:
enableExtendedProtocol: false
maxResultRows: 10000
defaultSearchPath: public
copyUnload:
enableLocalS3: true
maxInputRowBytes: 4194304
redis:
enabled: true
mode: managed
binaryPath: ""
externalUrl: ""
dataDir: redis
maxMemoryMB: 256
appendOnly: false
appAutoScaling:
enabled: true
region: us-east-1
lambda:
enabled: true
region: us-east-1
cloudRun:
enabled: true
project: devcloud
region: us-central1
docker: falseLegend:
| Value | Meaning |
|---|---|
| Yes | Implemented and covered by tests or E2E smoke checks. |
| Partial | Useful local subset exists, but behavior is not complete provider parity. |
| No | Not implemented. Requests may fail, be ignored, or return a compatibility error. |
| Capability | S3 | GCS | DynamoDB | BigQuery | SQS | Pub/Sub | Redshift | Redis | App Auto Scaling | Lambda | Cloud Run | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Local endpoint | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Dashboard view | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Dashboard mutation actions | Partial | Partial | Partial | Partial | Partial | Partial | Yes | Yes | Partial | No | Partial | No |
| Persistent local storage | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Configurable port | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Enable/disable via config | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Local relaxed auth mode | N/A | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Strict cloud-grade auth/IAM | No | Partial | No | Partial | No | Partial | No | Partial | Partial | Partial | Partial | Partial |
| Feature | Status | Notes |
|---|---|---|
| SMTP receive | Yes | Supports local inbound SMTP for development. |
HELO / EHLO, MAIL FROM, RCPT TO, DATA, RSET, NOOP, QUIT |
Yes | Core SMTP smoke path. |
| Message parsing | Yes | Parses headers, text body, HTML body, and attachments. |
| Raw RFC 5322 source | Yes | Available through the dashboard API. |
| Dashboard inbox | Yes | Inspect messages and raw source. |
| Delete messages | Yes | Single-message and clear-all paths are available through dashboard API. |
| Outbound relay | No | devcloud is an inbox emulator, not an SMTP relay. |
| SMTP AUTH | No | Default auth.smtp.mode is off. |
| TLS / STARTTLS | No | Local plaintext development endpoint only. |
| IMAP / POP3 | No | Not implemented. |
| Feature | Status | Notes |
|---|---|---|
| Path-style bucket/object routes | Yes | Default route model. |
| Virtual-host style routes | Partial | {bucket}.localhost Host-header requests route to the same local bucket handlers; path-style remains the default. |
| List buckets | Yes | GET /. |
| Create, head, list, delete bucket | Yes | Empty-bucket delete is supported. |
| Get bucket location | Yes | Returns configured region. |
| Put, head, get, delete object | Yes | Includes metadata and content headers. |
| Range GET | Yes | Supports byte ranges. |
| ListObjectsV2 | Yes | Prefix listing is covered. |
| CopyObject | Yes | Supports copy and metadata replacement. |
| Content-MD5 validation | Yes | Invalid and mismatched digests return S3-style errors. |
| Multipart upload | Yes | Create/upload/list/complete/abort local multipart flows. |
| Presigned URL validation | Yes | Covered for local SigV4 GET. |
| AWS SigV4 header auth | Partial | Relaxed mode is default; strict mode validates local credentials. |
| ACLs, bucket policy, IAM | Partial | Bucket policy and bucket/object ACL metadata endpoints are supported locally, including versionId-aware object ACL metadata; IAM enforcement is not implemented. |
| Versioning | Partial | Bucket versioning, generated and null version IDs, version-aware get/delete/copy-source, delete markers, multipart-complete version IDs/ETags, and local ListObjectVersions with key/version markers are supported. |
| Lifecycle | Partial | Bucket lifecycle metadata endpoints are supported; Enabled expiration rules for current objects are applied locally on S3 reads/lists. |
| Notifications | Partial | Bucket notification configuration metadata, including EventBridge metadata, is supported; matching local object create/delete flows append local event records. |
| SSE/KMS | Partial | SSE-S3 and SSE-KMS request metadata is stored locally and exposed through object read/write response headers; real KMS and SSE-C are not implemented. |
| Replication | Partial | Bucket replication configuration metadata is supported; enabled prefix rules replicate local object write/copy/multipart-complete flows and enabled delete marker replication to existing local destination buckets. |
| Object Lock | Partial | Bucket object lock configuration, object retention/legal-hold metadata, response headers, local delete guards, and governance retention bypass are supported. |
| S3 Select | Partial | Minimal SelectObjectContent supports SELECT * FROM S3Object for CSV and JSON Lines with eventstream responses; filtering and projections are not implemented. |
| Inventory / analytics | Partial | Bucket inventory and analytics configuration metadata endpoints are supported locally; CSV-format enabled inventory configs generate deterministic local reports under bucket storage. |
| Feature | Status | Notes |
|---|---|---|
| JSON API bucket routes | Yes | /storage/v1/b.... |
| Create, get, list, delete bucket | Yes | Empty-bucket delete is supported. |
| Object media upload | Yes | uploadType=media. |
| Object multipart upload | Yes | uploadType=multipart. |
| Object resumable upload | Yes | Session start and final upload are supported. |
| Object metadata get/list/patch/delete | Yes | Includes generation and metageneration fields. |
| Object media download | Yes | /download/storage/v1/... and alt=media. |
| Range download | Yes | Supports byte ranges. |
| Copy, rewrite, compose | Yes | Local object-copy workflows. |
| Preconditions | Yes | Generation/metageneration mismatch returns 412. |
| Pagination and prefix filters | Partial | Useful local subset for object listing. |
| OAuth bearer validation | Partial | Local relaxed modes only; no real Google IAM validation. |
| XML API | No | JSON API subset only. |
| IAM/ACLs, retention, lifecycle | No | Not implemented. |
| Pub/Sub notifications, signed URLs | No | Not implemented. |
| Feature | Status | Notes |
|---|---|---|
| REST v2 project/dataset/table routes | Yes | Local catalog resources persist under .devcloud/data/bigquery. |
| Table schema and row APIs | Yes | tables.insert, tables.get/list/patch/delete, tabledata.insertAll, and tabledata.list. |
| Partitioning and clustering metadata | Yes | Time/range partitioning and clustering fields round-trip in table metadata. |
| View metadata and query execution | Partial | View table resources persist query metadata and can be queried through the local SELECT subset. |
| Routine metadata | Partial | routines.insert/list/get/patch/update/delete persist local UDF/procedure metadata; routines are not executable. |
| Jobs API | Yes | Query, query destination tables, load, copy, extract, get, list, cancel, and result workflows are covered locally. |
| GoogleSQL query execution | Partial | Deterministic local subset for common SELECT workflows; unsupported syntax fails closed. |
| Google Cloud BigQuery client libraries | Partial | Local dataset/table/row/query compatibility workflows are covered through Rust E2E gates with endpoint override. |
| IAM policy endpoints | Partial | Local policy shape is supported; no real Google IAM enforcement. |
| BigQuery Storage API, BI Engine, ML | No | Not implemented. |
| Feature | Status | Notes |
|---|---|---|
| AWS JSON 1.0 endpoint | Yes | Uses X-Amz-Target: DynamoDB_20120810.*. |
| List/Create/Describe/Update/DeleteTable | Yes | Tables become ACTIVE immediately. |
| AttributeValue shapes | Yes | Supports string, number, binary, bool, null, map, list, and sets. |
| PutItem/GetItem/UpdateItem/DeleteItem | Yes | Includes condition expression and return value subsets. |
| Query and Scan | Yes | Supports key conditions, pagination, filters, and projections for local use. |
| Global secondary indexes | Partial | Queryable local index state for supported projection paths. |
| Local secondary indexes | Partial | Metadata is accepted; behavior is not full DynamoDB parity. |
| BatchGetItem / BatchWriteItem | Yes | Local batch subset. |
| TransactGetItems / TransactWriteItems | Yes | Local transaction subset. |
| PartiQL ExecuteStatement / BatchExecuteStatement / ExecuteTransaction | Partial | Supported statement subset; unsupported PartiQL is rejected. |
| TTL | Yes | TTL metadata and expiration are supported locally. |
| Streams | Partial | Stream metadata, shard iterators, and record reads exist for local inspection. |
| Backups and restore | Partial | Local backup metadata and restore flow. |
| Tags and resource policies | Partial | Local metadata only; no IAM enforcement. |
| DescribeLimits / DescribeEndpoints | Yes | Local compatibility responses. |
| AWS SigV4 header auth | Partial | Relaxed mode is default; strict mode validates local credentials. |
| DAX, global tables, autoscaling | No | Not implemented. |
| Real capacity accounting/throttling | No | Local deterministic behavior, not AWS capacity simulation. |
| IAM condition enforcement | No | Not implemented. |
DynamoDB dashboard management is available under /dashboard/dynamodb and the local /api/dynamodb/* dashboard API. The dashboard can inspect tables, items, indexes, TTL, and streams, and can run guarded local management flows for CreateTable, PutItem, UpdateItem, UpdateTimeToLive, DeleteItem, DeleteTable, Query, and Scan. Query and Scan expose result pagination with count, scanned count, next/previous controls, and selected result item JSON. Recent operation history is stored only in browser localStorage as metadata; it does not persist item payloads, credentials, full request payloads, or pagination keys. Dashboard mutation endpoints forward through the local DynamoDB JSON protocol path instead of editing storage directly. Destructive DeleteItem and DeleteTable flows require confirmation text matching the selected table name, and disabled DynamoDB services do not expose active mutation controls.
| Feature | Status | Notes |
|---|---|---|
| gRPC emulator endpoint | Yes | Implements local google.pubsub.v1.Publisher, Subscriber, and SchemaService surfaces. |
| REST v1 endpoint | Yes | Supports topic, subscription, publish, pull, ack, seek, schema, and IAM-compatible local workflows. |
| Google Cloud Pub/Sub client libraries | Yes | Use PUBSUB_EMULATOR_HOST=127.0.0.1:18085 and PUBSUB_PROJECT_ID=devcloud. |
| Topic create/get/list/update/delete | Yes | Includes labels, retention, schema settings, and KMS metadata where applicable. |
| Subscription create/get/list/update/delete | Yes | Includes ack deadline, retain acked messages, filters, retry policy, dead-letter policy, push config, and ordering flags. |
| Publish / Pull / Acknowledge / ModifyAckDeadline | Yes | Local lease and redelivery behavior is covered by unit and E2E tests. |
| StreamingPull | Yes | Supports flow control, ack/modack/nack, cancellation, and ordering-key gates. |
| Ordering keys | Yes | Local ordered delivery gate is implemented for pull and streaming pull flows. |
| Snapshots and Seek | Yes | Snapshot CRUD and seek-to-time/snapshot flows are implemented. |
| Schemas | Yes | Schema CRUD, revisions, rollback/delete revision, and validate message are implemented locally. |
| Push subscriptions | Partial | Local HTTP push worker, retry policy, and OIDC/no-wrapper metadata are supported when push is enabled. |
| IAM endpoints | Partial | Local policy shape is supported; no real Google IAM enforcement. |
| Exactly-once delivery | Partial | Metadata is accepted; no real cloud-grade exactly-once guarantee. |
| Cloud Monitoring, quotas, billing | No | Not implemented. |
| Production durability / HA | No | Filesystem-backed local emulator only. |
Pub/Sub dashboard actions are available under /dashboard/pubsub:
- create topics
- create subscriptions
- publish a message to the selected topic
- pull messages from the selected subscription
- acknowledge pulled messages
| Feature | Status | Notes |
|---|---|---|
| PostgreSQL wire endpoint | Yes | Listens on 127.0.0.1:15439 by default for local Redshift-style SQL clients. |
| PostgreSQL simple query protocol | Yes | Covers psql smoke workflows. |
| PostgreSQL extended query protocol | Partial | Supports Parse, Bind, Describe, Execute, Sync, Close, text bind parameters, portal resume, and safe unsupported errors for binary formats. |
| PostgreSQL execution backend | Yes | Default backend is managed local PostgreSQL; explicit memory fallback remains available for development continuity. |
| Redshift SQL translation | Partial | Handles local subsets for DDL/DML, Redshift table attributes, CTAS/views/materialized-view metadata, function rewrites, COPY, and UNLOAD. |
| COPY from local S3 | Yes | Local S3 side effect imports into the PostgreSQL-backed table path. |
| UNLOAD to local S3 | Yes | Query results can be exported through local S3 side effects. |
| Redshift Data API | Yes | Execute/describe/get-result/list workflows are covered by local gates. |
| Redshift management API | Partial | Cluster, parameter group, tags, credentials, and snapshot metadata workflows are local metadata. |
| Redshift Serverless API | Partial | Namespace and workgroup metadata are local compatibility responses. |
| Snapshot restore | Yes | Restores cluster metadata from local snapshot metadata without copying real AWS data. |
| System catalog / BI introspection | Partial | Provides representative pg_catalog, information_schema, Redshift system views, and workload metadata for common probes. |
| Dashboard query runner | Yes | Redshift dashboard supports status, catalog, table detail, statement history, and SQL query execution. |
| Real AWS Redshift / IAM / KMS / CloudWatch | No | Not implemented; devcloud does not make real AWS calls. |
| MPP / columnar execution / Spectrum / datashare | No | Out of local compatibility scope. |
| Feature | Status | Notes |
|---|---|---|
| Redis wire endpoint | Yes | Uses a real redis-server child process in managed mode; devcloud does not re-implement RESP. |
| External Redis mode | Yes | services.redis.mode: external validates externalUrl with PING and exposes the same dashboard surface. |
| Managed persistence | Yes | Runtime data is kept under .devcloud/data/redis by default. |
| String/hash/list/set/zset inspection | Partial | /dashboard/redis lists keys with SCAN and shows type-specific previews. |
| Command runner | Partial | Dashboard commands are restricted to the Redis allowlist in docs/design-redis-compat.md. |
| Destructive actions | Partial | Key delete, expire, and guarded FLUSHDB are supported; FLUSHALL and unsafe commands are rejected. |
| Redis AUTH | Partial | Relaxed mode does not set requirepass; strict mode passes the configured password to managed Redis. |
| Cluster, Sentinel, modules, RedisJSON, RediSearch | No | Out of local compatibility scope. |
| Feature | Status | Notes |
|---|---|---|
| Function CRUD | Yes | CreateFunction, GetFunction, GetFunctionConfiguration, ListFunctions (Marker/MaxItems), UpdateFunctionConfiguration (RevisionId precondition), UpdateFunctionCode, DeleteFunction on the /2015-03-31/functions REST API. Name, partial ARN, and full ARN identifiers are accepted. |
| Deployment packages | Partial | Zip (ZipFile base64, or S3Bucket/S3Key from the local S3 store when S3 is enabled; stored + DEFLATE entries, no zip64) and container images (below). The layer APIs are not supported. As on AWS, a zip package over 250 MB unzipped is rejected (50 MB for a direct ZipFile upload). |
| Container images | Partial | PackageType: Image with Code.ImageUri and ImageConfig (EntryPoint, Command, WorkingDirectory) on create/update/get; GetFunction returns RepositoryType: ECR. Invoking needs services.lambda.docker: true (DEVCLOUD_LAMBDA_DOCKER=true for devcloud-lambda) and the docker CLI: each environment is a docker run of the image (any local tag or pullable reference; the first run may pull it, within a 120 s start budget) with the Runtime Interface Emulator port published on loopback — or, with services.lambda.dockerNetwork (DEVCLOUD_LAMBDA_DOCKER_NETWORK) set because devcloud itself runs in a container sharing the Docker socket, joined to that network and reached by container name — so the image must start the RIE — every AWS base image (public.ecr.aws/lambda/*) does through its entrypoint; a custom EntryPoint must too. Environments stay warm like zip functions. Containers are labelled devcloud.lambda.owner=<instance id> (the id is kept in the Lambda storage directory as instance-id); on startup devcloud removes containers carrying its own id that a killed previous run left behind, and never touches other instances' containers. MemorySize becomes the container's --memory limit; Architectures is not mapped to --platform (the image's own platform runs). Variables reach the container through an owner-only --env-file, so a value with a line break cannot be passed. The RIE answers 200 for function errors too, so a response that is exactly a Lambda error document (errorType, errorMessage, and only error fields) is reported as X-Amz-Function-Error: Unhandled. Init Duration is the RIE's runtime init time, and a cold start's log opens with INIT_START Image: <ImageUri>. REPORT's Max Memory Used is the container's cgroup memory peak since it started (page cache included; read with docker exec <container> cat, so it is omitted for images without cat), with the same warning above MemorySize. The standalone devcloud-lambda Docker image does not include Docker (its docker build target does): invoking an image function without it fails with an error saying so (and DEVCLOUD_LAMBDA_DOCKER=true without a docker CLI on PATH is warned about at startup). |
| Invoke | Partial | RequestResponse, Event (async, 202), and DryRun; X-Amz-Function-Error: Unhandled on handler errors; X-Amz-Log-Type: Tail returns the last 4 KB of the START/END/REPORT-framed log; per-function Timeout is enforced. Execution environments are reused (warm starts): an environment is one python3 / node process that loads the handler module once and then serves one invocation at a time, so module-level state and one-time initialization carry over, as on AWS. A cold start adds an INIT_START line, the init-phase output, and Init Duration in REPORT; init gets its own budget of one Timeout. Concurrent invocations get separate environments. An environment is stopped after services.lambda.idleTimeoutSeconds (default 300) without invocations, when the function's configuration or code changes or the function is deleted, after a timeout, crash, or init failure, and on shutdown; idleTimeoutSeconds: 0 makes every invocation a cold start. Unlike AWS, an idle environment is not frozen: threads a Python handler left running keep running (Node handlers are paused between invocations). MemorySize is reported to the handler and in REPORT but does not limit the process's memory. On Linux, REPORT adds Max Memory Used (the interpreter process's peak resident memory during the invocation, init included on a cold start), and the log warns when it exceeds MemorySize. With services.lambda.logInvocations: true (DEVCLOUD_LAMBDA_LOG_INVOCATIONS, on by default for devcloud-lambda) every invocation's framed log is also printed to stdout, each line tagged [<function>]. |
| Runtimes | Partial | python3.x and nodejs* handlers run as local python3 / node processes (CommonJS, ESM .mjs, async and callback handlers). A Python runtime uses the matching python3.<minor> on devcloud's PATH when there is one (e.g. python3.12), otherwise python3; Node uses node. When the interpreter's version differs from the runtime (python3.12 on Python 3.11, nodejs20.x on Node 22), the invocation log gets a [WARNING] devcloud: runtime ... is running on ... line before the handler's output (on a cold start), and devcloud's stderr repeats it once per function and runtime. The AWS-bundled SDKs (boto3 for Python, AWS SDK v3 for Node) are not provided; ship them in the package or under the /opt directory. Other runtimes (java*, dotnet*, ruby*, provided*) can be deployed but invoking them returns InvalidRuntimeException. |
| Handler environment | Partial | Cleared environment: PATH, Lambda's reserved variables (AWS_LAMBDA_FUNCTION_NAME, AWS_REGION, LAMBDA_TASK_ROOT, ...), and the function's Environment.Variables. Host credentials are never passed through. To stand in for the execution role, set services.lambda.functionAccessKeyId / functionSecretAccessKey (and optionally functionSessionToken) and every handler receives them as AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN. |
/opt (layer contents) |
Partial | As on AWS, the default PYTHONPATH is /opt/python/lib/python<version>/site-packages:/opt/python and the default NODE_PATH is /opt/nodejs/node<major>/node_modules:/opt/nodejs/node_modules, so dependencies placed (or mounted) there are importable without extra settings. services.lambda.optDir points these paths at another directory. A function that sets its own PYTHONPATH / NODE_PATH replaces the default, as on AWS. |
| Tags / account settings | Yes | /2017-03-31/tags/{arn} list/tag/untag and GetAccountSettings. |
| Function URLs | Partial | CreateFunctionUrlConfig / GetFunctionUrlConfig / UpdateFunctionUrlConfig / DeleteFunctionUrlConfig / ListFunctionUrlConfigs under /2021-10-31/functions/{name}/url ($LATEST only). The returned FunctionUrl is http://<url-id>.lambda-url.<region>.localhost:<lambdaPort>/, where <url-id> is derived from the account, region, and function name, so it stays the same when the URL, the function, or the data directory is recreated. Clients that cannot use that host can call http://127.0.0.1:<lambdaPort>/_url/<url-id>/<path>, or address the URL by function name: http://127.0.0.1:<lambdaPort>/urls/<function>/<path>. Requests reach the handler as a payload format 2.0 event through the same synchronous invoke path as Invoke (recorded in recent invocations), and the result is mapped like AWS: an object with statusCode sets status, headers, multiValueHeaders, cookies (Set-Cookie), body, and isBase64Encoded; any other JSON value becomes a 200 application/json body; a function error is 502. Cors answers preflight requests itself and replaces the function's Access-Control-* headers. AuthType: AWS_IAM refuses unsigned requests (403) in every auth mode; strict verifies the SigV4 signature (service lambda) against auth.lambda credentials, relaxed / signed-relaxed only check that it is well formed. The mode is auth.lambda.mode unless services.lambda.urlAuthMode (DEVCLOUD_LAMBDA_URL_AUTH_MODE) sets one for URLs alone, e.g. strict URLs with a relaxed API. AuthType: NONE is public: resource-based policies are not evaluated, so no AddPermission is needed, and URLs bypass the API's browser (CSRF) guard. InvokeMode: RESPONSE_STREAM is accepted but served buffered. sourceIp is always 127.0.0.1. |
| Versions, aliases, layers, event source mappings, concurrency | No | Only $LATEST exists. The layer APIs (PublishLayerVersion, Layers) are not supported; put the layer contents in the /opt directory instead. |
| Auth | Partial | relaxed, signed-relaxed, and strict SigV4 (service lambda), like Application Auto Scaling. |
| Browser (CSRF) guard | Yes | Non-GET requests carrying a non-loopback Origin (or Sec-Fetch-Site: cross-site) are rejected with 403, so a web page cannot create or invoke functions; SDKs/CLIs (no Origin) and loopback front-ends are unaffected. The dashboard's test invoke applies the same rule. |
| Feature | Status | Notes |
|---|---|---|
| Admin API v2 services | Yes | Create (serviceId, validateOnly), get, list (including location -), patch (updateMask, allowMissing, etag check), delete under /v2/projects/{p}/locations/{l}/services. |
| Revisions | Yes | A template change creates a <svc>-<generation>-<suffix> revision; list/get/delete (the latest revision cannot be deleted). |
| Long-running operations | Partial | Every mutation completes synchronously and returns a done: true Operation; operations are kept in memory (get/list/delete/:wait). |
| IAM policy | Partial | getIamPolicy, setIamPolicy, testIamPermissions per service. Strict mode enforces a bearer token on the Admin API and on service requests unless the service grants allUsers roles/run.invoker or sets invokerIamDisabled. |
| Serving requests | Partial | Requests with Host: <svc>.<location>.<project>.run.localhost[:port] (the service uri) or under /_run/<project>/<location>/<svc>/ (in urls) are reverse-proxied to the latest revision. Traffic splitting is not emulated: the latest revision always serves. |
| Container execution | Partial | containers[0].command + args run as a local process with PORT set to a free loopback port plus K_SERVICE/K_REVISION/K_CONFIGURATION and the container env values (valueSource secrets are not resolved). Image-only containers run with docker run when services.cloudRun.docker: true, otherwise requests return 503. One instance per service, started on first request, replaced on a new revision, stopped on delete/shutdown. |
| Browser (CSRF) guard | Yes | Non-GET Admin API requests with a non-loopback Origin (or Sec-Fetch-Site: cross-site) are rejected with 403; service (data-plane) requests are not restricted. |
| Jobs, domain mappings, v1 (Knative) API | No | Out of local compatibility scope. |
| Feature | Status | Notes |
|---|---|---|
| Service registry | Yes | GET /api/dashboard/services. |
| Mail messages API | Yes | List, fetch detail/raw, delete. |
| S3 dashboard API | Yes | Bucket/object listing, download links. |
| GCS dashboard API | Yes | Bucket/object/upload-session inspection. |
| DynamoDB dashboard API | Yes | Status, tables, table detail, indexes, TTL, streams, items, guarded management operations, Query, and Scan. |
| SQS dashboard API | Yes | Status, queues, messages, leases, DLQ, and purge. |
| Pub/Sub dashboard API | Yes | Status, topics, subscriptions, publish, pull, ack, and message metadata. |
| Redshift dashboard API | Yes | Status, clusters, catalog, table detail, query runner, and statement history. |
| Redis dashboard API | Yes | Status, SCAN-based keys, key inspector, allowlisted command runner, delete, expire, and guarded FLUSHDB. |
| Lambda dashboard API | Yes | Status, functions, recent invocations with log tails, and test invoke through the Invoke API. |
| Cloud Run dashboard API | Yes | Status, services, revisions, running instances, and instance logs. |
| Common React dashboard shell | Yes | All service pages are served under /dashboard/<svc> from the shared React shell; compatibility /mail, /s3, /gcs, /dynamodb, /bigquery, /redis paths return 301 redirects. |
cargo build --workspace
cargo test --workspaceService acceptance gates and E2E scripts are run locally because they require service-specific external tooling (awscli-local, postgres server binaries, aws CLI, etc.).
Run before claiming a service MVP is complete or when investigating a service-level regression:
| Stage | Command |
|---|---|
| Mail MVP | VERIFY_STAGE=full bash scripts/mail-autoloop/verify.sh |
| S3 MVP | VERIFY_STAGE=full bash scripts/s3-autoloop/verify.sh |
| GCS MVP | VERIFY_STAGE=full bash scripts/gcs-autoloop/verify.sh |
| DynamoDB MVP | VERIFY_STAGE=full bash scripts/dynamodb-autoloop/verify.sh |
| BigQuery MVP | VERIFY_STAGE=full bash scripts/bigquery-autoloop/verify.sh |
| SQS MVP | VERIFY_STAGE=full bash scripts/sqs-autoloop/verify.sh |
| Pub/Sub MVP | VERIFY_STAGE=full bash scripts/pubsub-autoloop/verify.sh |
| Redis MVP | VERIFY_STAGE=full bash scripts/redis-autoloop/verify.sh |
| Application Auto Scaling MVP | VERIFY_STAGE=full bash scripts/applicationautoscaling-autoloop/verify.sh |
| Lambda MVP | VERIFY_STAGE=full bash scripts/lambda-autoloop/verify.sh |
| Cloud Run MVP | VERIFY_STAGE=full bash scripts/cloudrun-autoloop/verify.sh |
| GCS SDK compat | VERIFY_STAGE=full-sdk-compat bash scripts/gcs-sdk-compat-autoloop/verify.sh |
| BigQuery SDK compat | VERIFY_STAGE=full-sdk-compat bash scripts/bigquery-sdk-compat-autoloop/verify.sh |
| Pub/Sub full compat | VERIFY_STAGE=full-compat bash scripts/pubsub-full-compat-autoloop/verify.sh |
| Redshift advanced compat | VERIFY_STAGE=full-advanced bash scripts/redshift-advanced-compat-autoloop/verify.sh |
| Service | Script | Extra tool requirement |
|---|---|---|
scripts/mail-e2e.sh |
none | |
| S3 | scripts/s3-e2e.sh |
awscli-local (pipx install awscli-local) |
| GCS | scripts/gcs-e2e.sh |
none |
| DynamoDB | scripts/dynamodb-e2e.sh |
aws CLI |
| BigQuery | scripts/bigquery-e2e.sh |
none |
| SQS | scripts/sqs-e2e.sh |
none |
| Pub/Sub | scripts/pubsub-e2e.sh |
none |
| Redshift | scripts/redshift-e2e.sh |
psql, aws, and postgres server binary on PATH for managed mode |
| Redshift managed PostgreSQL | scripts/redshift-managed-postgres-e2e.sh |
initdb, postgres, psql on PATH |
| Redshift SQL translator | scripts/redshift-translator-e2e.sh |
psql, aws, and postgres server binary on PATH |
| Redis | scripts/redis-e2e.sh |
redis-cli |
| Application Auto Scaling | scripts/applicationautoscaling-e2e.sh |
none |
| Lambda | scripts/lambda-e2e.sh |
python3 (handler runtime) |
| Cloud Run | scripts/cloudrun-e2e.sh |
python3 (sample service) |
Useful env vars:
E2E_INTERACTIVE=truekeeps the daemon running after the journey for browser/API inspection.E2E_DELETE_DATA=falsepreserves stored data for inspection (DynamoDB, BigQuery, SQS).E2E_<SVC>_PORTandE2E_DASHBOARD_PORToverride defaults when the standard ports are busy. Example:E2E_INTERACTIVE=true E2E_S3_PORT=14566 E2E_DASHBOARD_PORT=18025 scripts/s3-e2e.sh.
| Path | Purpose |
|---|---|
orchestrator |
CLI, config loading, workspace initialization, and service supervisor. |
services/mail |
SMTP inbox service. |
services/s3 |
S3-compatible HTTP service and filesystem-backed object store. |
services/gcs |
GCS JSON API-compatible HTTP service. |
services/dynamodb |
DynamoDB-compatible JSON API service. |
services/bigquery |
BigQuery-compatible REST API service. |
services/redis |
Redis-compatible managed/external service wrapper. |
services/sqs |
SQS-compatible JSON and Query API service. |
services/pubsub |
Google Cloud Pub/Sub-compatible REST and gRPC service. |
services/redshift |
Redshift SQL, Data API, and management API service. |
services/applicationautoscaling |
Application Auto Scaling-compatible JSON API service. |
services/lambda |
AWS Lambda-compatible REST API with local python/node handler execution. |
services/cloudrun |
Cloud Run Admin API v2 plus a reverse proxy to locally run service processes. |
services/dashboard |
Local Web UI, embedded React assets, and dashboard APIs. |
docs/ |
Product and compatibility designs. |
mock/ |
UI design mocks. |
scripts/*-autoloop/ |
Bounded implementation-loop and verification scripts. |
scripts/*-e2e.sh |
End-to-end smoke tests. |
- devcloud is a local emulator. It intentionally does not implement cloud IAM, billing, availability, or production security guarantees.
- Runtime data under
.devcloud/should not be committed. - Default development credentials are
dev/devfor local S3 and DynamoDB strict-mode smoke tests. - Compatibility targets are driven by the scripts and design docs in
docs/; unsupported provider APIs should be added deliberately with tests.