Auth0 + Spinnery rolesIdentity is checked before product access.
Auth0 identifies the user, GitHub App scope limits repositories, and Spinnery roles decide who can open shells, share links, or change policy.
Security
Spinnery treats customer code, dev URL traffic, and agent activity as scoped product surfaces. Auth0 for identity, GitHub App repository scope, Spinnery authorization, organization-exclusive VMs, SSM SecureString/KMS for workspace secrets, minimal IAM on runtime hosts, signed dev links, optional Tailscale private access, configurable root policy, workspace event history, and awake-only runtime boundaries all stay visible to the team operating the workspace.
Product surface map
Security copy should map to the same path the buyer sees: login and repo scope, hosted workspace hosts, reviewer links, and runtime inputs. That keeps trust boundaries concrete before architecture details expand.
Auth0 + Spinnery rolesAuth0 identifies the user, GitHub App scope limits repositories, and Spinnery roles decide who can open shells, share links, or change policy.
org-exclusive shell and runtime VMsShell and runtime hosts are assigned to one customer organization, with workspace-level sessions, resource namespaces, and billing events.
signed app sessionSigned dev links cover web, same-origin /api, assets, and realtime traffic while blocked operational surfaces stay named and closed.
SSM referencesWorkspace secrets use SSM SecureString/KMS references and declared runtime inputs instead of appearing in browser links, route metadata, or logs.
Hosted workspace model
The security model should be legible from the first workspace handoff: spin login creates the authenticated product session, spin up opens the hosted shell, the runtime wakes separately for service work, and signed dev links expose only the app surface.
Auth0 + Spinnery rolesAuth0 establishes the CLI and dashboard user session. Spinnery then checks organization membership, workspace permissions, signed-link issuance rights, and billing visibility before opening any workspace surface.
spinnery.ymlThe workspace shape is committed beside the app: service commands, ports, inputs, dev routes, resources, checks, runtime size, and idle sleep are reviewable before a branch workspace runs.
one-org shell VMspin up opens an organization-exclusive shell VM with Git, tmux, Claude, Codex, logs, and the branch checkout. Another customer organization never shares that host.
awake service VMWeb, /api, workers, checks, and resources wake a runtime VM inside the same organization boundary only while service work needs capacity. Sleeping the runtime stops billing without changing access policy.
signed app sessionA signed dev.spinnery.dev link covers web, same-origin /api, assets, and realtime routes for one service, workspace, organization, and expiration. It never grants SSH, raw logs, secrets, root, private consoles, or runtime admin.
First-release trust
These are the public commitments the first release needs to make plain before a buyer asks for deeper architecture detail.
one-org-per-VMNo customer organization shares a shell or runtime VM with another customer organization, even when multiple branch workspaces are active.
Auth0 identifies; Spinnery authorizesAuth0 establishes the user session and login context. Spinnery checks membership, roles, GitHub App repository scope, workspace permission, signed dev link issuance, root policy, and billing visibility.
signed dev.spinnery.dev URLsReviewer access is a signed app session for one service, workspace, organization, and expiration. It does not open SSH, logs, secrets, root, private consoles, or runtime admin.
awake runtime meterSleep stops paid service capacity, but Auth0, workspace event history, signed-link policy, root policy, and workspace metadata stay governed.
Access Policy receipt
Security should be stated in product terms before architecture detail: Organization placement, Project and Workspace permissions, Service and Resource inputs, Shell and Runtime boundaries, signed dev link scope, CLI access, and the Access Policy that governs them.
one-org-per-VMEach Shell VM and Runtime VM belongs to one customer Organization. Project and Workspace placement can share only that Organization boundary; cross-customer code, dev traffic, logs, and Service processes never co-tenant.
roles + root postureSpinnery checks the user Organization, the selected Project and Workspace grants, signed dev link issuance, billing visibility, and root policy before opening a product surface.
SSM references onlyService inputs reference SSM SecureString/KMS values at Runtime wake. Raw secrets do not appear in the Shell, signed dev links, logs, route labels, private consoles, or customer handoffs.
disabled / break-glass / elevationRoot is governed by Organization policy and recorded through Workspace events. A signed dev link never grants root, SSH, runtime admin, private consoles, logs, or secrets.
Launch receipt
Security copy should describe the observable receipt a customer sees: identity and repo scope, host placement, signed review access, optional private access, and the fact that sleep changes cost without changing authorization.
Auth0 + GitHub AppThe first workspace should show the Auth0 organization, Spinnery role, and GitHub App installation scope before shell access or repo checkout happens.
one-org-per-VMThe shell and runtime hosts belong to one customer organization. Branch workspaces can share that org boundary, but another customer never lands on the same VM.
signed dev linkThe reviewer gets an expiring browser session for web, same-origin /api, assets, and realtime traffic. The signed dev link includes backend /api, while SSH, raw logs, secrets, root, private consoles, and runtime admin stay closed.
optional TailscaleTeams can route shell or private runtime surfaces through an approved customer tailnet without expanding the public signed dev link surface.
sleep changes cost onlyRuntime sleep stops metered service capacity, but Auth0, Spinnery authorization, root policy, signed-link revocation, and workspace event history remain active.
First workspace flow
The launch path should make security observable in the same moment a developer or agent opens the workspace: identity is authorized, hosts are placed, root and secret policy are named, and the reviewer link stays unissued until the app surface is ready to share.
$spin up acme/scheduler --branch signed-links
Auth0: acme developer authorized by Spinnery
GitHub: acme/scheduler selected repository installation
placement: shell vm org=acme; runtime vm org=acme
root: disabled unless break-glass is approved
secrets: SSM SecureString references only; raw values hidden
signed dev: not issued until spin share
blocked: SSH, logs, secrets, root, private consoles, runtime admin
Auth0 org -> Spinnery roleThe CLI starts from the Auth0 session, then Spinnery checks organization membership, project/workspace role, GitHub App repository scope, and signed-link issuance rights before shell access opens.
one-org-per-VMThe shell attaches inside the customer organization boundary. If service work wakes a runtime VM, that runtime stays in the same organization boundary and never co-tenants with another customer.
root disabled / SSM refsThe first receipt names the root posture and SSM SecureString references. Raw secret values are not printed, logged, or included in dev link metadata.
spin shareA signed dev link can cover web, same-origin /api, assets, and realtime traffic. SSH, logs, secrets, root, private consoles, and runtime admin remain closed.
Responsibility split
Production-facing security copy is stronger when it separates product controls from customer decisions and names what a signed dev link will never grant.
Organization-exclusive VM placement, signed dev gateway checks, Auth0 session mapping, Spinnery product authorization, runtime sleep state, and platform-secret separation are product controls.
Repository selection, spinnery.yml review, workspace role assignment, root policy choice, Tailscale policy, customer-cloud resource ownership, and cleanup decisions stay with the customer organization.
Readiness receipts, usage receipts, signed dev link scope, resource modes, and command history are the shared artifacts support, operators, developers, and agents can inspect.
SSH, raw logs, secrets, private consoles, root elevation, runtime admin, and customer-cloud credentials are never granted by a reviewer dev URL.
Controls
Operators should see the same boundaries the platform enforces: runtime placement, dev link scope, root policy, private access, and secret injection are explicit settings rather than hidden host assumptions.
Shell and runtime VMs are assigned to one customer organization. Workspaces can share the owning organization boundary, but Spinnery never packs another customer organization onto the same VM.
Auth0 proves identity, but Spinnery owns authorization. Organization membership, product roles, workspace access, dev link scope, and root policy are checked before any workspace surface opens.
Platform secrets stay in the control plane and are never copied into shell or runtime hosts. Workspace secrets are referenced through SSM SecureString paths protected by KMS and injected only into declared runtime inputs.
Signed dev links open web, same-origin /api, assets, and WebSockets while SSH, secrets, logs, MinIO console, Mailpit, and runtime admin stay private by default.
Teams can route shell or private runtime services through tagged Tailscale devices without turning private operational ports into public dev URLs.
Root access is a configurable organization policy: disabled, approved break-glass, or workspace elevation for root-heavy work. Signed dev links never inherit it.
Runtime isolation does not depend on billing state. Sleep stops metered service CPU and memory while organization policy, signed-link state, and workspace event history remain in force.
Runtime hosts use least-privilege IAM for declared workspace resources. Broad platform roles and secret-management permissions stay on Spinnery control-plane services.
Identity and authorization
Spinnery does not outsource authorization to the identity provider. Product checks live in Spinnery so organization membership, workspace role, signed dev link issuance, private access, and root elevation all use the same policy model.
Auth0 authenticationUsers authenticate through Auth0 for CLI and dashboard sessions. Auth0 establishes who the user is; it does not grant workspace access by itself.
Spinnery-owned rolesSpinnery evaluates organization membership, project role, workspace permission, signed dev link issuance rights, and root policy before allowing an action.
service / workspace / orgSigned dev link sessions and runtime actions carry the target service, workspace, and organization so access stays scoped to the selected branch environment.
Root access
Spinnery does not treat root as a hidden host default. Organizations decide whether root is disabled, break-glass only, or available in an approved workspace elevation mode, then every exception follows a visible approval path.
Root stays disabled unless the organization policy allows break-glass access or a dedicated workspace elevation mode.
A developer or agent names the package install, host repair, or debugging task that cannot be expressed in spinnery.yml or a base image update.
An admin approves the workspace, requester, expiration window, and allowed elevation mode before the shell can run root-level work.
Spinnery records the requester, approver, workspace, start and end times, then drops the workspace back to its normal root posture.
Secret delivery
Spinnery separates platform credentials from workspace runtime inputs. SSM SecureString is the handoff point for workspace secrets, while signed browser sessions, route labels, logs, and public dev links never receive raw values.
SSM SecureStringWorkspace secret values live in SSM SecureString parameters protected by KMS. Raw values do not appear in dev sessions, route labels, or event rows.
spinnery.yml inputsServices ask for inputs such as DATABASE_URL or API tokens by name, keeping secret contracts reviewable beside the code without committing values.
Runtime wakeWhen a workspace runtime wakes, Spinnery resolves the approved references and injects values only into the declared service environment.
Metadata onlyWorkspace events record who changed secret metadata, which workspace consumed a reference, and when policy changed without copying raw secrets.
Access surfaces
Signed dev links are intentionally narrower than authenticated workspace access, and private network access can be enabled without turning every service into a public URL.
Signed dev links
Signed dev links are not a tunnel into the VM. The gateway validates the signed service, workspace, organization, and expiration before it wakes or routes to the app surface.
A signed dev link binds one service, workspace, organization, and expiration before gateway traffic can reach the runtime.
Reviewers can use the app surface: web, same-origin /api, assets, and WebSockets for that workspace session.
SSH, secrets, logs, runtime admin, Tailscale private routes, root access, and resource consoles stay outside the signed browser session.
Lifecycle controls
Review access can be granted, rotated, expired, or revoked while the authenticated shell, runtime state, and workspace event history remain separate product surfaces.
Only an authorized organization member can create a dev link for an assigned workspace service. The link records issuer, service, workspace, organization, and expiration.
The gateway validates the signed scope before setting the browser session, then rechecks the session on app, same-origin /api, asset, and WebSocket requests.
Expired and revoked links stop at the gateway, even if the runtime is awake. Revocation does not tear down the workspace shell or delete runtime state.
Dev link issue, first use, expiration, revocation, and allowlist changes stay visible without logging raw secrets, cookies, or private resource console data.
Auth0 organization members with Spinnery product roles
Unknown users, wrong org context, revoked CLI sessions
Selected organizations and repositories in the installation scope
Broad personal tokens and repos outside the GitHub App installation
Workspace-scoped browser sessions with expiration and service allowlists
SSH, secrets, logs, runtime admin, private consoles
Tagged shell/runtime devices joined to the customer tailnet
Public gateway access when the workspace is Tailscale-only
Same-organization workspaces according to placement, root policy, and least-privilege runtime IAM
Cross-customer co-tenancy and broad platform IAM permissions
Runtime and billing
Runtime billing and access control are separate concerns. Sleeping a runtime stops metered service CPU and memory, but it does not expose a dormant workspace, bypass Auth0, widen signed dev link scope, or erase workspace event history.
Authenticated shell access, Git checkout, tmux sessions, logs, and workspace metadata stay available outside the runtime meter.
Dev URL traffic, tests, service commands, or agent jobs wake the organization-owned runtime VM for app, API, worker, database, cache, mail, and storage work.
Auto-sleep stops runtime billing without deleting the workspace or changing who can authenticate to the shell later.
Event history
First-release support needs enough event history to explain who opened a workspace, what woke the runtime, which dev link was used, and which policy changed.
Security reporting
Spinnery security reports should go to a direct product security channel, include the affected boundary, and avoid copying raw secrets or unrelated customer data into the report.
Name the organization, workspace, signed dev link host, affected service, and whether the report involves shell, runtime, gateway, or dashboard access.
Describe the data or capability at risk, such as cross-organization access, secret exposure, private logs, root elevation, or unsigned dev traffic.
Share timestamps, request IDs, command output, screenshots, and minimal reproduction steps without sending raw secrets or unrelated customer data.