Skip to content

feat(runtime-services): support isolated external MySQL providers#2046

Merged
chubes4 merged 3 commits into
mainfrom
feat/2043-external-mysql-provider
Jul 25, 2026
Merged

feat(runtime-services): support isolated external MySQL providers#2046
chubes4 merged 3 commits into
mainfrom
feat/2043-external-mysql-provider

Conversation

@chubes4

@chubes4 chubes4 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add an explicitly configured external provider for MySQL-compatible runtime services while preserving Docker as the default
  • provision a random database and temporary schema-scoped user through host-only environment references, with SQL delivered over stdin
  • enforce runtime network policy, a named external-service boundary, and explicit write approval before any external connection
  • deliver generated workload passwords only through ephemeral secret channels and persist names-only secret-envelope evidence

Provider contract

Recipes select configuration.provider: external, reference a named configuration.externalService boundary, and declare hostEnv, optional portEnv, usernameEnv, and passwordEnv references. The referenced values are read from the host environment during provisioning; recipes, plans, lifecycle evidence, and runtime metadata contain only environment variable names.

The referenced boundary must explicitly allowlist the resolved host and declare writes: allowed-with-approval. The resolved runtime policy must allow that host and use approvals: on-write; execution must also pass --approve-external-service-writes. Any missing or mismatched layer fails before mysql or mariadb is spawned.

The provider supports independent mysql and mariadb capability declarations via configuration.engine. Native clients connect with argument arrays, receive passwords through MYSQL_PWD, receive SQL through stdin, and have stdout/stderr capped at 1 MiB per stream. Overflow kills the child and returns bounded diagnostics. Docker behavior and defaults are unchanged.

Threat model and isolation

  • never accepts or connects the workload to a supplied application database
  • denies DDL unless runtime network policy, external-service host allowlisting, boundary write capability, on-write policy, and explicit execution approval all agree
  • generates and validates random database and user identifiers
  • proves both generated names are unused before provisioning and fails closed if that proof is unavailable
  • creates a schema-scoped temporary user and grants privileges only on the generated database
  • quotes every SQL identifier and value and never interpolates credentials through a shell
  • prevents administration environment references from also being exposed through recipe runtime or secret environment
  • treats interrupted create operations as uncertain partial provisioning and rolls them back before returning
  • drops both temporary database and user after success, failure, cancellation, timeout, readiness failure, or partial provisioning
  • bounds child-process output to prevent memory exhaustion while retaining bounded failure diagnostics

Secret delivery and evidence

Administrative passwords and generated workload passwords never enter argv, recipes, plans, errors, observations, snapshots, command evidence, wp-config.php, auto-prepend PHP, request-worker payloads, or persisted artifact paths.

Both Docker and external providers return database passwords only in secretEnv; the non-secret env result omits DB_PASSWORD. For external database runs, wp-config.php references getenv('DB_PASSWORD') and WP Codebox attaches the password only to the in-memory env of each Playground PHP run. External database runtimes disable the file-backed request-worker path, preventing transient payload serialization. Recursive post-disposal scans verify the generated password is absent from artifact and WordPress directories while the PHP execution receives it through the ephemeral environment.

Persisted run attestation merges generated secret metadata with declared secret metadata. secretEnvelope.count and names are accurate, generated entries use source: managed-runtime-service, and values remain excluded under the names-only redaction contract.

Lifecycle evidence remains provider-neutral: provider/version declaration, pending/ready/failed readiness, provisioning/provisioned/released/failed lifecycle, teardown completion/failure, interruption/readiness/provision/teardown diagnostics, and control results.

Follow-up integration

Extra-Chill/homeboy-extensions#2408 can select this provider, declare the release-host database boundary and policy, map its administration environment into the four generic references, and pass explicit write approval for the isolated test lifecycle. No host, repository, vendor, project, or production-path behavior is embedded here.

Tests

  • npm run build
  • npm run test:runtime-services
  • npm run test:runtime-services-lifecycle
  • npx tsx tests/playground-cli-runner-bootstrap-ini.test.ts
  • npm run test:redaction
  • npm run test:recipe-secret-env
  • npm run test:schema-parity
  • npm run test:recipe-validation-descriptors
  • git diff --check

npm run test:disposable-mysql-mysqli-e2e is included in PR CI; the local host has no Docker, so the local invocation reports its explicit Docker-unavailable skip. The repository has no configured lint script.

Closes #2043

@chubes4
chubes4 merged commit 4b63491 into main Jul 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(runtime-services): support isolated external MySQL providers without Docker

1 participant