Skip to content

sam-one: --tunnel codespaces, and a mesh of your own in a GitHub codespace - #522

Merged
aojea merged 3 commits into
google:mainfrom
aojea:feat/codespaces-testdrive
Sep 27, 2026
Merged

aojea merged 3 commits into
google:mainfrom
aojea:feat/codespaces-testdrive

Conversation

@aojea

@aojea aojea commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

A control plane of your own in a GitHub codespace, for two audiences: a practitioner who wants a public testnet without installing anything or holding a cloud account, and a contributor who wants to build and test in the browser and point external clients (SDK programs, a phone) at their branch.

What is in it

sam-one --tunnel codespaces (internal/tunnel/codespaces.go). A tunnel provider for the forwarder GitHub already runs: it derives https://<CODESPACE_NAME>-<port>.<GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN> from the environment GitHub sets, starts nothing, and plugs into the same Tunnel shape as cloudflare, so the banner, the QR code and the router advertisement work unchanged. A forwarded port is private to the codespace owner until they make it public, which no API inside the codespace can do; the provider probes its own public URL in the background, warns once with the exact click (and the gh command) when GitHub's login gate answers, and confirms the first 200 through the proxy. Unit tests cover URL derivation, the environment check and the probe state machine (gateway errors, login gate, public, deadline, cancel).

Dev containers. Three configurations:

  • .devcontainer/testnet/ copies the released sam-one and sam-node out of ghcr.io/google/sam-one:stable / sam-node:stable onto a plain base image: no toolchain, nothing compiled. .devcontainer/testnet-latest/ is the same from :latest (main). Together they mirror hub and bananas.
  • .devcontainer/devcontainer.json is the Go 1.27 image plus Node, Python and Docker-in-Docker features, with make build on create.

make testnet runs sam-one --data-dir ./.sam-one --port 8080 --tunnel codespaces (the tunnel flag only when CODESPACE_NAME is set, so on a laptop it is a local sam-one), prefers ./bin/sam-one over the one on PATH, and passes extra flags through ARGS. The state directory is ignored by git and, in a codespace, survives rebuilds.

Docs. A Codespaces guide that states the contract: what GitHub provides (URL, idle stop, retention, private ports), what a public port exposes (the same stance as Cloud Run --allow-unauthenticated), what persists, and that the command line is the one you take to Cloud Run or Kubernetes. The reference documents the provider; the getting-started tables and the contributing page gain the option; README gets two badges. Dependabot follows the dev container features and the digest-pinned base images.

Validation

  • go build ./..., go vet, golangci-lint and the dead-code check are clean; provider tests pass with -race.
  • End to end against a stand-in for GitHub's proxy (TLS reverse proxy: 302 to the login page while private, transparent once public, Host and X-Forwarded-Proto set): make testnet printed the documented command and the public URL in the banner, the provider warned while private and confirmed after the flip, /info advertised /dns4/<host>/tcp/443/wss, and a sam-node enrolled over the public URL and authenticated with the router over wss through the proxy.
  • Both dev container configurations built and ran with the devcontainer CLI; make build on create takes about three minutes on 2 cores; make testnet used the branch's own ./bin/sam-one in the develop container and the image binary in the testnet one.
  • The site builds with Hugo 0.136.5 (the CI version); the guide renders and is linked.

Rollout note

The testnet configurations run the published images, which do not have --tunnel codespaces until this merges (latest) and is tagged (stable); until then they fail with a clear unknown tunnel provider "codespaces". The develop configuration works from this branch. Still to confirm in a real codespace: WebSocket through GitHub's public port, whether the proxy sends X-Forwarded-Proto, and whether port visibility survives stop/start.

`--tunnel codespaces` advertises the https URL GitHub Codespaces assigns to
the forwarded port, https://<CODESPACE_NAME>-<port>.<forwarding domain>,
read from the environment GitHub sets. Nothing is started: GitHub runs the
forwarder, and the provider is the same Tunnel shape cloudflare uses, so the
banner, the QR code and the router advertisement work unchanged.

A forwarded port is private to the codespace owner until they make it
public, and no API inside the codespace can do that. The provider probes
its own public URL in the background: GitHub's login redirect earns one
warning with the exact click (and the gh command), and the first 200
through the proxy is confirmed in the log, so flipping the port is visible.
Two dev container configurations and one make target. `testnet` (and
`testnet-latest`) copy the released sam-one and sam-node out of the
published `stable` (or `latest`) images onto a plain base image, so a
practitioner never compiles; `develop` is the Go, Node, Python and Docker
toolchain with `make build` on create. In either, `make testnet` runs
sam-one on port 8080 with `--tunnel codespaces`, keeps its state in the
checkout's ignored .sam-one, and passes extra flags through ARGS; outside a
codespace the same target is a local sam-one.

The Codespaces guide states the contract: what GitHub provides (URL, idle
stop, retention, private ports), what a public port exposes (the Cloud Run
stance), what persists, and that the command is the one you take to Cloud
Run or Kubernetes. README badges point at the testnet and develop
configurations; Dependabot follows the features and the pinned base images.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for running and developing SAM inside GitHub Codespaces. It adds dev container configurations for both development (with Go, Node, Python, and Docker toolchains) and testnet environments (using stable or latest pre-built binaries). A new codespaces tunnel provider is implemented in internal/tunnel/codespaces.go (along with unit tests) to automatically detect the Codespace environment, derive the public HTTPS URL, and probe the forwarded port's visibility, providing actionable warnings if the port is private. Additionally, the Makefile is updated with a testnet target, and extensive documentation and README badges are added to guide users. I have no feedback to provide as there are no review comments.

The devcontainers go and base images ship without sshd, so gh codespace ssh
cannot reach a codespace built from them. The sshd feature is what GitHub's
own documentation prescribes for that case.
@aojea
aojea merged commit 744eddc into google:main Sep 27, 2026
20 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.

1 participant