| 58 | * - ensureReady → devcontainer up (starts/rebuilds container as needed) |
| 59 | */ |
| 60 | export class DevcontainerRuntime extends LocalBaseRuntime { |
| 61 | private readonly worktreeManager: WorktreeManager; |
| 62 | private readonly configPath: string; |
| 63 | |
| 64 | // Cached env used for credential forwarding |
| 65 | private lastCredentialEnv?: Record<string, string>; |
| 66 | private readonly shareCredentials: boolean; |
| 67 | |
| 68 | // Cached container requirements (mounts + env), computed by computeContainerRequirements() |
| 69 | private containerMounts: BindMount[] = []; |
| 70 | private containerEnv: Record<string, string> = {}; |
| 71 | |
| 72 | // Cached from devcontainer up output |
| 73 | private remoteHomeDir?: string; |
| 74 | private remoteWorkspaceFolder?: string; |
| 75 | private remoteUser?: string; |
| 76 | |
| 77 | // Current workspace context (set during postCreateSetup/ensureReady) |
| 78 | private currentWorkspacePath?: string; |
| 79 | |
| 80 | readonly createFlags: RuntimeCreateFlags = { |
| 81 | deferredRuntimeAccess: true, |
| 82 | }; |
| 83 | |
| 84 | /** |
| 85 | * Compute all mounts and env vars the container needs. |
| 86 | * Called once during postCreateSetup() and ensureReady(); results cached |
| 87 | * on this.containerMounts / this.containerEnv for use by exec() and getContainerEnv(). |
| 88 | * |
| 89 | * Gitdir mount is always resolved (worktree correctness). |
| 90 | * Credential env/mounts are gated behind shareCredentials. |
| 91 | */ |
| 92 | private computeContainerRequirements( |
| 93 | workspacePath: string, |
| 94 | runtimeEnv?: Record<string, string> |
| 95 | ): void { |
| 96 | const mounts: BindMount[] = []; |
| 97 | const env: Record<string, string> = {}; |
| 98 | |
| 99 | // Always: bind-mount parent .git dir for worktree support. |
| 100 | // Without this, git inside the container can't resolve the gitdir reference. |
| 101 | const gitdirMount = resolveGitdirMount(workspacePath); |
| 102 | if (gitdirMount) mounts.push(gitdirMount); |
| 103 | |
| 104 | if (this.shareCredentials) { |
| 105 | // Forward host credential env (GIT_ASKPASS, GIT_SSH_COMMAND, CODER_*, git identity) |
| 106 | Object.assign(env, resolveHostCredentialEnv()); |
| 107 | |
| 108 | // Mount /.coder-agent/ so GIT_ASKPASS=/.coder-agent/coder resolves |
| 109 | const coderMount = resolveCoderAgentMount(); |
| 110 | if (coderMount) mounts.push(coderMount); |
| 111 | |
| 112 | // SSH agent socket |
| 113 | const ssh = resolveSshAgentForwarding("/tmp/ssh-agent.sock"); |
| 114 | if (ssh) { |
| 115 | mounts.push({ source: ssh.hostSocketPath, target: ssh.targetSocketPath }); |
| 116 | env.SSH_AUTH_SOCK = ssh.targetSocketPath; |
| 117 | } |
nothing calls this directly
no outgoing calls
no test coverage detected