Security & trusted repos
How a pod proves who it is, how CI proves which repo it is, and how you decide what each may do — with no long-lived secret stored in your repositories. The narrative version is in the article No Secrets: How a Pod Behind NAT Runs in CI.
On your local network
Over its direct TCP/JSON API and USB serial console, the pod's firmware is unauthenticated — it assumes a trusted bench network, the same as most lab instruments. Anyone who can reach the pod's IP can drive it, so keep pods on a trusted network segment and don't expose port 8080 to the internet. Remote access is meant to go through the cloud path below, not a forwarded port.
How a pod authenticates to the cloud
For remote/CI use, the pod opens an outbound TLS WebSocket to embeddedci.com and authenticates with a device key it holds locally. Because the connection is outbound, the pod works behind NAT or a firewall with no port-forwarding, and nothing is exposed to the public internet. The TLS connection verifies the server against embedded root certificates, so the pod only ever talks to the real server.
How CI authenticates (GitHub OIDC)
A GitHub Actions job doesn't store an API key. It mints a short-lived GitHub OIDC token — a signed assertion of "I am a job in owner/repo" — which the server verifies with GitHub and exchanges for a session scoped to the devices that repo may drive. This is the same model as PyPI Trusted Publishing. It needs one permission block:
permissions: id-token: write # lets the job mint a GitHub OIDC token for embeddedci contents: read
The token is minted per run and expires in minutes; there's no EMBEDDEDCI_API_KEY in your repo secrets to leak or rotate.
The trusted-repo allow-list
Identity isn't authorization. In the web app under BenchPod → GitHub Actions you declare which repositories are trusted and which devices each may drive:
- Add the repo as
OWNER/REPO(click Look up to resolve the numeric ids). - Choose Any device, or pin it to a specific device or set of devices.
A repo that isn't listed gets nothing; a listed repo can reach only the devices you named. So a shared fleet serves many teams without any one repo being able to grab a board it shouldn't.
What is and isn't stored
- Device key — lives on the pod, never leaves it.
- CI credential — a GitHub OIDC token minted per run, expires in minutes.
- Authorization — a server-side allow-list you control, not a secret in the repo.