feat(sandbox): fork, templates, and --variable/--env-file on create#933
Merged
Conversation
Picks up SandboxCreateInput.sourceSandboxId / networkIsolation / variables plus accumulated drift in unrelated types since the last refresh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- `railway sandbox fork [ID]` forks a sandbox (default: the active one)
via sandboxCreate.sourceSandboxId; the new sandbox becomes the active
ref so subsequent `sandbox ssh`/`exec` target the fork
- `--variable KEY=VALUE` on create and fork: repeatable and
comma-separable (a comma only splits when every segment carries its
own `=`, so values containing commas stay intact)
- Bare Railway references auto-wrap: `DB=Postgres.DATABASE_URL` →
`${{Postgres.DATABASE_URL}}`, resolved server-side at create time.
Strict pattern (UPPER_SNAKE var segment) so `1.5`/`example.com`
never wrap; the unambiguous `shared.` namespace allows any case
(`shared.char`). Pre-wrapped/embedded ${{...}} values pass through
verbatim
- `--env-file PATH` (repeatable) loads dotenv-style files (comments,
export prefix, quoted values, trailing comments); `--variable` flags
override file entries on key collision
- Experimental warning on all `railway sandbox` commands (stderr, so
--json stdout stays clean)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- `railway sandbox template build` (aliases: create, new) builds a template from repeatable `-c` shell instructions via sandboxTemplateBuild; `--wait` polls until READY/FAILED. Templates are content-addressed server-side (id = recipe hash, ~7d snapshot cache), so re-running an identical build is an instant cache hit - `railway sandbox template status <id-or-name>` and `template list` - `railway sandbox create --template <name-or-id>`: sandboxCreate needs the full recipe (not just the hash), so built recipes are stored locally in config.json (StoredSandboxTemplate) with an optional `--name` handle; create resends the stored instructions - Composes with --variable/--env-file/--idle-timeout-minutes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
railway sandbox fork + --variable/--env-file on create and fork--variable/--env-file on create
Maps to sandboxCreate.networkIsolation: PRIVATE (mono #30438/#30618). Default stays ISOLATED (field omitted). First production caller of the PRIVATE path — verified live: privnet DNS resolves and a psql query against postgres.railway.internal succeeds from both a created and a forked sandbox, while default sandboxes remain isolated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f6cf64a to
2553547
Compare
…ng prod The SSH relay was a compile-time constant (ssh.railway.com) while backboard URLs follow RAILWAY_ENV — so a dev-mode CLI registered keys and created sandboxes against the develop backboard but dialed the production relay, which rejected the (correctly registered) key with 'Permission denied (publickey)'. Mirror backboard's controllers/ssh mapping: dev → ssh.railway-develop.com -p 2222; staging falls through to the prod relay exactly like backboard's IS_DEV-only branch (probes show ssh.railway-staging.com does not serve the SSH relay). Applies to native ssh, tmux sessions, the generated ~/.ssh/config block (Port line when non-default), and volume SFTP. Production behavior is byte-identical: (ssh.railway.com, None) produces the same target string, zero extra args, and the same config block — existing config-block tests pass unmodified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Command telemetry now walks nested subcommand levels (joined with ':'), so `sandbox template build` reports sub_command="template:build" instead of just "template". Note: this also enriches other nested commands (e.g. "keys:add" instead of "keys" for `ssh keys add`, "files:pull" for `volume files pull`) — dashboards doing exact matches on the old single-level values will want a prefix match. - `sandbox ssh` now emits the same stage-tagged failure events as `railway ssh` (tel.rs generalized with *_for variants taking a command namespace): ssh_resolve_target / ssh_key_setup / ssh_session / ssh_exit_nonzero under command="sandbox". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codyde
added a commit
that referenced
this pull request
Jun 4, 2026
…-browser-login * origin/master: (28 commits) chore: Release railwayapp version 5.0.0 feat(sandbox): fork, templates, and `--variable`/`--env-file` on create (#933) chore: Release railwayapp version 4.68.0 feat(volume): include modified time in files JSON (#931) chore: Release railwayapp version 4.67.0 Add service source connection support (#934) chore: Release railwayapp version 4.66.2 Make GraphQL HTTP timeout configurable via RAILWAY_HTTP_TIMEOUT (#932) chore: Release railwayapp version 4.66.1 feat(volume): show status and scheduled deletion date in volume list (#928) SSH Command: Handle Identity Files (#926) chore: Release railwayapp version 4.66.0 feat(sandbox): `railway sandbox` commands (create/list/ssh/exec/destroy) (#925) chore: Release railwayapp version 4.65.0 SSH Agent Support, `russh` edition. (#915) chore: Release railwayapp version 4.64.0 chore: Release railwayapp version 4.63.0 Rephrase agent advisory and gate by CLI version (#919) Forward --remote to setup agent in cli.new installer (#918) chore: Release railwayapp version 4.62.0 ... # Conflicts: # src/consts.rs # src/util/mod.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What shipped
Expands the
railway sandboxnamespace (#925) with forking, templates, and variable seeding, riding backend support that already landed in mono (sandboxCreate.sourceSandboxIdrailwayapp/mono#30565,sandboxCreate.variablesrailwayapp/mono#30635,sandboxTemplateBuild).railway sandbox fork [ID]--id, mirroringdestroy)railway sandbox ssh/execimmediately targets itrailway sandbox template build(aliases:create,new)-c '<shell command>'instructions viasandboxTemplateBuild;--waitpolls the status query untilREADY/FAILEDtemplate status <id-or-name>andtemplate listround out the surfacerailway sandbox create --template <name-or-id>:sandboxCreateneeds the full recipe (not just the hash), so the CLI stores built recipes locally inconfig.jsonwith an optional--namehandle and resends the instructions on create--private-networkoncreateandforksandboxCreate.networkIsolation: PRIVATE; default staysISOLATED(field omitted)psqlquery againstpostgres.railway.internalsucceeds from both a created and a forked sandbox (--variable DB=Postgres.DATABASE_URL+--private-networkis the combo that makes resolved internal URLs actually usable)--variable KEY=VALUEoncreateandfork--variable FOO=bar,BAZ=qux. A comma only splits when every segment carries its own=, so values containing commas (ALLOWED=a.com,b.com) stay intactDB=Postgres.DATABASE_URL(auto-wrapped to${{Postgres.DATABASE_URL}})DB=${{Postgres.DATABASE_URL}}(passes through verbatim)URL=http://${{svc.HOST}}:8080name.UPPER_SNAKE) so plain values like1.5orexample.comare never mangled; the unambiguousshared.namespace accepts any case (shared.char)--env-file PATHoncreateandforkexportprefix, single/double-quoted values, trailing#comments on unquoted values)--variableflags override file entries on key collisionfix(ssh): env-aware relay host (dev-mode
Permission deniedbug)ssh.railway.comwhile backboard URLs followRAILWAY_ENV— dev-mode CLIs registered keys against the develop backboard but dialed the prod relay →Permission denied (publickey)(reported by Pierre in raildev)controllers/sshmapping: dev →ssh.railway-develop.com -p 2222; staging falls through to prod exactly like backboard'sIS_DEV-only branch. Covers native ssh, tmux, the generated~/.ssh/configblock, and volume SFTP(ssh.railway.com, None)yields the same target string, no extra args, same config block (existing tests pass unmodified); prod smoke-tested (create → ssh → destroy)Telemetry
sandbox template buildnow reportssub_command: "template:build"(previously just"template"). Heads-up for dashboard owners: other nested commands get richer values too (keys:add,files:pull) — exact-match filters on the old single-level names should become prefix matchessandbox sshemits the same stage-tagged failure events asrailway ssh(tel.rsgeneralized):ssh_resolve_target/ssh_key_setup/ssh_session/ssh_exit_nonzeroundercommand: "sandbox"source: clivia user-agent, with fork/template metric tags and template cache hit/miss analytics)Misc
railway sandboxinvocation (stderr only —--jsonstdout stays clean): "Railway sandboxes are experimental and APIs may change or break during testing."src/gql/schema.jsonrefreshed from prod introspection (own commit; large diff is accumulated drift, only the sandbox types are load-bearing here)Testing
1.5,example.com,a.b.C, pre-wrapped, embedded,shared.lowercase), dotenv parsing, and file/flag precedence--idsemantics, ssh command mode--wait(npm install + marker file), instant cache hit on rebuild,status/list,create --templateverified to boot with the baked filesystem (pnpm 9.15.9+ marker present), unknown-template error hint🤖 Generated with Claude Code