@elie-laloum/outpost 2.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (588) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +3 -1
  3. package/SECURITY.md +3 -1
  4. package/dist/adapters/agents/claude-diagnostics.d.ts +1 -0
  5. package/dist/adapters/agents/claude-diagnostics.js +7 -0
  6. package/dist/adapters/agents/claude-diagnostics.js.map +1 -0
  7. package/dist/adapters/agents/cli-diagnostics.constants.d.ts +12 -0
  8. package/dist/adapters/agents/cli-diagnostics.constants.js +24 -0
  9. package/dist/adapters/agents/cli-diagnostics.constants.js.map +1 -0
  10. package/dist/adapters/agents/cli-diagnostics.d.ts +4 -0
  11. package/dist/adapters/agents/cli-diagnostics.js +14 -0
  12. package/dist/adapters/agents/cli-diagnostics.js.map +1 -0
  13. package/dist/adapters/agents/cli-diagnostics.types.d.ts +13 -0
  14. package/dist/adapters/agents/cli-diagnostics.types.js +2 -0
  15. package/dist/adapters/agents/cli-diagnostics.types.js.map +1 -0
  16. package/dist/adapters/agents/codex-diagnostics.d.ts +1 -0
  17. package/dist/adapters/agents/codex-diagnostics.js +7 -0
  18. package/dist/adapters/agents/codex-diagnostics.js.map +1 -0
  19. package/dist/adapters/agents/gemini-adapter.d.ts +3 -0
  20. package/dist/adapters/agents/gemini-adapter.js +15 -0
  21. package/dist/adapters/agents/gemini-adapter.js.map +1 -0
  22. package/dist/adapters/agents/gemini-diagnostics.d.ts +2 -0
  23. package/dist/adapters/agents/gemini-diagnostics.js +15 -0
  24. package/dist/adapters/agents/gemini-diagnostics.js.map +1 -0
  25. package/dist/adapters/agents/gemini-events.d.ts +2 -0
  26. package/dist/adapters/agents/gemini-events.js +50 -0
  27. package/dist/adapters/agents/gemini-events.js.map +1 -0
  28. package/dist/adapters/agents/gemini-request.d.ts +4 -0
  29. package/dist/adapters/agents/gemini-request.js +21 -0
  30. package/dist/adapters/agents/gemini-request.js.map +1 -0
  31. package/dist/adapters/agents/gemini.types.d.ts +6 -0
  32. package/dist/adapters/agents/gemini.types.js +2 -0
  33. package/dist/adapters/agents/gemini.types.js.map +1 -0
  34. package/dist/adapters/agents/protocol-fixtures.constants.d.ts +2 -0
  35. package/dist/adapters/agents/protocol-fixtures.constants.js +105 -0
  36. package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -0
  37. package/dist/adapters/agents/protocol-fixtures.types.d.ts +6 -0
  38. package/dist/adapters/agents/protocol-fixtures.types.js +2 -0
  39. package/dist/adapters/agents/protocol-fixtures.types.js.map +1 -0
  40. package/dist/application/agent-bootstrap.constants.d.ts +1 -0
  41. package/dist/application/agent-bootstrap.constants.js +1 -0
  42. package/dist/application/agent-bootstrap.constants.js.map +1 -1
  43. package/dist/application/agent-bootstrap.js +6 -2
  44. package/dist/application/agent-bootstrap.js.map +1 -1
  45. package/dist/application/agent-output.js +9 -2
  46. package/dist/application/agent-output.js.map +1 -1
  47. package/dist/application/artifact-tasks.d.ts +5 -0
  48. package/dist/application/artifact-tasks.js +31 -0
  49. package/dist/application/artifact-tasks.js.map +1 -0
  50. package/dist/application/artifact-tasks.types.d.ts +8 -0
  51. package/dist/application/artifact-tasks.types.js +2 -0
  52. package/dist/application/artifact-tasks.types.js.map +1 -0
  53. package/dist/application/diagnostic-probe.d.ts +3 -0
  54. package/dist/application/diagnostic-probe.js +55 -0
  55. package/dist/application/diagnostic-probe.js.map +1 -0
  56. package/dist/application/dispatch-validation.js +2 -0
  57. package/dist/application/dispatch-validation.js.map +1 -1
  58. package/dist/application/doctor-agent.constants.d.ts +11 -0
  59. package/dist/application/doctor-agent.constants.js +10 -0
  60. package/dist/application/doctor-agent.constants.js.map +1 -0
  61. package/dist/application/doctor-agent.d.ts +3 -0
  62. package/dist/application/doctor-agent.js +53 -0
  63. package/dist/application/doctor-agent.js.map +1 -0
  64. package/dist/application/doctor-image.d.ts +3 -0
  65. package/dist/application/doctor-image.js +133 -0
  66. package/dist/application/doctor-image.js.map +1 -0
  67. package/dist/application/doctor-protocol.d.ts +3 -0
  68. package/dist/application/doctor-protocol.js +30 -0
  69. package/dist/application/doctor-protocol.js.map +1 -0
  70. package/dist/application/doctor-protocol.types.d.ts +10 -0
  71. package/dist/application/doctor-protocol.types.js +2 -0
  72. package/dist/application/doctor-protocol.types.js.map +1 -0
  73. package/dist/application/doctor-sandbox.constants.d.ts +5 -0
  74. package/dist/application/doctor-sandbox.constants.js +6 -0
  75. package/dist/application/doctor-sandbox.constants.js.map +1 -0
  76. package/dist/application/doctor-sandbox.d.ts +4 -0
  77. package/dist/application/doctor-sandbox.js +133 -0
  78. package/dist/application/doctor-sandbox.js.map +1 -0
  79. package/dist/application/doctor-sandbox.types.d.ts +23 -0
  80. package/dist/application/doctor-sandbox.types.js +2 -0
  81. package/dist/application/doctor-sandbox.types.js.map +1 -0
  82. package/dist/application/doctor-transfers.constants.d.ts +6 -0
  83. package/dist/application/doctor-transfers.constants.js +7 -0
  84. package/dist/application/doctor-transfers.constants.js.map +1 -0
  85. package/dist/application/doctor-transfers.d.ts +4 -0
  86. package/dist/application/doctor-transfers.js +88 -0
  87. package/dist/application/doctor-transfers.js.map +1 -0
  88. package/dist/application/doctor.constants.d.ts +9 -0
  89. package/dist/application/doctor.constants.js +15 -0
  90. package/dist/application/doctor.constants.js.map +1 -0
  91. package/dist/application/doctor.d.ts +3 -0
  92. package/dist/application/doctor.js +106 -0
  93. package/dist/application/doctor.js.map +1 -0
  94. package/dist/application/doctor.types.d.ts +39 -0
  95. package/dist/application/doctor.types.js +2 -0
  96. package/dist/application/doctor.types.js.map +1 -0
  97. package/dist/application/execution.js +1 -0
  98. package/dist/application/execution.js.map +1 -1
  99. package/dist/application/outpost.types.d.ts +4 -0
  100. package/dist/application/outpost.types.js.map +1 -1
  101. package/dist/application/queue-worker.d.ts +2 -0
  102. package/dist/application/queue-worker.js +75 -0
  103. package/dist/application/queue-worker.js.map +1 -0
  104. package/dist/application/queue-worker.types.d.ts +15 -0
  105. package/dist/application/queue-worker.types.js +2 -0
  106. package/dist/application/queue-worker.types.js.map +1 -0
  107. package/dist/application/queued-task.d.ts +3 -0
  108. package/dist/application/queued-task.js +56 -0
  109. package/dist/application/queued-task.js.map +1 -0
  110. package/dist/application/queued-task.types.d.ts +11 -0
  111. package/dist/application/queued-task.types.js +2 -0
  112. package/dist/application/queued-task.types.js.map +1 -0
  113. package/dist/application/recovery-checksum-capture.d.ts +2 -0
  114. package/dist/application/recovery-checksum-capture.js +32 -0
  115. package/dist/application/recovery-checksum-capture.js.map +1 -0
  116. package/dist/application/recovery-checksum-paths.d.ts +2 -0
  117. package/dist/application/recovery-checksum-paths.js +11 -0
  118. package/dist/application/recovery-checksum-paths.js.map +1 -0
  119. package/dist/application/recovery-checksums.constants.d.ts +5 -0
  120. package/dist/application/recovery-checksums.constants.js +6 -0
  121. package/dist/application/recovery-checksums.constants.js.map +1 -0
  122. package/dist/application/recovery-checksums.d.ts +3 -0
  123. package/dist/application/recovery-checksums.js +94 -0
  124. package/dist/application/recovery-checksums.js.map +1 -0
  125. package/dist/application/recovery-checksums.types.d.ts +17 -0
  126. package/dist/application/recovery-checksums.types.js +2 -0
  127. package/dist/application/recovery-checksums.types.js.map +1 -0
  128. package/dist/application/recovery-inspection.d.ts +2 -0
  129. package/dist/application/recovery-inspection.js +32 -0
  130. package/dist/application/recovery-inspection.js.map +1 -0
  131. package/dist/application/recovery-inspection.types.d.ts +18 -0
  132. package/dist/application/recovery-inspection.types.js +2 -0
  133. package/dist/application/recovery-inspection.types.js.map +1 -0
  134. package/dist/application/recovery-restorability.d.ts +2 -0
  135. package/dist/application/recovery-restorability.js +137 -0
  136. package/dist/application/recovery-restorability.js.map +1 -0
  137. package/dist/application/recovery-restore-snapshot.d.ts +2 -0
  138. package/dist/application/recovery-restore-snapshot.js +57 -0
  139. package/dist/application/recovery-restore-snapshot.js.map +1 -0
  140. package/dist/application/recovery-restore.d.ts +3 -0
  141. package/dist/application/recovery-restore.js +161 -0
  142. package/dist/application/recovery-restore.js.map +1 -0
  143. package/dist/application/recovery-restore.types.d.ts +28 -0
  144. package/dist/application/recovery-restore.types.js +2 -0
  145. package/dist/application/recovery-restore.types.js.map +1 -0
  146. package/dist/application/recovery-retention-policy.d.ts +2 -0
  147. package/dist/application/recovery-retention-policy.js +21 -0
  148. package/dist/application/recovery-retention-policy.js.map +1 -0
  149. package/dist/application/recovery-retention.constants.d.ts +3 -0
  150. package/dist/application/recovery-retention.constants.js +2 -0
  151. package/dist/application/recovery-retention.constants.js.map +1 -0
  152. package/dist/application/recovery-retention.d.ts +4 -0
  153. package/dist/application/recovery-retention.js +207 -0
  154. package/dist/application/recovery-retention.js.map +1 -0
  155. package/dist/application/recovery-retention.types.d.ts +52 -0
  156. package/dist/application/recovery-retention.types.js +2 -0
  157. package/dist/application/recovery-retention.types.js.map +1 -0
  158. package/dist/application/recovery-verification.constants.d.ts +5 -0
  159. package/dist/application/recovery-verification.constants.js +10 -0
  160. package/dist/application/recovery-verification.constants.js.map +1 -0
  161. package/dist/application/recovery-verification.d.ts +3 -0
  162. package/dist/application/recovery-verification.js +107 -0
  163. package/dist/application/recovery-verification.js.map +1 -0
  164. package/dist/application/recovery-verification.types.d.ts +26 -0
  165. package/dist/application/recovery-verification.types.js +2 -0
  166. package/dist/application/recovery-verification.types.js.map +1 -0
  167. package/dist/application/remote-apply.js +30 -6
  168. package/dist/application/remote-apply.js.map +1 -1
  169. package/dist/application/remote-backup.js +6 -2
  170. package/dist/application/remote-backup.js.map +1 -1
  171. package/dist/application/remote-download.js +38 -6
  172. package/dist/application/remote-download.js.map +1 -1
  173. package/dist/application/remote-history.d.ts +6 -0
  174. package/dist/application/remote-history.js +114 -0
  175. package/dist/application/remote-history.js.map +1 -0
  176. package/dist/application/remote-upload.d.ts +2 -0
  177. package/dist/application/remote-upload.js +17 -0
  178. package/dist/application/remote-upload.js.map +1 -0
  179. package/dist/application/remote-validation.js +39 -28
  180. package/dist/application/remote-validation.js.map +1 -1
  181. package/dist/application/remote-workspace.constants.d.ts +3 -0
  182. package/dist/application/remote-workspace.constants.js +2 -0
  183. package/dist/application/remote-workspace.constants.js.map +1 -0
  184. package/dist/application/remote-workspace.js +10 -10
  185. package/dist/application/remote-workspace.js.map +1 -1
  186. package/dist/application/remote-workspace.types.d.ts +3 -1
  187. package/dist/application/remote-workspace.types.js.map +1 -1
  188. package/dist/application/sandbox-activity.d.ts +3 -0
  189. package/dist/application/sandbox-activity.js +25 -0
  190. package/dist/application/sandbox-activity.js.map +1 -0
  191. package/dist/application/sandbox-provision.js +55 -10
  192. package/dist/application/sandbox-provision.js.map +1 -1
  193. package/dist/application/sandbox-session.types.d.ts +2 -0
  194. package/dist/application/sandbox-session.types.js.map +1 -1
  195. package/dist/application/sandbox.js +33 -10
  196. package/dist/application/sandbox.js.map +1 -1
  197. package/dist/application/speculation-host.d.ts +2 -0
  198. package/dist/application/speculation-host.js +30 -0
  199. package/dist/application/speculation-host.js.map +1 -0
  200. package/dist/application/speculation.constants.d.ts +4 -0
  201. package/dist/application/speculation.constants.js +2 -0
  202. package/dist/application/speculation.constants.js.map +1 -0
  203. package/dist/application/speculation.d.ts +2 -0
  204. package/dist/application/speculation.js +166 -0
  205. package/dist/application/speculation.js.map +1 -0
  206. package/dist/application/speculation.types.d.ts +56 -0
  207. package/dist/application/speculation.types.js +2 -0
  208. package/dist/application/speculation.types.js.map +1 -0
  209. package/dist/application/storage-reservation.d.ts +3 -0
  210. package/dist/application/storage-reservation.js +10 -0
  211. package/dist/application/storage-reservation.js.map +1 -0
  212. package/dist/application/storage-reservation.types.d.ts +4 -0
  213. package/dist/application/storage-reservation.types.js +2 -0
  214. package/dist/application/storage-reservation.types.js.map +1 -0
  215. package/dist/application/task-usage.d.ts +4 -0
  216. package/dist/application/task-usage.js +41 -0
  217. package/dist/application/task-usage.js.map +1 -0
  218. package/dist/application/task-usage.types.d.ts +5 -0
  219. package/dist/application/task-usage.types.js +2 -0
  220. package/dist/application/task-usage.types.js.map +1 -0
  221. package/dist/application/tasks.js +23 -2
  222. package/dist/application/tasks.js.map +1 -1
  223. package/dist/application/tasks.types.d.ts +4 -3
  224. package/dist/application/tasks.types.js.map +1 -1
  225. package/dist/application/workspace-allocation.d.ts +3 -0
  226. package/dist/application/workspace-allocation.js +34 -0
  227. package/dist/application/workspace-allocation.js.map +1 -0
  228. package/dist/application/workspace.js +2 -2
  229. package/dist/application/workspace.js.map +1 -1
  230. package/dist/cli/commands.js +4 -0
  231. package/dist/cli/commands.js.map +1 -1
  232. package/dist/cli/doctor-command.d.ts +3 -0
  233. package/dist/cli/doctor-command.js +38 -0
  234. package/dist/cli/doctor-command.js.map +1 -0
  235. package/dist/cli/main.constants.d.ts +38 -2
  236. package/dist/cli/main.constants.js +21 -2
  237. package/dist/cli/main.constants.js.map +1 -1
  238. package/dist/cli/recovery-command.d.ts +2 -0
  239. package/dist/cli/recovery-command.js +93 -0
  240. package/dist/cli/recovery-command.js.map +1 -0
  241. package/dist/cli/recovery-prune-command.d.ts +2 -0
  242. package/dist/cli/recovery-prune-command.js +34 -0
  243. package/dist/cli/recovery-prune-command.js.map +1 -0
  244. package/dist/cli/recovery-restore-command.d.ts +2 -0
  245. package/dist/cli/recovery-restore-command.js +34 -0
  246. package/dist/cli/recovery-restore-command.js.map +1 -0
  247. package/dist/cli/recovery-verify-command.d.ts +2 -0
  248. package/dist/cli/recovery-verify-command.js +43 -0
  249. package/dist/cli/recovery-verify-command.js.map +1 -0
  250. package/dist/cli/scaffold-files.js +2 -2
  251. package/dist/cli/scaffold-files.js.map +1 -1
  252. package/dist/cli/scaffold-validation.js +1 -1
  253. package/dist/cli/scaffold-validation.js.map +1 -1
  254. package/dist/cli/scaffold.constants.d.ts +5 -0
  255. package/dist/cli/scaffold.constants.js +7 -2
  256. package/dist/cli/scaffold.constants.js.map +1 -1
  257. package/dist/cli/scaffold.types.d.ts +1 -1
  258. package/dist/cli/scaffold.types.js.map +1 -1
  259. package/dist/domain/agent.types.d.ts +2 -0
  260. package/dist/domain/agent.types.js.map +1 -1
  261. package/dist/domain/artifact-reference.d.ts +4 -0
  262. package/dist/domain/artifact-reference.js +90 -0
  263. package/dist/domain/artifact-reference.js.map +1 -0
  264. package/dist/domain/artifact.constants.d.ts +2 -0
  265. package/dist/domain/artifact.constants.js +3 -0
  266. package/dist/domain/artifact.constants.js.map +1 -0
  267. package/dist/domain/artifact.d.ts +7 -0
  268. package/dist/domain/artifact.js +104 -0
  269. package/dist/domain/artifact.js.map +1 -0
  270. package/dist/domain/artifact.types.d.ts +44 -0
  271. package/dist/domain/artifact.types.js +2 -0
  272. package/dist/domain/artifact.types.js.map +1 -0
  273. package/dist/domain/egress.constants.d.ts +1 -0
  274. package/dist/domain/egress.constants.js +7 -0
  275. package/dist/domain/egress.constants.js.map +1 -0
  276. package/dist/domain/egress.d.ts +2 -0
  277. package/dist/domain/egress.js +48 -0
  278. package/dist/domain/egress.js.map +1 -0
  279. package/dist/domain/egress.types.d.ts +8 -0
  280. package/dist/domain/egress.types.js +2 -0
  281. package/dist/domain/egress.types.js.map +1 -0
  282. package/dist/domain/ports.d.ts +1 -1
  283. package/dist/domain/ports.js.map +1 -1
  284. package/dist/domain/sandbox.types.d.ts +13 -0
  285. package/dist/domain/sandbox.types.js.map +1 -1
  286. package/dist/domain/task-queue.constants.d.ts +8 -0
  287. package/dist/domain/task-queue.constants.js +9 -0
  288. package/dist/domain/task-queue.constants.js.map +1 -0
  289. package/dist/domain/task-queue.d.ts +11 -0
  290. package/dist/domain/task-queue.js +105 -0
  291. package/dist/domain/task-queue.js.map +1 -0
  292. package/dist/domain/task-queue.types.d.ts +41 -0
  293. package/dist/domain/task-queue.types.js +2 -0
  294. package/dist/domain/task-queue.types.js.map +1 -0
  295. package/dist/domain/workflow/budget.constants.d.ts +1 -0
  296. package/dist/domain/workflow/budget.constants.js +7 -0
  297. package/dist/domain/workflow/budget.constants.js.map +1 -0
  298. package/dist/domain/workflow/budget.d.ts +9 -0
  299. package/dist/domain/workflow/budget.js +69 -0
  300. package/dist/domain/workflow/budget.js.map +1 -0
  301. package/dist/domain/workflow/budget.types.d.ts +15 -0
  302. package/dist/domain/workflow/budget.types.js +2 -0
  303. package/dist/domain/workflow/budget.types.js.map +1 -0
  304. package/dist/domain/workflow/checkpoint-validation.d.ts +3 -0
  305. package/dist/domain/workflow/checkpoint-validation.js +81 -0
  306. package/dist/domain/workflow/checkpoint-validation.js.map +1 -0
  307. package/dist/domain/workflow/checkpoint-value.d.ts +2 -0
  308. package/dist/domain/workflow/checkpoint-value.js +49 -0
  309. package/dist/domain/workflow/checkpoint-value.js.map +1 -0
  310. package/dist/domain/workflow/checkpoint.d.ts +3 -0
  311. package/dist/domain/workflow/checkpoint.js +70 -0
  312. package/dist/domain/workflow/checkpoint.js.map +1 -0
  313. package/dist/domain/workflow/checkpoint.types.d.ts +40 -0
  314. package/dist/domain/workflow/checkpoint.types.js +2 -0
  315. package/dist/domain/workflow/checkpoint.types.js.map +1 -0
  316. package/dist/domain/workflow/gate-validation.d.ts +4 -0
  317. package/dist/domain/workflow/gate-validation.js +71 -0
  318. package/dist/domain/workflow/gate-validation.js.map +1 -0
  319. package/dist/domain/workflow/gates.constants.d.ts +4 -0
  320. package/dist/domain/workflow/gates.constants.js +5 -0
  321. package/dist/domain/workflow/gates.constants.js.map +1 -0
  322. package/dist/domain/workflow/gates.d.ts +7 -0
  323. package/dist/domain/workflow/gates.js +85 -0
  324. package/dist/domain/workflow/gates.js.map +1 -0
  325. package/dist/domain/workflow/gates.types.d.ts +27 -0
  326. package/dist/domain/workflow/gates.types.js +2 -0
  327. package/dist/domain/workflow/gates.types.js.map +1 -0
  328. package/dist/domain/workflow/task-runner.js +22 -3
  329. package/dist/domain/workflow/task-runner.js.map +1 -1
  330. package/dist/domain/workflow/usage-receipt.constants.d.ts +2 -0
  331. package/dist/domain/workflow/usage-receipt.constants.js +3 -0
  332. package/dist/domain/workflow/usage-receipt.constants.js.map +1 -0
  333. package/dist/domain/workflow/usage-receipt.d.ts +2 -0
  334. package/dist/domain/workflow/usage-receipt.js +18 -0
  335. package/dist/domain/workflow/usage-receipt.js.map +1 -0
  336. package/dist/domain/workflow/validation.js +6 -0
  337. package/dist/domain/workflow/validation.js.map +1 -1
  338. package/dist/domain/workflow/workflow-scheduler.js +68 -33
  339. package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
  340. package/dist/domain/workflow/workflow-state.d.ts +2 -1
  341. package/dist/domain/workflow/workflow-state.js +107 -3
  342. package/dist/domain/workflow/workflow-state.js.map +1 -1
  343. package/dist/domain/workflow.d.ts +2 -0
  344. package/dist/domain/workflow.js +1 -0
  345. package/dist/domain/workflow.js.map +1 -1
  346. package/dist/domain/workflow.types.d.ts +23 -3
  347. package/dist/domain/workflow.types.js.map +1 -1
  348. package/dist/index.d.ts +44 -5
  349. package/dist/index.js +19 -2
  350. package/dist/index.js.map +1 -1
  351. package/dist/infrastructure/artifact-store.constants.d.ts +1 -0
  352. package/dist/infrastructure/artifact-store.constants.js +2 -0
  353. package/dist/infrastructure/artifact-store.constants.js.map +1 -0
  354. package/dist/infrastructure/artifact-store.d.ts +3 -0
  355. package/dist/infrastructure/artifact-store.js +100 -0
  356. package/dist/infrastructure/artifact-store.js.map +1 -0
  357. package/dist/infrastructure/artifact-store.types.d.ts +4 -0
  358. package/dist/infrastructure/artifact-store.types.js +2 -0
  359. package/dist/infrastructure/artifact-store.types.js.map +1 -0
  360. package/dist/infrastructure/file-manifest.d.ts +6 -0
  361. package/dist/infrastructure/file-manifest.js +92 -0
  362. package/dist/infrastructure/file-manifest.js.map +1 -0
  363. package/dist/infrastructure/git/lock-inspection.constants.d.ts +4 -0
  364. package/dist/infrastructure/git/lock-inspection.constants.js +5 -0
  365. package/dist/infrastructure/git/lock-inspection.constants.js.map +1 -0
  366. package/dist/infrastructure/git/lock-inspection.d.ts +3 -0
  367. package/dist/infrastructure/git/lock-inspection.js +64 -0
  368. package/dist/infrastructure/git/lock-inspection.js.map +1 -0
  369. package/dist/infrastructure/git/lock-inspection.types.d.ts +27 -0
  370. package/dist/infrastructure/git/lock-inspection.types.js +2 -0
  371. package/dist/infrastructure/git/lock-inspection.types.js.map +1 -0
  372. package/dist/infrastructure/git/lock.d.ts +1 -0
  373. package/dist/infrastructure/git/lock.js +70 -29
  374. package/dist/infrastructure/git/lock.js.map +1 -1
  375. package/dist/infrastructure/git/process-identity.d.ts +3 -0
  376. package/dist/infrastructure/git/process-identity.js +73 -0
  377. package/dist/infrastructure/git/process-identity.js.map +1 -0
  378. package/dist/infrastructure/git/process-identity.types.d.ts +10 -0
  379. package/dist/infrastructure/git/process-identity.types.js +2 -0
  380. package/dist/infrastructure/git/process-identity.types.js.map +1 -0
  381. package/dist/infrastructure/git/verification-command.d.ts +1 -0
  382. package/dist/infrastructure/git/verification-command.js +37 -0
  383. package/dist/infrastructure/git/verification-command.js.map +1 -0
  384. package/dist/infrastructure/git/workspace-lease.js +1 -0
  385. package/dist/infrastructure/git/workspace-lease.js.map +1 -1
  386. package/dist/infrastructure/git/workspace.js +5 -1
  387. package/dist/infrastructure/git/workspace.js.map +1 -1
  388. package/dist/infrastructure/git/worktree-inspection.constants.d.ts +5 -0
  389. package/dist/infrastructure/git/worktree-inspection.constants.js +16 -0
  390. package/dist/infrastructure/git/worktree-inspection.constants.js.map +1 -0
  391. package/dist/infrastructure/git/worktree-inspection.d.ts +3 -0
  392. package/dist/infrastructure/git/worktree-inspection.js +120 -0
  393. package/dist/infrastructure/git/worktree-inspection.js.map +1 -0
  394. package/dist/infrastructure/git/worktree-inspection.types.d.ts +19 -0
  395. package/dist/infrastructure/git/worktree-inspection.types.js +2 -0
  396. package/dist/infrastructure/git/worktree-inspection.types.js.map +1 -0
  397. package/dist/infrastructure/inspection-file.constants.d.ts +1 -0
  398. package/dist/infrastructure/inspection-file.constants.js +5 -0
  399. package/dist/infrastructure/inspection-file.constants.js.map +1 -0
  400. package/dist/infrastructure/inspection-file.d.ts +1 -0
  401. package/dist/infrastructure/inspection-file.js +43 -0
  402. package/dist/infrastructure/inspection-file.js.map +1 -0
  403. package/dist/infrastructure/inspection-hash.constants.d.ts +1 -0
  404. package/dist/infrastructure/inspection-hash.constants.js +2 -0
  405. package/dist/infrastructure/inspection-hash.constants.js.map +1 -0
  406. package/dist/infrastructure/inspection-hash.d.ts +2 -0
  407. package/dist/infrastructure/inspection-hash.js +62 -0
  408. package/dist/infrastructure/inspection-hash.js.map +1 -0
  409. package/dist/infrastructure/inspection-hash.types.d.ts +5 -0
  410. package/dist/infrastructure/inspection-hash.types.js +2 -0
  411. package/dist/infrastructure/inspection-hash.types.js.map +1 -0
  412. package/dist/infrastructure/journal-retention.constants.d.ts +4 -0
  413. package/dist/infrastructure/journal-retention.constants.js +5 -0
  414. package/dist/infrastructure/journal-retention.constants.js.map +1 -0
  415. package/dist/infrastructure/journal-retention.d.ts +2 -0
  416. package/dist/infrastructure/journal-retention.js +51 -0
  417. package/dist/infrastructure/journal-retention.js.map +1 -0
  418. package/dist/infrastructure/journal.js +37 -13
  419. package/dist/infrastructure/journal.js.map +1 -1
  420. package/dist/infrastructure/opentelemetry.constants.d.ts +10 -0
  421. package/dist/infrastructure/opentelemetry.constants.js +11 -0
  422. package/dist/infrastructure/opentelemetry.constants.js.map +1 -0
  423. package/dist/infrastructure/opentelemetry.d.ts +3 -0
  424. package/dist/infrastructure/opentelemetry.js +131 -0
  425. package/dist/infrastructure/opentelemetry.js.map +1 -0
  426. package/dist/infrastructure/opentelemetry.types.d.ts +21 -0
  427. package/dist/infrastructure/opentelemetry.types.js +2 -0
  428. package/dist/infrastructure/opentelemetry.types.js.map +1 -0
  429. package/dist/infrastructure/resource-activity-inspection.d.ts +2 -0
  430. package/dist/infrastructure/resource-activity-inspection.js +152 -0
  431. package/dist/infrastructure/resource-activity-inspection.js.map +1 -0
  432. package/dist/infrastructure/resource-activity.constants.d.ts +8 -0
  433. package/dist/infrastructure/resource-activity.constants.js +26 -0
  434. package/dist/infrastructure/resource-activity.constants.js.map +1 -0
  435. package/dist/infrastructure/resource-activity.d.ts +2 -0
  436. package/dist/infrastructure/resource-activity.js +166 -0
  437. package/dist/infrastructure/resource-activity.js.map +1 -0
  438. package/dist/infrastructure/resource-activity.types.d.ts +53 -0
  439. package/dist/infrastructure/resource-activity.types.js +2 -0
  440. package/dist/infrastructure/resource-activity.types.js.map +1 -0
  441. package/dist/infrastructure/storage-inventory.constants.d.ts +6 -0
  442. package/dist/infrastructure/storage-inventory.constants.js +11 -0
  443. package/dist/infrastructure/storage-inventory.constants.js.map +1 -0
  444. package/dist/infrastructure/storage-inventory.d.ts +2 -0
  445. package/dist/infrastructure/storage-inventory.js +123 -0
  446. package/dist/infrastructure/storage-inventory.js.map +1 -0
  447. package/dist/infrastructure/storage-inventory.types.d.ts +38 -0
  448. package/dist/infrastructure/storage-inventory.types.js +2 -0
  449. package/dist/infrastructure/storage-inventory.types.js.map +1 -0
  450. package/dist/infrastructure/storage-mutation-lock.constants.d.ts +5 -0
  451. package/dist/infrastructure/storage-mutation-lock.constants.js +6 -0
  452. package/dist/infrastructure/storage-mutation-lock.constants.js.map +1 -0
  453. package/dist/infrastructure/storage-mutation-lock.d.ts +1 -0
  454. package/dist/infrastructure/storage-mutation-lock.js +21 -0
  455. package/dist/infrastructure/storage-mutation-lock.js.map +1 -0
  456. package/dist/infrastructure/storage-reservations.constants.d.ts +4 -0
  457. package/dist/infrastructure/storage-reservations.constants.js +5 -0
  458. package/dist/infrastructure/storage-reservations.constants.js.map +1 -0
  459. package/dist/infrastructure/storage-reservations.d.ts +2 -0
  460. package/dist/infrastructure/storage-reservations.js +150 -0
  461. package/dist/infrastructure/storage-reservations.js.map +1 -0
  462. package/dist/infrastructure/storage-reservations.types.d.ts +21 -0
  463. package/dist/infrastructure/storage-reservations.types.js +2 -0
  464. package/dist/infrastructure/storage-reservations.types.js.map +1 -0
  465. package/dist/infrastructure/task-queue-http.constants.d.ts +2 -0
  466. package/dist/infrastructure/task-queue-http.constants.js +3 -0
  467. package/dist/infrastructure/task-queue-http.constants.js.map +1 -0
  468. package/dist/infrastructure/task-queue-http.d.ts +4 -0
  469. package/dist/infrastructure/task-queue-http.js +158 -0
  470. package/dist/infrastructure/task-queue-http.js.map +1 -0
  471. package/dist/infrastructure/task-queue-http.types.d.ts +16 -0
  472. package/dist/infrastructure/task-queue-http.types.js +2 -0
  473. package/dist/infrastructure/task-queue-http.types.js.map +1 -0
  474. package/dist/infrastructure/task-queue.d.ts +2 -0
  475. package/dist/infrastructure/task-queue.js +134 -0
  476. package/dist/infrastructure/task-queue.js.map +1 -0
  477. package/dist/infrastructure/transfer.js +17 -0
  478. package/dist/infrastructure/transfer.js.map +1 -1
  479. package/dist/infrastructure/workflow-checkpoint.constants.d.ts +1 -0
  480. package/dist/infrastructure/workflow-checkpoint.constants.js +2 -0
  481. package/dist/infrastructure/workflow-checkpoint.constants.js.map +1 -0
  482. package/dist/infrastructure/workflow-checkpoint.d.ts +3 -0
  483. package/dist/infrastructure/workflow-checkpoint.js +77 -0
  484. package/dist/infrastructure/workflow-checkpoint.js.map +1 -0
  485. package/dist/infrastructure/workflow-checkpoint.types.d.ts +4 -0
  486. package/dist/infrastructure/workflow-checkpoint.types.js +2 -0
  487. package/dist/infrastructure/workflow-checkpoint.types.js.map +1 -0
  488. package/dist/providers/agents.d.ts +2 -0
  489. package/dist/providers/agents.js +1 -0
  490. package/dist/providers/agents.js.map +1 -1
  491. package/dist/providers/cloud.constants.d.ts +1 -0
  492. package/dist/providers/cloud.constants.js +1 -0
  493. package/dist/providers/cloud.constants.js.map +1 -1
  494. package/dist/providers/container-cache.constants.d.ts +11 -0
  495. package/dist/providers/container-cache.constants.js +9 -0
  496. package/dist/providers/container-cache.constants.js.map +1 -0
  497. package/dist/providers/container-cache.d.ts +4 -0
  498. package/dist/providers/container-cache.js +48 -0
  499. package/dist/providers/container-cache.js.map +1 -0
  500. package/dist/providers/container-cache.types.d.ts +8 -0
  501. package/dist/providers/container-cache.types.js +2 -0
  502. package/dist/providers/container-cache.types.js.map +1 -0
  503. package/dist/providers/container-isolation.d.ts +2 -0
  504. package/dist/providers/container-isolation.js +29 -0
  505. package/dist/providers/container-isolation.js.map +1 -0
  506. package/dist/providers/container-mounts.js +7 -2
  507. package/dist/providers/container-mounts.js.map +1 -1
  508. package/dist/providers/container-network.d.ts +2 -0
  509. package/dist/providers/container-network.js +14 -0
  510. package/dist/providers/container-network.js.map +1 -0
  511. package/dist/providers/container-plan.js +6 -2
  512. package/dist/providers/container-plan.js.map +1 -1
  513. package/dist/providers/container.constants.d.ts +1 -0
  514. package/dist/providers/container.constants.js +1 -0
  515. package/dist/providers/container.constants.js.map +1 -1
  516. package/dist/providers/container.js +50 -3
  517. package/dist/providers/container.js.map +1 -1
  518. package/dist/providers/container.types.d.ts +5 -0
  519. package/dist/providers/container.types.js.map +1 -1
  520. package/dist/providers/daytona-command.js +10 -6
  521. package/dist/providers/daytona-command.js.map +1 -1
  522. package/dist/providers/daytona-terminal.d.ts +3 -0
  523. package/dist/providers/daytona-terminal.js +128 -0
  524. package/dist/providers/daytona-terminal.js.map +1 -0
  525. package/dist/providers/daytona.js +15 -4
  526. package/dist/providers/daytona.js.map +1 -1
  527. package/dist/providers/diagnostic-container.d.ts +4 -0
  528. package/dist/providers/diagnostic-container.js +15 -0
  529. package/dist/providers/diagnostic-container.js.map +1 -0
  530. package/dist/providers/docker.d.ts +2 -0
  531. package/dist/providers/docker.js.map +1 -1
  532. package/dist/providers/file-batches.constants.d.ts +10 -0
  533. package/dist/providers/file-batches.constants.js +57 -0
  534. package/dist/providers/file-batches.constants.js.map +1 -0
  535. package/dist/providers/file-batches.d.ts +2 -0
  536. package/dist/providers/file-batches.js +160 -0
  537. package/dist/providers/file-batches.js.map +1 -0
  538. package/dist/providers/file-upload.constants.d.ts +1 -0
  539. package/dist/providers/file-upload.constants.js +68 -0
  540. package/dist/providers/file-upload.constants.js.map +1 -0
  541. package/dist/providers/file-upload.d.ts +2 -0
  542. package/dist/providers/file-upload.js +146 -0
  543. package/dist/providers/file-upload.js.map +1 -0
  544. package/dist/providers/firecracker-command.d.ts +5 -0
  545. package/dist/providers/firecracker-command.js +114 -0
  546. package/dist/providers/firecracker-command.js.map +1 -0
  547. package/dist/providers/firecracker-files.constants.d.ts +1 -0
  548. package/dist/providers/firecracker-files.constants.js +21 -0
  549. package/dist/providers/firecracker-files.constants.js.map +1 -0
  550. package/dist/providers/firecracker-files.d.ts +3 -0
  551. package/dist/providers/firecracker-files.js +110 -0
  552. package/dist/providers/firecracker-files.js.map +1 -0
  553. package/dist/providers/firecracker-machine.d.ts +3 -0
  554. package/dist/providers/firecracker-machine.js +155 -0
  555. package/dist/providers/firecracker-machine.js.map +1 -0
  556. package/dist/providers/firecracker.constants.d.ts +10 -0
  557. package/dist/providers/firecracker.constants.js +11 -0
  558. package/dist/providers/firecracker.constants.js.map +1 -0
  559. package/dist/providers/firecracker.d.ts +4 -0
  560. package/dist/providers/firecracker.js +103 -0
  561. package/dist/providers/firecracker.js.map +1 -0
  562. package/dist/providers/firecracker.types.d.ts +36 -0
  563. package/dist/providers/firecracker.types.js +2 -0
  564. package/dist/providers/firecracker.types.js.map +1 -0
  565. package/dist/providers/local.js +2 -1
  566. package/dist/providers/local.js.map +1 -1
  567. package/dist/providers/podman.d.ts +2 -0
  568. package/dist/providers/podman.js.map +1 -1
  569. package/dist/providers/terminal-bridge.d.ts +14 -0
  570. package/dist/providers/terminal-bridge.js +100 -0
  571. package/dist/providers/terminal-bridge.js.map +1 -0
  572. package/dist/providers/vercel-directory.d.ts +2 -0
  573. package/dist/providers/vercel-directory.js +7 -0
  574. package/dist/providers/vercel-directory.js.map +1 -0
  575. package/dist/providers/vercel-files.js +3 -2
  576. package/dist/providers/vercel-files.js.map +1 -1
  577. package/dist/providers/vercel-network.d.ts +2 -0
  578. package/dist/providers/vercel-network.js +18 -0
  579. package/dist/providers/vercel-network.js.map +1 -0
  580. package/dist/providers/vercel.d.ts +1 -0
  581. package/dist/providers/vercel.js +8 -2
  582. package/dist/providers/vercel.js.map +1 -1
  583. package/dist/providers/vercel.types.d.ts +2 -0
  584. package/dist/providers/vercel.types.js.map +1 -1
  585. package/dist/providers/versions.constants.d.ts +1 -0
  586. package/dist/providers/versions.constants.js +1 -0
  587. package/dist/providers/versions.constants.js.map +1 -1
  588. package/package.json +16 -1
@@ -0,0 +1,48 @@
1
+ import { createHash } from "node:crypto";
2
+ import { realpath } from "node:fs/promises";
3
+ import { posix } from "node:path";
4
+ import { invariant } from "../domain/errors.js";
5
+ import { cacheDefaults } from "./container-cache.constants.js";
6
+ export function validateCaches(config) {
7
+ const names = new Set();
8
+ for (const cache of config.caches ?? []) {
9
+ invariant(typeof cache.name === "string" &&
10
+ cacheDefaults.namePattern.test(cache.name), "Cache names must start with a lowercase letter and contain at most 48 lowercase letters, digits or hyphens");
11
+ invariant(!names.has(cache.name), `Duplicate cache name: ${cache.name}`);
12
+ invariant(typeof cache.key === "string" &&
13
+ cache.key.trim().length > 0 &&
14
+ cache.key.length <= cacheDefaults.maximumKeyLength, "Cache keys must be nonempty strings of at most 1024 characters");
15
+ names.add(cache.name);
16
+ }
17
+ if (!names.size)
18
+ return;
19
+ for (const volume of config.volumes ?? []) {
20
+ const target = posix.resolve("/workspace", volume.target.replaceAll("\\", "/"));
21
+ invariant(!(target === cacheDefaults.root ||
22
+ target.startsWith(cacheDefaults.root + "/") ||
23
+ cacheDefaults.root.startsWith(target.replace(/\/$/, "") + "/")), "Explicit volumes must not overlap dependency caches");
24
+ }
25
+ }
26
+ export async function cacheMounts(caches, repository, image, user) {
27
+ if (!caches.length)
28
+ return [];
29
+ const canonical = await realpath(repository);
30
+ return caches.map(({ name, key }) => {
31
+ const digest = createHash("sha256")
32
+ .update(JSON.stringify([
33
+ cacheDefaults.version,
34
+ canonical,
35
+ image,
36
+ user.uid,
37
+ user.gid,
38
+ name,
39
+ key,
40
+ ]))
41
+ .digest("hex");
42
+ return {
43
+ volume: `outpost-cache-${name}-${digest}`,
44
+ target: `${cacheDefaults.root}/${name}`,
45
+ };
46
+ });
47
+ }
48
+ //# sourceMappingURL=container-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-cache.js","sourceRoot":"","sources":["../../src/providers/container-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAO/D,MAAM,UAAU,cAAc,CAAC,MAAwB;IACrD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACxC,SAAS,CACP,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAC5B,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAC5C,4GAA4G,CAC7G,CAAC;QACF,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,yBAAyB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,SAAS,CACP,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;YAC3B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC3B,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC,gBAAgB,EACpD,gEAAgE,CACjE,CAAC;QACF,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI;QAAE,OAAO;IACxB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAC1B,YAAY,EACZ,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CACpC,CAAC;QACF,SAAS,CACP,CAAC,CACC,MAAM,KAAK,aAAa,CAAC,IAAI;YAC7B,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,GAAG,GAAG,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAC/D,EACD,qDAAqD,CACtD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAkC,EAClC,UAAkB,EAClB,KAAa,EACb,IAAmB;IAEnB,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;QAClC,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC;aAChC,MAAM,CACL,IAAI,CAAC,SAAS,CAAC;YACb,aAAa,CAAC,OAAO;YACrB,SAAS;YACT,KAAK;YACL,IAAI,CAAC,GAAG;YACR,IAAI,CAAC,GAAG;YACR,IAAI;YACJ,GAAG;SACJ,CAAC,CACH;aACA,MAAM,CAAC,KAAK,CAAC,CAAC;QACjB,OAAO;YACL,MAAM,EAAE,iBAAiB,IAAI,IAAI,MAAM,EAAE;YACzC,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,IAAI,IAAI,EAAE;SACxC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { realpath } from \"node:fs/promises\";\nimport { posix } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { cacheDefaults } from \"./container-cache.constants.ts\";\nimport type {\n DependencyCache,\n ContainerCacheMount,\n} from \"./container-cache.types.ts\";\nimport type { ContainerOptions, ContainerUser } from \"./container.types.ts\";\n\nexport function validateCaches(config: ContainerOptions): void {\n const names = new Set<string>();\n for (const cache of config.caches ?? []) {\n invariant(\n typeof cache.name === \"string\" &&\n cacheDefaults.namePattern.test(cache.name),\n \"Cache names must start with a lowercase letter and contain at most 48 lowercase letters, digits or hyphens\",\n );\n invariant(!names.has(cache.name), `Duplicate cache name: ${cache.name}`);\n invariant(\n typeof cache.key === \"string\" &&\n cache.key.trim().length > 0 &&\n cache.key.length <= cacheDefaults.maximumKeyLength,\n \"Cache keys must be nonempty strings of at most 1024 characters\",\n );\n names.add(cache.name);\n }\n if (!names.size) return;\n for (const volume of config.volumes ?? []) {\n const target = posix.resolve(\n \"/workspace\",\n volume.target.replaceAll(\"\\\\\", \"/\"),\n );\n invariant(\n !(\n target === cacheDefaults.root ||\n target.startsWith(cacheDefaults.root + \"/\") ||\n cacheDefaults.root.startsWith(target.replace(/\\/$/, \"\") + \"/\")\n ),\n \"Explicit volumes must not overlap dependency caches\",\n );\n }\n}\n\nexport async function cacheMounts(\n caches: readonly DependencyCache[],\n repository: string,\n image: string,\n user: ContainerUser,\n): Promise<ContainerCacheMount[]> {\n if (!caches.length) return [];\n const canonical = await realpath(repository);\n return caches.map(({ name, key }) => {\n const digest = createHash(\"sha256\")\n .update(\n JSON.stringify([\n cacheDefaults.version,\n canonical,\n image,\n user.uid,\n user.gid,\n name,\n key,\n ]),\n )\n .digest(\"hex\");\n return {\n volume: `outpost-cache-${name}-${digest}`,\n target: `${cacheDefaults.root}/${name}`,\n };\n });\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export interface DependencyCache {
2
+ readonly name: string;
3
+ readonly key: string;
4
+ }
5
+ export interface ContainerCacheMount {
6
+ readonly volume: string;
7
+ readonly target: string;
8
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=container-cache.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-cache.types.js","sourceRoot":"","sources":["../../src/providers/container-cache.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface DependencyCache {\n readonly name: string;\n readonly key: string;\n}\n\nexport interface ContainerCacheMount {\n readonly volume: string;\n readonly target: string;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { SandboxContext } from "../domain/sandbox.types.ts";
2
+ export declare function validateIsolatedMount(context: SandboxContext, source: string, target: string): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { isAbsolute, relative, posix } from "node:path";
3
+ import { invariant } from "../domain/errors.js";
4
+ function contains(parent, child) {
5
+ const offset = relative(parent, child);
6
+ return (!isAbsolute(offset) &&
7
+ offset !== ".." &&
8
+ !offset.startsWith("../") &&
9
+ !offset.startsWith("..\\"));
10
+ }
11
+ export async function validateIsolatedMount(context, source, target) {
12
+ const canonical = await realpath(source);
13
+ for (const path of [
14
+ context.repository,
15
+ context.directory,
16
+ ...context.gitDirectories,
17
+ ]) {
18
+ const protectedPath = await realpath(path);
19
+ invariant(!contains(canonical, protectedPath) &&
20
+ !contains(protectedPath, canonical), "Isolated repository mounts must not expose the host repository, workspace or Git metadata");
21
+ }
22
+ for (const protectedPath of ["/outpost", "/tmp"]) {
23
+ const offset = posix.relative(protectedPath, target);
24
+ const reverse = posix.relative(target, protectedPath);
25
+ invariant((offset === ".." || offset.startsWith("../")) &&
26
+ (reverse === ".." || reverse.startsWith("../")), "Isolated repository mounts must not overlap workspace or control directories");
27
+ }
28
+ }
29
+ //# sourceMappingURL=container-isolation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-isolation.js","sourceRoot":"","sources":["../../src/providers/container-isolation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,SAAS,QAAQ,CAAC,MAAc,EAAE,KAAa;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,CACL,CAAC,UAAU,CAAC,MAAM,CAAC;QACnB,MAAM,KAAK,IAAI;QACf,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;QACzB,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAC3B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAuB,EACvB,MAAc,EACd,MAAc;IAEd,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI;QACjB,OAAO,CAAC,UAAU;QAClB,OAAO,CAAC,SAAS;QACjB,GAAG,OAAO,CAAC,cAAc;KAC1B,EAAE,CAAC;QACF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3C,SAAS,CACP,CAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;YACjC,CAAC,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC,EACrC,2FAA2F,CAC5F,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,aAAa,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACtD,SAAS,CACP,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC3C,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EACjD,8EAA8E,CAC/E,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { realpath } from \"node:fs/promises\";\nimport { isAbsolute, relative, posix } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxContext } from \"../domain/sandbox.types.ts\";\n\nfunction contains(parent: string, child: string): boolean {\n const offset = relative(parent, child);\n return (\n !isAbsolute(offset) &&\n offset !== \"..\" &&\n !offset.startsWith(\"../\") &&\n !offset.startsWith(\"..\\\\\")\n );\n}\n\nexport async function validateIsolatedMount(\n context: SandboxContext,\n source: string,\n target: string,\n): Promise<void> {\n const canonical = await realpath(source);\n for (const path of [\n context.repository,\n context.directory,\n ...context.gitDirectories,\n ]) {\n const protectedPath = await realpath(path);\n invariant(\n !contains(canonical, protectedPath) &&\n !contains(protectedPath, canonical),\n \"Isolated repository mounts must not expose the host repository, workspace or Git metadata\",\n );\n }\n for (const protectedPath of [\"/outpost\", \"/tmp\"]) {\n const offset = posix.relative(protectedPath, target);\n const reverse = posix.relative(target, protectedPath);\n invariant(\n (offset === \"..\" || offset.startsWith(\"../\")) &&\n (reverse === \"..\" || reverse.startsWith(\"../\")),\n \"Isolated repository mounts must not overlap workspace or control directories\",\n );\n }\n}\n"]}
@@ -2,6 +2,7 @@ import { stat } from "node:fs/promises";
2
2
  import { isAbsolute, posix, relative } from "node:path";
3
3
  import { invariant, OutpostError } from "../domain/errors.js";
4
4
  import { expandPath } from "../infrastructure/files.js";
5
+ import { validateIsolatedMount } from "./container-isolation.js";
5
6
  export async function containerMounts(context, config, platform, root, home) {
6
7
  const env = {
7
8
  ...context.variables,
@@ -10,8 +11,10 @@ export async function containerMounts(context, config, platform, root, home) {
10
11
  GIT_CONFIG_KEY_0: "safe.directory",
11
12
  GIT_CONFIG_VALUE_0: "*",
12
13
  };
13
- const internal = [{ source: context.directory, target: root }];
14
- if (context.gitDirectories.length) {
14
+ const internal = config.repositoryMode === "isolated"
15
+ ? []
16
+ : [{ source: context.directory, target: root }];
17
+ if (config.repositoryMode !== "isolated" && context.gitDirectories.length) {
15
18
  const common = context.gitDirectories.at(-1);
16
19
  const offset = relative(common, context.gitDirectories[0]);
17
20
  const nested = !isAbsolute(offset) &&
@@ -46,6 +49,8 @@ export async function containerMounts(context, config, platform, root, home) {
46
49
  : destination.startsWith("~/")
47
50
  ? posix.resolve(home, destination.slice(2))
48
51
  : posix.resolve(root, destination);
52
+ if (config.repositoryMode === "isolated")
53
+ await validateIsolatedMount(context, source, target);
49
54
  if (info.isFile() && !internal.includes(volume)) {
50
55
  const parent = posix.dirname(target);
51
56
  invariant(parent === home || parent.startsWith(home + "/"), "File mounts must live inside the agent home; mount the containing directory for other destinations");
@@ -1 +1 @@
1
- {"version":3,"file":"container-mounts.js","sourceRoot":"","sources":["../../src/providers/container-mounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { isAbsolute, posix, relative } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxContext, Volume } from \"../domain/sandbox.types.ts\";\nimport { expandPath } from \"../infrastructure/files.ts\";\nimport type { ContainerMounts, ContainerOptions } from \"./container.types.ts\";\n\nexport async function containerMounts(\n context: SandboxContext,\n config: ContainerOptions,\n platform: NodeJS.Platform,\n root: string,\n home: string,\n): Promise<ContainerMounts> {\n const env: Record<string, string> = {\n ...context.variables,\n HOME: home,\n GIT_CONFIG_COUNT: \"1\",\n GIT_CONFIG_KEY_0: \"safe.directory\",\n GIT_CONFIG_VALUE_0: \"*\",\n };\n const internal: Volume[] = [{ source: context.directory, target: root }];\n if (context.gitDirectories.length) {\n const common = context.gitDirectories.at(-1)!;\n const offset = relative(common, context.gitDirectories[0]!);\n const nested =\n !isAbsolute(offset) &&\n offset !== \"..\" &&\n !offset.startsWith(\"..\\\\\") &&\n !offset.startsWith(\"../\");\n internal.push({\n source: common,\n target: \"/outpost/git/common\",\n });\n if (!nested)\n internal.push({\n source: context.gitDirectories[0]!,\n target: \"/outpost/git/worktree\",\n });\n env.GIT_DIR = nested\n ? posix.join(\"/outpost/git/common\", offset.replaceAll(\"\\\\\", \"/\"))\n : \"/outpost/git/worktree\";\n env.GIT_COMMON_DIR = \"/outpost/git/common\";\n env.GIT_WORK_TREE = root;\n }\n const volumes: string[] = [];\n const fileParents = new Set<string>();\n for (const volume of [...internal, ...(config.volumes ?? [])]) {\n const source = expandPath(volume.source, context.repository);\n const info = await stat(source).catch(() => undefined);\n if (!info)\n throw new OutpostError(\n \"provider\",\n `Mount source is unavailable: ${source}`,\n );\n const destination = volume.target.replaceAll(\"\\\\\", \"/\");\n const target =\n destination === \"~\"\n ? home\n : destination.startsWith(\"~/\")\n ? posix.resolve(home, destination.slice(2))\n : posix.resolve(root, destination);\n if (info.isFile() && !internal.includes(volume)) {\n const parent = posix.dirname(target);\n invariant(\n parent === home || parent.startsWith(home + \"/\"),\n \"File mounts must live inside the agent home; mount the containing directory for other destinations\",\n );\n for (let folder = parent; folder !== home; folder = posix.dirname(folder))\n fileParents.add(folder);\n }\n invariant(\n !source.includes(\",\") && !target.includes(\",\"),\n \"Mount paths cannot contain commas\",\n );\n if (config.label === false || platform !== \"linux\")\n volumes.push(\n \"--mount\",\n `type=bind,source=${source},target=${target}${volume.readOnly ? \",readonly\" : \"\"}`,\n );\n else\n volumes.push(\n \"--volume\",\n `${source}:${target}:${volume.readOnly ? \"ro,\" : \"\"}${config.label ?? \"z\"}`,\n );\n }\n\n return { env, volumes, fileParents };\n}\n"]}
1
+ {"version":3,"file":"container-mounts.js","sourceRoot":"","sources":["../../src/providers/container-mounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { isAbsolute, posix, relative } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxContext, Volume } from \"../domain/sandbox.types.ts\";\nimport { expandPath } from \"../infrastructure/files.ts\";\nimport { validateIsolatedMount } from \"./container-isolation.ts\";\nimport type { ContainerMounts, ContainerOptions } from \"./container.types.ts\";\n\nexport async function containerMounts(\n context: SandboxContext,\n config: ContainerOptions,\n platform: NodeJS.Platform,\n root: string,\n home: string,\n): Promise<ContainerMounts> {\n const env: Record<string, string> = {\n ...context.variables,\n HOME: home,\n GIT_CONFIG_COUNT: \"1\",\n GIT_CONFIG_KEY_0: \"safe.directory\",\n GIT_CONFIG_VALUE_0: \"*\",\n };\n const internal: Volume[] =\n config.repositoryMode === \"isolated\"\n ? []\n : [{ source: context.directory, target: root }];\n if (config.repositoryMode !== \"isolated\" && context.gitDirectories.length) {\n const common = context.gitDirectories.at(-1)!;\n const offset = relative(common, context.gitDirectories[0]!);\n const nested =\n !isAbsolute(offset) &&\n offset !== \"..\" &&\n !offset.startsWith(\"..\\\\\") &&\n !offset.startsWith(\"../\");\n internal.push({\n source: common,\n target: \"/outpost/git/common\",\n });\n if (!nested)\n internal.push({\n source: context.gitDirectories[0]!,\n target: \"/outpost/git/worktree\",\n });\n env.GIT_DIR = nested\n ? posix.join(\"/outpost/git/common\", offset.replaceAll(\"\\\\\", \"/\"))\n : \"/outpost/git/worktree\";\n env.GIT_COMMON_DIR = \"/outpost/git/common\";\n env.GIT_WORK_TREE = root;\n }\n const volumes: string[] = [];\n const fileParents = new Set<string>();\n for (const volume of [...internal, ...(config.volumes ?? [])]) {\n const source = expandPath(volume.source, context.repository);\n const info = await stat(source).catch(() => undefined);\n if (!info)\n throw new OutpostError(\n \"provider\",\n `Mount source is unavailable: ${source}`,\n );\n const destination = volume.target.replaceAll(\"\\\\\", \"/\");\n const target =\n destination === \"~\"\n ? home\n : destination.startsWith(\"~/\")\n ? posix.resolve(home, destination.slice(2))\n : posix.resolve(root, destination);\n if (config.repositoryMode === \"isolated\")\n await validateIsolatedMount(context, source, target);\n if (info.isFile() && !internal.includes(volume)) {\n const parent = posix.dirname(target);\n invariant(\n parent === home || parent.startsWith(home + \"/\"),\n \"File mounts must live inside the agent home; mount the containing directory for other destinations\",\n );\n for (let folder = parent; folder !== home; folder = posix.dirname(folder))\n fileParents.add(folder);\n }\n invariant(\n !source.includes(\",\") && !target.includes(\",\"),\n \"Mount paths cannot contain commas\",\n );\n if (config.label === false || platform !== \"linux\")\n volumes.push(\n \"--mount\",\n `type=bind,source=${source},target=${target}${volume.readOnly ? \",readonly\" : \"\"}`,\n );\n else\n volumes.push(\n \"--volume\",\n `${source}:${target}:${volume.readOnly ? \"ro,\" : \"\"}${config.label ?? \"z\"}`,\n );\n }\n\n return { env, volumes, fileParents };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { ContainerOptions } from "./container.types.ts";
2
+ export declare function containerNetworks(options: ContainerOptions): readonly string[];
@@ -0,0 +1,14 @@
1
+ import { validateEgress } from "../domain/egress.js";
2
+ import { invariant } from "../domain/errors.js";
3
+ export function containerNetworks(options) {
4
+ const policy = validateEgress(options.egress);
5
+ const networks = typeof options.networks === "string"
6
+ ? [options.networks]
7
+ : [...(options.networks ?? [])];
8
+ if (!policy)
9
+ return networks;
10
+ invariant(policy.mode === "deny-all", "Docker/Podman cannot enforce egress allowlists; use Vercel or an externally managed firewall");
11
+ invariant(networks.every((network) => network === "none"), "egress deny-all conflicts with configured networks");
12
+ return ["none"];
13
+ }
14
+ //# sourceMappingURL=container-network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-network.js","sourceRoot":"","sources":["../../src/providers/container-network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,MAAM,UAAU,iBAAiB,CAC/B,OAAyB;IAEzB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAClC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACpB,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM;QAAE,OAAO,QAAQ,CAAC;IAC7B,SAAS,CACP,MAAM,CAAC,IAAI,KAAK,UAAU,EAC1B,8FAA8F,CAC/F,CAAC;IACF,SAAS,CACP,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,EAC/C,oDAAoD,CACrD,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC","sourcesContent":["import { validateEgress } from \"../domain/egress.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function containerNetworks(\n options: ContainerOptions,\n): readonly string[] {\n const policy = validateEgress(options.egress);\n const networks =\n typeof options.networks === \"string\"\n ? [options.networks]\n : [...(options.networks ?? [])];\n if (!policy) return networks;\n invariant(\n policy.mode === \"deny-all\",\n \"Docker/Podman cannot enforce egress allowlists; use Vercel or an externally managed firewall\",\n );\n invariant(\n networks.every((network) => network === \"none\"),\n \"egress deny-all conflicts with configured networks\",\n );\n return [\"none\"];\n}\n"]}
@@ -18,10 +18,14 @@ export function containerPlan({ config, engine, user, root, name, image, volumes
18
18
  ]
19
19
  : []),
20
20
  "--workdir",
21
- root,
21
+ config.repositoryMode === "isolated" ? "/" : root,
22
22
  "--cap-drop",
23
23
  "ALL",
24
- ...(fileParents.size ? ["--cap-add", "CHOWN"] : []),
24
+ ...(fileParents.size ||
25
+ config.caches?.length ||
26
+ config.repositoryMode === "isolated"
27
+ ? ["--cap-add", "CHOWN"]
28
+ : []),
25
29
  "--security-opt",
26
30
  "no-new-privileges",
27
31
  "--tmpfs",
@@ -1 +1 @@
1
- {"version":3,"file":"container-plan.js","sourceRoot":"","sources":["../../src/providers/container-plan.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,GACU;IACrB,MAAM,QAAQ,GACZ,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACjC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;QACnB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG;QACX,QAAQ;QACR,QAAQ;QACR,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;QACzB,GAAG,CAAC,MAAM,KAAK,QAAQ;YACvB,MAAM,CAAC,MAAM,KAAK,KAAK;YACvB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC;YACvD,CAAC,CAAC;gBACE,UAAU;gBACV,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;aACpE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,WAAW;QACX,IAAI;QACJ,YAAY;QACZ,KAAK;QACL,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,gBAAgB;QAChB,mBAAmB;QACnB,SAAS;QACT,MAAM,KAAK,QAAQ;YACjB,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,sBAAsB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY;QAC5G,GAAG,OAAO;QACV,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3E,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACnE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,cAAc;QACd,OAAO;QACP,KAAK;QACL,UAAU;KACX,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { ContainerPlanOptions } from \"./container.types.ts\";\n\nexport function containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n}: ContainerPlanOptions): string[] {\n const networks =\n typeof config.networks === \"string\"\n ? [config.networks]\n : (config.networks ?? []);\n const args = [\n \"create\",\n \"--name\",\n name,\n \"--init\",\n \"--user\",\n `${user.uid}:${user.gid}`,\n ...(engine === \"podman\" &&\n config.userns !== false &&\n (process.getuid?.() !== 0 || config.userns === \"keep-id\")\n ? [\n \"--userns\",\n config.user ? `keep-id:uid=${user.uid},gid=${user.gid}` : \"keep-id\",\n ]\n : []),\n \"--workdir\",\n root,\n \"--cap-drop\",\n \"ALL\",\n ...(fileParents.size ? [\"--cap-add\", \"CHOWN\"] : []),\n \"--security-opt\",\n \"no-new-privileges\",\n \"--tmpfs\",\n engine === \"podman\"\n ? \"/home/agent:rw,mode=1777\"\n : `/home/agent:rw,uid=${fileParents.size ? 0 : user.uid},gid=${fileParents.size ? 0 : user.gid},mode=0700`,\n ...volumes,\n ...networks.flatMap((network) => [\"--network\", network]),\n ...(config.groups ?? []).flatMap((group) => [\"--group-add\", String(group)]),\n ...(config.devices ?? []).flatMap((device) => [\"--device\", device]),\n ...(config.cpus ? [\"--cpus\", String(config.cpus)] : []),\n ...(config.memoryMb ? [\"--memory\", `${config.memoryMb}m`] : []),\n \"--entrypoint\",\n \"sleep\",\n image,\n \"infinity\",\n ];\n\n return args;\n}\n"]}
1
+ {"version":3,"file":"container-plan.js","sourceRoot":"","sources":["../../src/providers/container-plan.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,GACU;IACrB,MAAM,QAAQ,GACZ,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACjC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;QACnB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG;QACX,QAAQ;QACR,QAAQ;QACR,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;QACzB,GAAG,CAAC,MAAM,KAAK,QAAQ;YACvB,MAAM,CAAC,MAAM,KAAK,KAAK;YACvB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC;YACvD,CAAC,CAAC;gBACE,UAAU;gBACV,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;aACpE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,WAAW;QACX,MAAM,CAAC,cAAc,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;QACjD,YAAY;QACZ,KAAK;QACL,GAAG,CAAC,WAAW,CAAC,IAAI;YACpB,MAAM,CAAC,MAAM,EAAE,MAAM;YACrB,MAAM,CAAC,cAAc,KAAK,UAAU;YAClC,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC;QACP,gBAAgB;QAChB,mBAAmB;QACnB,SAAS;QACT,MAAM,KAAK,QAAQ;YACjB,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,sBAAsB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY;QAC5G,GAAG,OAAO;QACV,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3E,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACnE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,cAAc;QACd,OAAO;QACP,KAAK;QACL,UAAU;KACX,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { ContainerPlanOptions } from \"./container.types.ts\";\n\nexport function containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n}: ContainerPlanOptions): string[] {\n const networks =\n typeof config.networks === \"string\"\n ? [config.networks]\n : (config.networks ?? []);\n const args = [\n \"create\",\n \"--name\",\n name,\n \"--init\",\n \"--user\",\n `${user.uid}:${user.gid}`,\n ...(engine === \"podman\" &&\n config.userns !== false &&\n (process.getuid?.() !== 0 || config.userns === \"keep-id\")\n ? [\n \"--userns\",\n config.user ? `keep-id:uid=${user.uid},gid=${user.gid}` : \"keep-id\",\n ]\n : []),\n \"--workdir\",\n config.repositoryMode === \"isolated\" ? \"/\" : root,\n \"--cap-drop\",\n \"ALL\",\n ...(fileParents.size ||\n config.caches?.length ||\n config.repositoryMode === \"isolated\"\n ? [\"--cap-add\", \"CHOWN\"]\n : []),\n \"--security-opt\",\n \"no-new-privileges\",\n \"--tmpfs\",\n engine === \"podman\"\n ? \"/home/agent:rw,mode=1777\"\n : `/home/agent:rw,uid=${fileParents.size ? 0 : user.uid},gid=${fileParents.size ? 0 : user.gid},mode=0700`,\n ...volumes,\n ...networks.flatMap((network) => [\"--network\", network]),\n ...(config.groups ?? []).flatMap((group) => [\"--group-add\", String(group)]),\n ...(config.devices ?? []).flatMap((device) => [\"--device\", device]),\n ...(config.cpus ? [\"--cpus\", String(config.cpus)] : []),\n ...(config.memoryMb ? [\"--memory\", `${config.memoryMb}m`] : []),\n \"--entrypoint\",\n \"sleep\",\n image,\n \"infinity\",\n ];\n\n return args;\n}\n"]}
@@ -5,6 +5,7 @@ export declare const containerDefaults: Readonly<{
5
5
  cleanupMs: 10000;
6
6
  retainBytes: 65536;
7
7
  root: "/workspace";
8
+ isolatedRoot: "/tmp/outpost/workspace";
8
9
  home: "/home/agent";
9
10
  minimumMemoryMb: 64;
10
11
  }>;
@@ -5,6 +5,7 @@ export const containerDefaults = Object.freeze({
5
5
  cleanupMs: 10_000,
6
6
  retainBytes: 65_536,
7
7
  root: "/workspace",
8
+ isolatedRoot: "/tmp/outpost/workspace",
8
9
  home: "/home/agent",
9
10
  minimumMemoryMb: 64,
10
11
  });
@@ -1 +1 @@
1
- {"version":3,"file":"container.constants.js","sourceRoot":"","sources":["../../src/providers/container.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,UAAU,EAAE,MAAM;IAClB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,MAAM;IACnB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,aAAa;IACnB,eAAe,EAAE,EAAE;CACpB,CAAC,CAAC","sourcesContent":["export const containerDefaults = Object.freeze({\n uid: 1000,\n gid: 1000,\n deadlineMs: 60_000,\n cleanupMs: 10_000,\n retainBytes: 65_536,\n root: \"/workspace\",\n home: \"/home/agent\",\n minimumMemoryMb: 64,\n});\n"]}
1
+ {"version":3,"file":"container.constants.js","sourceRoot":"","sources":["../../src/providers/container.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,UAAU,EAAE,MAAM;IAClB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,MAAM;IACnB,IAAI,EAAE,YAAY;IAClB,YAAY,EAAE,wBAAwB;IACtC,IAAI,EAAE,aAAa;IACnB,eAAe,EAAE,EAAE;CACpB,CAAC,CAAC","sourcesContent":["export const containerDefaults = Object.freeze({\n uid: 1000,\n gid: 1000,\n deadlineMs: 60_000,\n cleanupMs: 10_000,\n retainBytes: 65_536,\n root: \"/workspace\",\n isolatedRoot: \"/tmp/outpost/workspace\",\n home: \"/home/agent\",\n minimumMemoryMb: 64,\n});\n"]}
@@ -1,9 +1,12 @@
1
1
  import { execFileSync } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { basename } from "node:path";
4
+ import { containerNetworks } from "./container-network.js";
4
5
  import { invariant } from "../domain/errors.js";
5
6
  import { executeProcess, quote, requireSuccess, } from "../infrastructure/process.js";
6
7
  import { registerCleanup } from "../infrastructure/shutdown.js";
8
+ import { cacheMounts, validateCaches } from "./container-cache.js";
9
+ import { cacheCreateOptions, cacheDefaults, } from "./container-cache.constants.js";
7
10
  import { containerCommand } from "./container-command.js";
8
11
  import { containerFiles } from "./container-files.js";
9
12
  import { containerMounts } from "./container-mounts.js";
@@ -16,7 +19,15 @@ export function imageName(repository) {
16
19
  .replace(/[^a-z0-9_.-]/g, "-") || "workspace"}`;
17
20
  }
18
21
  export function containerProvider(engine, options = {}, executor = executeProcess, platform = process.platform) {
19
- const config = { ...options };
22
+ const config = {
23
+ ...options,
24
+ networks: containerNetworks(options),
25
+ caches: (options.caches ?? []).map((cache) => ({ ...cache })),
26
+ };
27
+ invariant(config.repositoryMode === undefined ||
28
+ config.repositoryMode === "mounted" ||
29
+ config.repositoryMode === "isolated", "repositoryMode must be mounted or isolated");
30
+ validateCaches(config);
20
31
  if (config.cpus !== undefined)
21
32
  invariant(Number.isFinite(config.cpus) && config.cpus > 0, "cpus must be positive");
22
33
  if (config.memoryMb !== undefined)
@@ -24,7 +35,7 @@ export function containerProvider(engine, options = {}, executor = executeProces
24
35
  config.memoryMb >= containerDefaults.minimumMemoryMb, "memoryMb must be at least 64");
25
36
  return {
26
37
  name: engine,
27
- placement: "mounted",
38
+ placement: config.repositoryMode === "isolated" ? "remote" : "mounted",
28
39
  variables: { ...config.variables },
29
40
  async acquire(context) {
30
41
  context.signal?.throwIfAborted();
@@ -45,8 +56,13 @@ export function containerProvider(engine, options = {}, executor = executeProces
45
56
  ...extra,
46
57
  }, executor);
47
58
  await containerPreflight(engine, platform, call, config, image, user);
48
- const root = containerDefaults.root, home = containerDefaults.home;
59
+ const root = config.repositoryMode === "isolated"
60
+ ? containerDefaults.isolatedRoot
61
+ : containerDefaults.root, home = containerDefaults.home;
49
62
  const { env, volumes, fileParents } = await containerMounts(context, config, platform, root, home);
63
+ const caches = await cacheMounts(config.caches ?? [], context.repository, image, user);
64
+ for (const cache of caches)
65
+ volumes.push("--volume", `${cache.volume}:${cache.target}:nocopy`);
50
66
  const args = containerPlan({
51
67
  config,
52
68
  engine,
@@ -72,10 +88,31 @@ export function containerProvider(engine, options = {}, executor = executeProces
72
88
  return releasing;
73
89
  };
74
90
  try {
91
+ for (const cache of caches)
92
+ await call([
93
+ "volume",
94
+ "create",
95
+ ...cacheCreateOptions[engine],
96
+ "--label",
97
+ `${cacheDefaults.label}=true`,
98
+ cache.volume,
99
+ ], context.signal ? { signal: context.signal } : {});
75
100
  await call(args, {
76
101
  ...(context.signal ? { signal: context.signal } : {}),
77
102
  });
78
103
  await call(["start", name], context.signal ? { signal: context.signal } : {});
104
+ for (const cache of caches) {
105
+ await call([
106
+ "exec",
107
+ "--user",
108
+ "0:0",
109
+ name,
110
+ "chown",
111
+ `${user.uid}:${user.gid}`,
112
+ cache.target,
113
+ ], context.signal ? { signal: context.signal } : {});
114
+ await call(["exec", name, "chmod", "700", cache.target], context.signal ? { signal: context.signal } : {});
115
+ }
79
116
  for (const parent of fileParents)
80
117
  await call([
81
118
  "exec",
@@ -96,6 +133,16 @@ export function containerProvider(engine, options = {}, executor = executeProces
96
133
  `${user.uid}:${user.gid}`,
97
134
  home,
98
135
  ]);
136
+ if (config.repositoryMode === "isolated")
137
+ await call([
138
+ "exec",
139
+ "--user",
140
+ "0:0",
141
+ name,
142
+ "sh",
143
+ "-c",
144
+ `mkdir -p ${quote(root)} && chmod 700 ${quote(root)} /tmp/outpost && chown ${user.uid}:${user.gid} ${quote(root)} /tmp/outpost`,
145
+ ], context.signal ? { signal: context.signal } : {});
99
146
  await call([
100
147
  "exec",
101
148
  name,
@@ -1 +1 @@
1
- {"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/providers/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EACL,cAAc,EACd,KAAK,EACL,cAAc,GACf,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAK7D,MAAM,UAAU,SAAS,CAAC,UAAkB;IAC1C,OAAO,WACL,QAAQ,CAAC,UAAU,CAAC;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,IAAI,WACtC,EAAE,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAuB,EACvB,UAA4B,EAAE,EAC9B,WAAqB,cAAc,EACnC,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAC3B,SAAS,CACP,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,EAC/C,uBAAuB,CACxB,CAAC;IACJ,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;QAC/B,SAAS,CACP,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC;YACnC,MAAM,CAAC,QAAQ,IAAI,iBAAiB,CAAC,eAAe,EACtD,8BAA8B,CAC/B,CAAC;IACJ,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE;QAClC,KAAK,CAAC,OAAO,CAAC,OAAO;YACnB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,WAAW,UAAU,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI;gBAC1B,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,iBAAiB,CAAC,GAAG;gBAChD,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,iBAAiB,CAAC,GAAG;aACjD,CAAC;YACF,SAAS,CACP,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBACxB,IAAI,CAAC,GAAG,IAAI,CAAC;gBACb,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1B,IAAI,CAAC,GAAG,IAAI,CAAC,EACf,wBAAwB,CACzB,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,IAAuB,EAAE,QAA0B,EAAE,EAAE,EAAE,CACrE,cAAc,CACZ;gBACE,UAAU,EAAE,MAAM;gBAClB,SAAS,EAAE,IAAI;gBACf,UAAU,EAAE,iBAAiB,CAAC,UAAU;gBACxC,GAAG,KAAK;aACT,EACD,QAAQ,CACT,CAAC;YACJ,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACtE,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,EACjC,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC;YAChC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CACzD,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,IAAI,CACL,CAAC;YACF,MAAM,IAAI,GAAG,aAAa,CAAC;gBACzB,MAAM;gBACN,MAAM;gBACN,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,KAAK;gBACL,OAAO;gBACP,WAAW;aACZ,CAAC,CAAC;YACH,IAAI,MAAM,GAAG,KAAK,EAChB,SAAoC,CAAC;YACvC,IAAI,UAAU,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;YAC1B,MAAM,OAAO,GAAG,GAAkB,EAAE;gBAClC,MAAM,GAAG,IAAI,CAAC;gBACd,SAAS,KAAK,IAAI,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;qBACxC,IAAI,CAAC,GAAG,EAAE;oBACT,UAAU,EAAE,CAAC;gBACf,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACf,SAAS,GAAG,SAAS,CAAC;oBACtB,MAAM,KAAK,CAAC;gBACd,CAAC,CAAC,CAAC;gBACL,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC;YACF,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,EAAE;oBACf,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtD,CAAC,CAAC;gBACH,MAAM,IAAI,CACR,CAAC,OAAO,EAAE,IAAI,CAAC,EACf,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;gBACF,KAAK,MAAM,MAAM,IAAI,WAAW;oBAC9B,MAAM,IAAI,CAAC;wBACT,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,IAAI;wBACJ,IAAI;wBACJ,YAAY,KAAK,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE;qBAC9E,CAAC,CAAC;gBACL,IAAI,WAAW,CAAC,IAAI;oBAClB,MAAM,IAAI,CAAC;wBACT,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,OAAO;wBACP,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;wBACzB,IAAI;qBACL,CAAC,CAAC;gBACL,MAAM,IAAI,CAAC;oBACT,MAAM;oBACN,IAAI;oBACJ,IAAI;oBACJ,IAAI;oBACJ,qHAAqH;iBACtH,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,OAAO,EAAE,CAAC;gBAClB,CAAC;gBAAC,OAAO,OAAO,EAAE,CAAC;oBACjB,MAAM,IAAI,cAAc,CACtB,CAAC,KAAK,EAAE,OAAO,CAAC,EAChB,yCAAyC,CAC1C,CAAC;gBACJ,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE;gBACzC,IAAI,CAAC,MAAM;oBACT,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;wBAC5C,OAAO,EAAE,iBAAiB,CAAC,SAAS;wBACpC,KAAK,EAAE,QAAQ;wBACf,WAAW,EAAE,IAAI;qBAClB,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YACH,OAAO;gBACL,IAAI;gBACJ,IAAI;gBACJ,MAAM,EAAE,gBAAgB,CAAC;oBACvB,MAAM;oBACN,MAAM;oBACN,QAAQ;oBACR,IAAI;oBACJ,IAAI;oBACJ,GAAG;oBACH,IAAI;oBACJ,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM;iBACvB,CAAC;gBACF,GAAG,cAAc,CAAC;oBAChB,MAAM;oBACN,MAAM;oBACN,QAAQ;oBACR,IAAI;oBACJ,IAAI;oBACJ,GAAG;oBACH,IAAI;oBACJ,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM;iBACvB,CAAC;gBACF,OAAO;aACR,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport {\n executeProcess,\n quote,\n requireSuccess,\n} from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { containerCommand } from \"./container-command.ts\";\nimport { containerFiles } from \"./container-files.ts\";\nimport { containerMounts } from \"./container-mounts.ts\";\nimport { containerPlan } from \"./container-plan.ts\";\nimport { containerPreflight } from \"./container-preflight.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine, ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function imageName(repository: string): string {\n return `outpost:${\n basename(repository)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]/g, \"-\") || \"workspace\"\n }`;\n}\n\nexport function containerProvider(\n engine: ContainerEngine,\n options: ContainerOptions = {},\n executor: Executor = executeProcess,\n platform: NodeJS.Platform = process.platform,\n): SandboxProvider {\n const config = { ...options };\n if (config.cpus !== undefined)\n invariant(\n Number.isFinite(config.cpus) && config.cpus > 0,\n \"cpus must be positive\",\n );\n if (config.memoryMb !== undefined)\n invariant(\n Number.isSafeInteger(config.memoryMb) &&\n config.memoryMb >= containerDefaults.minimumMemoryMb,\n \"memoryMb must be at least 64\",\n );\n return {\n name: engine,\n placement: \"mounted\",\n variables: { ...config.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const name = `outpost-${randomUUID()}`;\n const image = config.image ?? imageName(context.repository);\n const user = config.user ?? {\n uid: process.getuid?.() ?? containerDefaults.uid,\n gid: process.getgid?.() ?? containerDefaults.gid,\n };\n invariant(\n Number.isInteger(user.uid) &&\n user.uid >= 0 &&\n Number.isInteger(user.gid) &&\n user.gid >= 0,\n \"Invalid container user\",\n );\n const call = (args: readonly string[], extra: Partial<Command> = {}) =>\n requireSuccess(\n {\n executable: engine,\n arguments: args,\n deadlineMs: containerDefaults.deadlineMs,\n ...extra,\n },\n executor,\n );\n await containerPreflight(engine, platform, call, config, image, user);\n const root = containerDefaults.root,\n home = containerDefaults.home;\n const { env, volumes, fileParents } = await containerMounts(\n context,\n config,\n platform,\n root,\n home,\n );\n const args = containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n });\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = (): Promise<void> => {\n closed = true;\n releasing ??= call([\"rm\", \"--force\", name])\n .then(() => {\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n });\n return releasing;\n };\n try {\n await call(args, {\n ...(context.signal ? { signal: context.signal } : {}),\n });\n await call(\n [\"start\", name],\n context.signal ? { signal: context.signal } : {},\n );\n for (const parent of fileParents)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,\n ]);\n if (fileParents.size)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n home,\n ]);\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n \"command -v setsid >/dev/null && command -v kill >/dev/null && command -v tar >/dev/null && command -v cp >/dev/null\",\n ]);\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Sandbox provisioning and cleanup failed\",\n );\n }\n throw cause;\n }\n unregister = registerCleanup(release, () => {\n if (!closed)\n execFileSync(engine, [\"rm\", \"--force\", name], {\n timeout: containerDefaults.cleanupMs,\n stdio: \"ignore\",\n windowsHide: true,\n });\n });\n return {\n root,\n home,\n invoke: containerCommand({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n ...containerFiles({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n release,\n };\n },\n };\n}\n"]}
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/providers/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EACL,cAAc,EACd,KAAK,EACL,cAAc,GACf,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,aAAa,GACd,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAK7D,MAAM,UAAU,SAAS,CAAC,UAAkB;IAC1C,OAAO,WACL,QAAQ,CAAC,UAAU,CAAC;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,IAAI,WACtC,EAAE,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAuB,EACvB,UAA4B,EAAE,EAC9B,WAAqB,cAAc,EACnC,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,MAAM,GAAG;QACb,GAAG,OAAO;QACV,QAAQ,EAAE,iBAAiB,CAAC,OAAO,CAAC;QACpC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;KAC9D,CAAC;IACF,SAAS,CACP,MAAM,CAAC,cAAc,KAAK,SAAS;QACjC,MAAM,CAAC,cAAc,KAAK,SAAS;QACnC,MAAM,CAAC,cAAc,KAAK,UAAU,EACtC,4CAA4C,CAC7C,CAAC;IACF,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAC3B,SAAS,CACP,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,EAC/C,uBAAuB,CACxB,CAAC;IACJ,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;QAC/B,SAAS,CACP,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC;YACnC,MAAM,CAAC,QAAQ,IAAI,iBAAiB,CAAC,eAAe,EACtD,8BAA8B,CAC/B,CAAC;IACJ,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,MAAM,CAAC,cAAc,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;QACtE,SAAS,EAAE,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE;QAClC,KAAK,CAAC,OAAO,CAAC,OAAO;YACnB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,WAAW,UAAU,EAAE,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI;gBAC1B,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,iBAAiB,CAAC,GAAG;gBAChD,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,iBAAiB,CAAC,GAAG;aACjD,CAAC;YACF,SAAS,CACP,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBACxB,IAAI,CAAC,GAAG,IAAI,CAAC;gBACb,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1B,IAAI,CAAC,GAAG,IAAI,CAAC,EACf,wBAAwB,CACzB,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,IAAuB,EAAE,QAA0B,EAAE,EAAE,EAAE,CACrE,cAAc,CACZ;gBACE,UAAU,EAAE,MAAM;gBAClB,SAAS,EAAE,IAAI;gBACf,UAAU,EAAE,iBAAiB,CAAC,UAAU;gBACxC,GAAG,KAAK;aACT,EACD,QAAQ,CACT,CAAC;YACJ,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACtE,MAAM,IAAI,GACN,MAAM,CAAC,cAAc,KAAK,UAAU;gBAClC,CAAC,CAAC,iBAAiB,CAAC,YAAY;gBAChC,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAC5B,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC;YAChC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CACzD,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,IAAI,CACL,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,MAAM,CAAC,MAAM,IAAI,EAAE,EACnB,OAAO,CAAC,UAAU,EAClB,KAAK,EACL,IAAI,CACL,CAAC;YACF,KAAK,MAAM,KAAK,IAAI,MAAM;gBACxB,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC;YACrE,MAAM,IAAI,GAAG,aAAa,CAAC;gBACzB,MAAM;gBACN,MAAM;gBACN,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,KAAK;gBACL,OAAO;gBACP,WAAW;aACZ,CAAC,CAAC;YACH,IAAI,MAAM,GAAG,KAAK,EAChB,SAAoC,CAAC;YACvC,IAAI,UAAU,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;YAC1B,MAAM,OAAO,GAAG,GAAkB,EAAE;gBAClC,MAAM,GAAG,IAAI,CAAC;gBACd,SAAS,KAAK,IAAI,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;qBACxC,IAAI,CAAC,GAAG,EAAE;oBACT,UAAU,EAAE,CAAC;gBACf,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACf,SAAS,GAAG,SAAS,CAAC;oBACtB,MAAM,KAAK,CAAC;gBACd,CAAC,CAAC,CAAC;gBACL,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC;YACF,IAAI,CAAC;gBACH,KAAK,MAAM,KAAK,IAAI,MAAM;oBACxB,MAAM,IAAI,CACR;wBACE,QAAQ;wBACR,QAAQ;wBACR,GAAG,kBAAkB,CAAC,MAAM,CAAC;wBAC7B,SAAS;wBACT,GAAG,aAAa,CAAC,KAAK,OAAO;wBAC7B,KAAK,CAAC,MAAM;qBACb,EACD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;gBACJ,MAAM,IAAI,CAAC,IAAI,EAAE;oBACf,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtD,CAAC,CAAC;gBACH,MAAM,IAAI,CACR,CAAC,OAAO,EAAE,IAAI,CAAC,EACf,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;gBACF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,MAAM,IAAI,CACR;wBACE,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,OAAO;wBACP,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;wBACzB,KAAK,CAAC,MAAM;qBACb,EACD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;oBACF,MAAM,IAAI,CACR,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAC5C,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;gBACJ,CAAC;gBACD,KAAK,MAAM,MAAM,IAAI,WAAW;oBAC9B,MAAM,IAAI,CAAC;wBACT,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,IAAI;wBACJ,IAAI;wBACJ,YAAY,KAAK,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE;qBAC9E,CAAC,CAAC;gBACL,IAAI,WAAW,CAAC,IAAI;oBAClB,MAAM,IAAI,CAAC;wBACT,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,OAAO;wBACP,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;wBACzB,IAAI;qBACL,CAAC,CAAC;gBACL,IAAI,MAAM,CAAC,cAAc,KAAK,UAAU;oBACtC,MAAM,IAAI,CACR;wBACE,MAAM;wBACN,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,IAAI;wBACJ,IAAI;wBACJ,YAAY,KAAK,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,eAAe;qBAChI,EACD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;gBACJ,MAAM,IAAI,CAAC;oBACT,MAAM;oBACN,IAAI;oBACJ,IAAI;oBACJ,IAAI;oBACJ,qHAAqH;iBACtH,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,OAAO,EAAE,CAAC;gBAClB,CAAC;gBAAC,OAAO,OAAO,EAAE,CAAC;oBACjB,MAAM,IAAI,cAAc,CACtB,CAAC,KAAK,EAAE,OAAO,CAAC,EAChB,yCAAyC,CAC1C,CAAC;gBACJ,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE;gBACzC,IAAI,CAAC,MAAM;oBACT,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE;wBAC5C,OAAO,EAAE,iBAAiB,CAAC,SAAS;wBACpC,KAAK,EAAE,QAAQ;wBACf,WAAW,EAAE,IAAI;qBAClB,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YACH,OAAO;gBACL,IAAI;gBACJ,IAAI;gBACJ,MAAM,EAAE,gBAAgB,CAAC;oBACvB,MAAM;oBACN,MAAM;oBACN,QAAQ;oBACR,IAAI;oBACJ,IAAI;oBACJ,GAAG;oBACH,IAAI;oBACJ,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM;iBACvB,CAAC;gBACF,GAAG,cAAc,CAAC;oBAChB,MAAM;oBACN,MAAM;oBACN,QAAQ;oBACR,IAAI;oBACJ,IAAI;oBACJ,GAAG;oBACH,IAAI;oBACJ,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM;iBACvB,CAAC;gBACF,OAAO;aACR,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { containerNetworks } from \"./container-network.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport {\n executeProcess,\n quote,\n requireSuccess,\n} from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { cacheMounts, validateCaches } from \"./container-cache.ts\";\nimport {\n cacheCreateOptions,\n cacheDefaults,\n} from \"./container-cache.constants.ts\";\nimport { containerCommand } from \"./container-command.ts\";\nimport { containerFiles } from \"./container-files.ts\";\nimport { containerMounts } from \"./container-mounts.ts\";\nimport { containerPlan } from \"./container-plan.ts\";\nimport { containerPreflight } from \"./container-preflight.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine, ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function imageName(repository: string): string {\n return `outpost:${\n basename(repository)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]/g, \"-\") || \"workspace\"\n }`;\n}\n\nexport function containerProvider(\n engine: ContainerEngine,\n options: ContainerOptions = {},\n executor: Executor = executeProcess,\n platform: NodeJS.Platform = process.platform,\n): SandboxProvider {\n const config = {\n ...options,\n networks: containerNetworks(options),\n caches: (options.caches ?? []).map((cache) => ({ ...cache })),\n };\n invariant(\n config.repositoryMode === undefined ||\n config.repositoryMode === \"mounted\" ||\n config.repositoryMode === \"isolated\",\n \"repositoryMode must be mounted or isolated\",\n );\n validateCaches(config);\n if (config.cpus !== undefined)\n invariant(\n Number.isFinite(config.cpus) && config.cpus > 0,\n \"cpus must be positive\",\n );\n if (config.memoryMb !== undefined)\n invariant(\n Number.isSafeInteger(config.memoryMb) &&\n config.memoryMb >= containerDefaults.minimumMemoryMb,\n \"memoryMb must be at least 64\",\n );\n return {\n name: engine,\n placement: config.repositoryMode === \"isolated\" ? \"remote\" : \"mounted\",\n variables: { ...config.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const name = `outpost-${randomUUID()}`;\n const image = config.image ?? imageName(context.repository);\n const user = config.user ?? {\n uid: process.getuid?.() ?? containerDefaults.uid,\n gid: process.getgid?.() ?? containerDefaults.gid,\n };\n invariant(\n Number.isInteger(user.uid) &&\n user.uid >= 0 &&\n Number.isInteger(user.gid) &&\n user.gid >= 0,\n \"Invalid container user\",\n );\n const call = (args: readonly string[], extra: Partial<Command> = {}) =>\n requireSuccess(\n {\n executable: engine,\n arguments: args,\n deadlineMs: containerDefaults.deadlineMs,\n ...extra,\n },\n executor,\n );\n await containerPreflight(engine, platform, call, config, image, user);\n const root =\n config.repositoryMode === \"isolated\"\n ? containerDefaults.isolatedRoot\n : containerDefaults.root,\n home = containerDefaults.home;\n const { env, volumes, fileParents } = await containerMounts(\n context,\n config,\n platform,\n root,\n home,\n );\n const caches = await cacheMounts(\n config.caches ?? [],\n context.repository,\n image,\n user,\n );\n for (const cache of caches)\n volumes.push(\"--volume\", `${cache.volume}:${cache.target}:nocopy`);\n const args = containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n });\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = (): Promise<void> => {\n closed = true;\n releasing ??= call([\"rm\", \"--force\", name])\n .then(() => {\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n });\n return releasing;\n };\n try {\n for (const cache of caches)\n await call(\n [\n \"volume\",\n \"create\",\n ...cacheCreateOptions[engine],\n \"--label\",\n `${cacheDefaults.label}=true`,\n cache.volume,\n ],\n context.signal ? { signal: context.signal } : {},\n );\n await call(args, {\n ...(context.signal ? { signal: context.signal } : {}),\n });\n await call(\n [\"start\", name],\n context.signal ? { signal: context.signal } : {},\n );\n for (const cache of caches) {\n await call(\n [\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n cache.target,\n ],\n context.signal ? { signal: context.signal } : {},\n );\n await call(\n [\"exec\", name, \"chmod\", \"700\", cache.target],\n context.signal ? { signal: context.signal } : {},\n );\n }\n for (const parent of fileParents)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,\n ]);\n if (fileParents.size)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n home,\n ]);\n if (config.repositoryMode === \"isolated\")\n await call(\n [\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(root)} && chmod 700 ${quote(root)} /tmp/outpost && chown ${user.uid}:${user.gid} ${quote(root)} /tmp/outpost`,\n ],\n context.signal ? { signal: context.signal } : {},\n );\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n \"command -v setsid >/dev/null && command -v kill >/dev/null && command -v tar >/dev/null && command -v cp >/dev/null\",\n ]);\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Sandbox provisioning and cleanup failed\",\n );\n }\n throw cause;\n }\n unregister = registerCleanup(release, () => {\n if (!closed)\n execFileSync(engine, [\"rm\", \"--force\", name], {\n timeout: containerDefaults.cleanupMs,\n stdio: \"ignore\",\n windowsHide: true,\n });\n });\n return {\n root,\n home,\n invoke: containerCommand({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n ...containerFiles({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n release,\n };\n },\n };\n}\n"]}
@@ -1,7 +1,12 @@
1
+ import type { EgressPolicy } from "../domain/egress.types.ts";
1
2
  import type { Command, CommandResult, Variables } from "../domain/command.types.ts";
2
3
  import type { Volume } from "../domain/sandbox.types.ts";
3
4
  import type { Executor } from "../infrastructure/process.types.ts";
5
+ import type { DependencyCache } from "./container-cache.types.ts";
4
6
  export interface ContainerOptions {
7
+ readonly egress?: EgressPolicy;
8
+ readonly repositoryMode?: "mounted" | "isolated";
9
+ readonly caches?: readonly DependencyCache[];
5
10
  readonly image?: string;
6
11
  readonly user?: {
7
12
  readonly uid: number;
@@ -1 +1 @@
1
- {"version":3,"file":"container.types.js","sourceRoot":"","sources":["../../src/providers/container.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n Command,\n CommandResult,\n Variables,\n} from \"../domain/command.types.ts\";\nimport type { Volume } from \"../domain/sandbox.types.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\n\nexport interface ContainerOptions {\n readonly image?: string;\n readonly user?: { readonly uid: number; readonly gid: number };\n readonly volumes?: readonly Volume[];\n readonly variables?: Variables;\n readonly networks?: string | readonly string[];\n readonly groups?: readonly (string | number)[];\n readonly devices?: readonly string[];\n readonly cpus?: number;\n readonly memoryMb?: number;\n readonly label?: \"z\" | \"Z\" | false;\n readonly retain?: number;\n readonly userns?: \"keep-id\" | false;\n}\n\nexport type ContainerEngine = \"docker\" | \"podman\";\nexport type ContainerCall = (\n args: readonly string[],\n extra?: Partial<Command>,\n) => Promise<CommandResult>;\nexport interface ContainerRuntime {\n readonly engine: ContainerEngine;\n readonly config: ContainerOptions;\n readonly executor: Executor;\n readonly root: string;\n readonly name: string;\n readonly env: Record<string, string>;\n readonly call: ContainerCall;\n readonly isClosed: () => boolean;\n}\nexport interface ContainerMounts {\n readonly env: Record<string, string>;\n readonly volumes: string[];\n readonly fileParents: Set<string>;\n}\n\nexport interface ContainerUser {\n readonly uid: number;\n readonly gid: number;\n}\nexport interface ContainerPlanOptions {\n readonly config: ContainerOptions;\n readonly engine: ContainerEngine;\n readonly user: ContainerUser;\n readonly root: string;\n readonly name: string;\n readonly image: string;\n readonly volumes: readonly string[];\n readonly fileParents: ReadonlySet<string>;\n}\n"]}
1
+ {"version":3,"file":"container.types.js","sourceRoot":"","sources":["../../src/providers/container.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { EgressPolicy } from \"../domain/egress.types.ts\";\nimport type {\n Command,\n CommandResult,\n Variables,\n} from \"../domain/command.types.ts\";\nimport type { Volume } from \"../domain/sandbox.types.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport type { DependencyCache } from \"./container-cache.types.ts\";\n\nexport interface ContainerOptions {\n readonly egress?: EgressPolicy;\n readonly repositoryMode?: \"mounted\" | \"isolated\";\n readonly caches?: readonly DependencyCache[];\n readonly image?: string;\n readonly user?: { readonly uid: number; readonly gid: number };\n readonly volumes?: readonly Volume[];\n readonly variables?: Variables;\n readonly networks?: string | readonly string[];\n readonly groups?: readonly (string | number)[];\n readonly devices?: readonly string[];\n readonly cpus?: number;\n readonly memoryMb?: number;\n readonly label?: \"z\" | \"Z\" | false;\n readonly retain?: number;\n readonly userns?: \"keep-id\" | false;\n}\n\nexport type ContainerEngine = \"docker\" | \"podman\";\nexport type ContainerCall = (\n args: readonly string[],\n extra?: Partial<Command>,\n) => Promise<CommandResult>;\nexport interface ContainerRuntime {\n readonly engine: ContainerEngine;\n readonly config: ContainerOptions;\n readonly executor: Executor;\n readonly root: string;\n readonly name: string;\n readonly env: Record<string, string>;\n readonly call: ContainerCall;\n readonly isClosed: () => boolean;\n}\nexport interface ContainerMounts {\n readonly env: Record<string, string>;\n readonly volumes: string[];\n readonly fileParents: Set<string>;\n}\n\nexport interface ContainerUser {\n readonly uid: number;\n readonly gid: number;\n}\nexport interface ContainerPlanOptions {\n readonly config: ContainerOptions;\n readonly engine: ContainerEngine;\n readonly user: ContainerUser;\n readonly root: string;\n readonly name: string;\n readonly image: string;\n readonly volumes: readonly string[];\n readonly fileParents: ReadonlySet<string>;\n}\n"]}
@@ -1,15 +1,15 @@
1
+ import { setTimeout } from "node:timers/promises";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { OutpostError } from "../domain/errors.js";
3
4
  import { interruptible } from "../infrastructure/abort.js";
4
5
  import { quote } from "../infrastructure/process.js";
5
6
  import { cloudDefaults } from "./cloud.constants.js";
7
+ import { daytonaTerminal } from "./daytona-terminal.js";
6
8
  export function daytonaCommand(runtime) {
7
9
  const { sandbox, root, options, context, isClosed } = runtime;
8
10
  return async (command) => {
9
11
  if (isClosed())
10
12
  throw new OutpostError("provider", "Cloud sandbox is closed");
11
- if (command.interactive)
12
- throw new OutpostError("provider", "Interactive terminals require a mounted or local provider");
13
13
  const signal = command.signal
14
14
  ? AbortSignal.any([
15
15
  command.signal,
@@ -17,6 +17,8 @@ export function daytonaCommand(runtime) {
17
17
  ])
18
18
  : AbortSignal.timeout(command.deadlineMs ?? cloudDefaults.deadlineMs);
19
19
  signal.throwIfAborted();
20
+ if (command.interactive)
21
+ return daytonaTerminal(runtime, command, signal);
20
22
  const id = `outpost-${randomUUID()}`;
21
23
  const input = `/tmp/${id}.stdin`;
22
24
  const pid = `/tmp/${id}.pid`;
@@ -59,10 +61,12 @@ export function daytonaCommand(runtime) {
59
61
  if (cancellation)
60
62
  await cancellation;
61
63
  signal.throwIfAborted();
62
- const result = await sandbox.process.getSessionCommand(id, response.cmdId);
63
- if (result.exitCode === undefined)
64
- throw new OutpostError("provider", "Cloud command ended without an exit status");
65
- return { status: result.exitCode, ...output };
64
+ while (true) {
65
+ const result = await interruptible(sandbox.process.getSessionCommand(id, response.cmdId), signal);
66
+ if (result.exitCode !== undefined)
67
+ return { status: result.exitCode, ...output };
68
+ await setTimeout(cloudDefaults.pollMs, undefined, { signal });
69
+ }
66
70
  }
67
71
  catch (cause) {
68
72
  cancel();
@@ -1 +1 @@
1
- {"version":3,"file":"daytona-command.js","sourceRoot":"","sources":["../../src/providers/daytona-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,MAAM,UAAU,cAAc,CAC5B,OAAuB;IAEvB,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,IAAI,QAAQ,EAAE;YACZ,MAAM,IAAI,YAAY,CAAC,UAAU,EAAE,yBAAyB,CAAC,CAAC;QAChE,IAAI,OAAO,CAAC,WAAW;YACrB,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,2DAA2D,CAC5D,CAAC;QACJ,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;YAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC;gBACd,OAAO,CAAC,MAAM;gBACd,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC;aACpE,CAAC;YACJ,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC,CAAC;QACxE,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,WAAW,UAAU,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,QAAQ,EAAE,QAAQ,CAAC;QACjC,MAAM,GAAG,GAAG,QAAQ,EAAE,MAAM,CAAC;QAC7B,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAC7B,MAAM,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QACjE,MAAM,OAAO,GAAG;YACd,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,CAAC,UAAU;YAClB,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;SAC7B;aACE,GAAG,CAAC,KAAK,CAAC;aACV,IAAI,CAAC,GAAG,CAAC,CAAC;QACb,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,gBAAgB,MAAM,CAAC,OAAO,CACjF,SAAS,CACV;aACE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;aAC/C,IAAI,CACH,GAAG,CACJ,iBAAiB,KAAK,CAAC,aAAa,KAAK,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,GAAG,GAAG,SAAS,CAAC,sBAAsB,OAAO,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QACnL,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAC1C,IAAI,YAA0C,CAAC;QAC/C,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,cAAc,CAC7C,SAAS,KAAK,CAAC,GAAG,GAAG,SAAS,CAAC,aAAa,KAAK,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,GAAG,CAAC,2BAA2B,CAC1H,CAAC;YACF,KAAK,YAAY,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3C,CAAC,CAAC;QACF,MAAM,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,IAAI,MAAM,CAAC,OAAO;gBAAE,MAAM,EAAE,CAAC;YAC7B,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,MAAM,aAAa,CAClC,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,EAAE;gBACxC,OAAO,EAAE,MAAM;gBACf,KAAK,EAAE,IAAI;aACZ,CAAC,EACF,MAAM,CACP,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,KAAK;gBACjB,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,+CAA+C,CAChD,CAAC;YACJ,MAAM,OAAO,GAAG,CAAC,OAA4B,EAAE,EAAE,CAAC,CAAC,KAAa,EAAE,EAAE;gBAClE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAC/C,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,WAAW,CAAC,CACjE,CAAC;gBACF,OAAO,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACpC,CAAC,CAAC;YACF,MAAM,aAAa,CACjB,OAAO,CAAC,OAAO,CAAC,qBAAqB,CACnC,EAAE,EACF,QAAQ,CAAC,KAAK,EACd,OAAO,CAAC,QAAQ,CAAC,EACjB,OAAO,CAAC,QAAQ,CAAC,CAClB,EACD,MAAM,CACP,CAAC;YACF,IAAI,YAAY;gBAAE,MAAM,YAAY,CAAC;YACrC,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,iBAAiB,CACpD,EAAE,EACF,QAAQ,CAAC,KAAK,CACf,CAAC;YACF,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;gBAC/B,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,4CAA4C,CAC7C,CAAC;YACJ,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,CAAC;YACT,IAAI,CAAC;gBACH,MAAM,aAAa,CACjB,YAAa,EACb,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,CAClD,CAAC;YACJ,CAAC;YAAC,OAAO,OAAO,EAAE,CAAC;gBACjB,MAAM,IAAI,cAAc,CACtB,CAAC,KAAK,EAAE,OAAO,CAAC,EAChB,2CAA2C,CAC5C,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YACxC,MAAM,OAAO,CAAC,OAAO;iBAClB,cAAc,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;iBACrD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport { interruptible } from \"../infrastructure/abort.ts\";\nimport { quote } from \"../infrastructure/process.ts\";\nimport { cloudDefaults } from \"./cloud.constants.ts\";\nimport type { DaytonaRuntime } from \"./daytona.types.ts\";\n\nexport function daytonaCommand(\n runtime: DaytonaRuntime,\n): SandboxLease[\"invoke\"] {\n const { sandbox, root, options, context, isClosed } = runtime;\n return async (command) => {\n if (isClosed())\n throw new OutpostError(\"provider\", \"Cloud sandbox is closed\");\n if (command.interactive)\n throw new OutpostError(\n \"provider\",\n \"Interactive terminals require a mounted or local provider\",\n );\n const signal = command.signal\n ? AbortSignal.any([\n command.signal,\n AbortSignal.timeout(command.deadlineMs ?? cloudDefaults.deadlineMs),\n ])\n : AbortSignal.timeout(command.deadlineMs ?? cloudDefaults.deadlineMs);\n signal.throwIfAborted();\n const id = `outpost-${randomUUID()}`;\n const input = `/tmp/${id}.stdin`;\n const pid = `/tmp/${id}.pid`;\n if (command.stdin !== undefined)\n await sandbox.fs.uploadFile(Buffer.from(command.stdin), input);\n const variables = { ...context.variables, ...command.variables };\n const program = [\n ...(command.elevated ? [\"sudo\", \"-n\", \"--\"] : []),\n command.executable,\n ...(command.arguments ?? []),\n ]\n .map(quote)\n .join(\" \");\n const script = `cd ${quote(command.directory ?? root)} && exec env ${Object.entries(\n variables,\n )\n .map(([key, value]) => quote(`${key}=${value}`))\n .join(\n \" \",\n )} setsid sh -c ${quote(`echo $$ > ${quote(pid)}; test ! -f ${quote(pid + \".cancel\")} || exit 130; exec ${program}${command.stdin === undefined ? \"\" : ` < ${quote(input)}`}`)}`;\n const output = { stdout: \"\", stderr: \"\" };\n let cancellation: Promise<unknown> | undefined;\n const cancel = () => {\n cancellation ??= sandbox.process.executeCommand(\n `touch ${quote(pid + \".cancel\")}; if [ -f ${quote(pid)} ]; then kill -KILL -$(cat ${quote(pid)}) 2>/dev/null || true; fi`,\n );\n void cancellation.catch(() => undefined);\n };\n await sandbox.process.createSession(id);\n try {\n signal.addEventListener(\"abort\", cancel, { once: true });\n if (signal.aborted) cancel();\n signal.throwIfAborted();\n const response = await interruptible(\n sandbox.process.executeSessionCommand(id, {\n command: script,\n async: true,\n }),\n signal,\n );\n if (!response.cmdId)\n throw new OutpostError(\n \"provider\",\n \"Cloud provider returned no command identifier\",\n );\n const consume = (channel: \"stdout\" | \"stderr\") => (chunk: string) => {\n output[channel] = (output[channel] + chunk).slice(\n -(command.retain ?? options.retain ?? cloudDefaults.retainBytes),\n );\n command.observe?.(channel, chunk);\n };\n await interruptible(\n sandbox.process.getSessionCommandLogs(\n id,\n response.cmdId,\n consume(\"stdout\"),\n consume(\"stderr\"),\n ),\n signal,\n );\n if (cancellation) await cancellation;\n signal.throwIfAborted();\n const result = await sandbox.process.getSessionCommand(\n id,\n response.cmdId,\n );\n if (result.exitCode === undefined)\n throw new OutpostError(\n \"provider\",\n \"Cloud command ended without an exit status\",\n );\n return { status: result.exitCode, ...output };\n } catch (cause) {\n cancel();\n try {\n await interruptible(\n cancellation!,\n AbortSignal.timeout(cloudDefaults.cancellationMs),\n );\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Cloud cancellation could not be confirmed\",\n );\n }\n throw cause;\n } finally {\n signal.removeEventListener(\"abort\", cancel);\n await sandbox.process.deleteSession(id);\n await sandbox.process\n .executeCommand(`rm -f ${quote(input)} ${quote(pid)}`)\n .catch(() => undefined);\n }\n };\n}\n"]}
1
+ {"version":3,"file":"daytona-command.js","sourceRoot":"","sources":["../../src/providers/daytona-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { setTimeout } from \"node:timers/promises\";\nimport { randomUUID } from \"node:crypto\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport { interruptible } from \"../infrastructure/abort.ts\";\nimport { quote } from \"../infrastructure/process.ts\";\nimport { cloudDefaults } from \"./cloud.constants.ts\";\nimport { daytonaTerminal } from \"./daytona-terminal.ts\";\nimport type { DaytonaRuntime } from \"./daytona.types.ts\";\n\nexport function daytonaCommand(\n runtime: DaytonaRuntime,\n): SandboxLease[\"invoke\"] {\n const { sandbox, root, options, context, isClosed } = runtime;\n return async (command) => {\n if (isClosed())\n throw new OutpostError(\"provider\", \"Cloud sandbox is closed\");\n const signal = command.signal\n ? AbortSignal.any([\n command.signal,\n AbortSignal.timeout(command.deadlineMs ?? cloudDefaults.deadlineMs),\n ])\n : AbortSignal.timeout(command.deadlineMs ?? cloudDefaults.deadlineMs);\n signal.throwIfAborted();\n if (command.interactive) return daytonaTerminal(runtime, command, signal);\n const id = `outpost-${randomUUID()}`;\n const input = `/tmp/${id}.stdin`;\n const pid = `/tmp/${id}.pid`;\n if (command.stdin !== undefined)\n await sandbox.fs.uploadFile(Buffer.from(command.stdin), input);\n const variables = { ...context.variables, ...command.variables };\n const program = [\n ...(command.elevated ? [\"sudo\", \"-n\", \"--\"] : []),\n command.executable,\n ...(command.arguments ?? []),\n ]\n .map(quote)\n .join(\" \");\n const script = `cd ${quote(command.directory ?? root)} && exec env ${Object.entries(\n variables,\n )\n .map(([key, value]) => quote(`${key}=${value}`))\n .join(\n \" \",\n )} setsid sh -c ${quote(`echo $$ > ${quote(pid)}; test ! -f ${quote(pid + \".cancel\")} || exit 130; exec ${program}${command.stdin === undefined ? \"\" : ` < ${quote(input)}`}`)}`;\n const output = { stdout: \"\", stderr: \"\" };\n let cancellation: Promise<unknown> | undefined;\n const cancel = () => {\n cancellation ??= sandbox.process.executeCommand(\n `touch ${quote(pid + \".cancel\")}; if [ -f ${quote(pid)} ]; then kill -KILL -$(cat ${quote(pid)}) 2>/dev/null || true; fi`,\n );\n void cancellation.catch(() => undefined);\n };\n await sandbox.process.createSession(id);\n try {\n signal.addEventListener(\"abort\", cancel, { once: true });\n if (signal.aborted) cancel();\n signal.throwIfAborted();\n const response = await interruptible(\n sandbox.process.executeSessionCommand(id, {\n command: script,\n async: true,\n }),\n signal,\n );\n if (!response.cmdId)\n throw new OutpostError(\n \"provider\",\n \"Cloud provider returned no command identifier\",\n );\n const consume = (channel: \"stdout\" | \"stderr\") => (chunk: string) => {\n output[channel] = (output[channel] + chunk).slice(\n -(command.retain ?? options.retain ?? cloudDefaults.retainBytes),\n );\n command.observe?.(channel, chunk);\n };\n await interruptible(\n sandbox.process.getSessionCommandLogs(\n id,\n response.cmdId,\n consume(\"stdout\"),\n consume(\"stderr\"),\n ),\n signal,\n );\n if (cancellation) await cancellation;\n signal.throwIfAborted();\n while (true) {\n const result = await interruptible(\n sandbox.process.getSessionCommand(id, response.cmdId),\n signal,\n );\n if (result.exitCode !== undefined)\n return { status: result.exitCode, ...output };\n await setTimeout(cloudDefaults.pollMs, undefined, { signal });\n }\n } catch (cause) {\n cancel();\n try {\n await interruptible(\n cancellation!,\n AbortSignal.timeout(cloudDefaults.cancellationMs),\n );\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Cloud cancellation could not be confirmed\",\n );\n }\n throw cause;\n } finally {\n signal.removeEventListener(\"abort\", cancel);\n await sandbox.process.deleteSession(id);\n await sandbox.process\n .executeCommand(`rm -f ${quote(input)} ${quote(pid)}`)\n .catch(() => undefined);\n }\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { Command, CommandResult } from "../domain/command.types.ts";
2
+ import type { DaytonaRuntime } from "./daytona.types.ts";
3
+ export declare function daytonaTerminal(runtime: DaytonaRuntime, command: Command, signal: AbortSignal): Promise<CommandResult>;