Skip to content

Select private GitHub repositories for Docker Sandboxes #171

Description

@gannonh

Status

Approved

Approved: 2026-09-01T01:08:00Z

Goal

A maintainer can select a repository and branch available to the host GitHub account, including a private repository, then create a Docker Sandbox whose /workspace is pinned to the exact resolved commit.

Context

#159 and #163 retained a public-only repository/ref form while re-porting Docker Sandboxes. The archived archive/kata-2026-08 implementation had authenticated repository and branch discovery through the host gh session and a lazy picker with pagination, default-branch selection, and stale-response protection.

Restore that product behavior on the current durable deployment aggregate. Keep the current exact-SHA source identity and Docker lifecycle. Do not restore the archived Sandbox service, JSON session store, source fingerprints, mutable branch clone, or broad credential seeding.

Parent: #108. Related: #159, #163, #170.

Constraints and non-goals

  • The browser receives repository and branch metadata only. It never receives a GitHub credential.
  • The host gh session is the authentication authority for discovery, source resolution, and checkout.
  • Persist only { repository, ref, resolvedCommitSha }. Keep credentials out of requests, request hashes, events, intents, receipts, SQLite, provider profiles, and resource handles.
  • Keep the token out of Docker create configuration, environment, labels, mounts other than a credential-free tmpfs declaration, exec arguments, remote URLs, Git configuration, diagnostics, and logs.
  • Treat the local Docker daemon and its Unix socket as a trusted secret transport boundary. A remote or untrusted daemon is out of scope.
  • Preserve branches, tags, annotated tags, and explicit refs/... resolution.
  • Keep Docker Sandbox creation on web and desktop. Mobile creation remains out of scope.
  • Defer user-configured environment variables, user-managed secrets, and managed image channels to Configure sandbox environment and managed image channels #170 and its future decomposition.

Acceptance criteria

  • Add authenticated, write-scoped Sandbox HTTP endpoints that page repositories available to the host GitHub account and branches for one selected repository. Responses contain only decoded repository/branch metadata and use Cache-Control: no-store.
  • Repository discovery includes owner, collaborator, and organization-member repositories, sorts by update time, represents public/private/internal visibility, and returns the default branch.
  • Add a repository and branch picker to the existing Add Environment Docker flow. It loads lazily, paginates, filters loaded results locally, selects the repository default branch, deduplicates appended pages, permits retry, and prevents stale responses from replacing a newer selection. Keep a manual ref entry path for tags and explicit refs such as refs/pull/123/head.
  • Replace anonymous source resolution with command-scoped use of the host gh auth git-credential helper while retaining the current exact-ref and peeled-tag resolution behavior. There is no anonymous fallback after authenticated resolution.
  • Persist the exact resolved commit before provider allocation. Retry and recovery fetch that persisted SHA and never resolve the mutable ref again.
  • Keep the generic SandboxProviderDriver identify interface credential-free. Construct the Docker driver with a callback-scoped credential capability that obtains fresh token bytes from gh auth token only when an unfinished checkout requires them.
  • Allocate a credential-free tmpfs path for checkout auth. Stream fresh token bytes through Docker exec stdin into a mode-0600 tmpfs file, use a fixed askpass command with a clean HTTPS remote, verify detached HEAD equals the persisted SHA, and remove the token/helper through finalizer cleanup before publishing readiness.
  • A matching ready marker and HEAD make identify idempotent and skip credential acquisition. Re-entering identify for an Allocated record first removes stale auth files, reacquires the current host credential, and uses the same persisted SHA. A handled identify failure retains the current service behavior of compensating the allocation; a later user retry creates a new allocation.
  • Credential access is callback-scoped. The token is never persisted, logged, returned, or retained in an error; references are released after use and owned mutable token buffers are wiped in finalizers. Errors after acquisition use fixed redacted diagnostics and do not retain raw process output, Docker request bodies, or token-bearing causes.
  • Missing or unauthenticated gh produces distinct fixed, actionable discovery, resolution, and checkout errors without raw subprocess causes.
  • Focused tests prove discovery pagination, private/internal metadata, exact CLI arguments, branch/tag/explicit-ref resolution, recovery and compensation behavior, picker request invalidation, manual ref submission, actionable unauthenticated errors, and that a sentinel token appears only in the Docker exec stdin stream while active.
  • A guarded Docker test against a private repository available to the host gh session proves the persisted SHA equals /workspace HEAD, .git/config is credential-free, transient files are gone, and the token is absent from Docker inspect/config/exec metadata, isolated SQLite, receipts, and captured logs.
  • User documentation explains that private repository access uses the server host's authenticated GitHub CLI session and that the local Docker daemon is part of the trusted boundary.

Architecture

SandboxGitHubAccess becomes the focused host-side authority for safe repository metadata, authenticated exact-ref resolution, and construction of a callback-scoped checkout capability. SandboxDeploymentService.create continues to persist the resolved SHA before allocation and never handles a credential.

The Docker driver captures the capability at construction. During identify it first checks the ready marker and exact HEAD. An unfinished checkout acquires fresh token bytes, streams them through Docker exec stdin into a credential tmpfs, runs the existing pinned fetch through a fixed askpass helper, verifies HEAD, and cleans up. Recovery follows the same idempotent path.

Delivery slices

  1. Select and create a Docker Sandbox from a private GitHub repository: add authenticated repository and branch discovery, retain manual refs, resolve and persist the exact SHA, perform callback-scoped authenticated checkout, attach through the existing environment flow, and prove secret absence and cleanup.

Demonstration

  • Consumer: A maintainer running the web app or desktop app with Docker and an authenticated host gh session.
  • Action: Open Add Environment, choose Sandboxes and Docker, select a private repository and branch from the picker, and create the environment.
  • Observable result: The environment attaches normally and /workspace contains the exact selected revision without asking the maintainer to paste a repository URL or token.
  • Evidence: Focused test output plus the guarded private-repository Docker proof. Integrated picker screenshots require separate permission for browser or computer use.

Verification

Run focused tests for changed contracts, GitHub CLI/access, source resolution, deployment persistence/recovery, Docker driver auth transport, and picker logic/components. Do not run repo-wide checks.

Run the guarded private-repository Docker test with an isolated Kata home and an owned fixture repository. Capture the exact repository and SHA, owned container identity, secret-absence assertions, and final empty owned-container inventory. Never print or snapshot the GitHub token.

Risks and mitigations

  • Docker necessarily transports credential bytes to the container. Limit the supported trust model to the local daemon/socket, use tmpfs and Docker exec stdin transport, and exclude request bodies from diagnostics.
  • A process or daemon failure can interrupt cleanup. Use deterministic paths, cleanup before every upload, shell trap cleanup, a host finalizer, mutable token-buffer wiping, reference release, and provider compensation.
  • Repository or branch responses can race user selection. Use independent request generations and invalidate them on selection changes and unmount.

Build handoff

  • Approved scope: The private GitHub picker and authenticated exact-SHA Docker checkout described above.
  • Non-goals: Sandbox environment variables/secrets, image channels, Vercel lifecycle, mobile Sandbox creation, remote Docker daemons, and unrelated Connections refactors.
  • Ordered slice: Contracts and host access, picker, transient Docker checkout, focused tests, then guarded private-repository proof.
  • Required verification: Focused changed-file tests and one guarded private-repository Docker lifecycle proof. Browser verification remains unclaimed without explicit permission.
  • Required fixture: A private repository accessible to the existing host gh session and local Docker or OrbStack.
  • Blocking open questions: None for a trusted local Docker daemon.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementRequested improvement or new capability.kind:sub-specChild spec produced by decomposing an epic.phase:verifyCurrently in the Verify phase.status:implementedBuilt and reported. Ready to verify.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions