@molecule/api-code-sandbox-docker 1.1.2 → 1.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAcV,eAAe,EAOhB,MAAM,4BAA4B,CAAA;AAoBnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AA4K9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQ9D;AAkCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,EAAE;IACJ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACjC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE,CAAA;CAC1D,GACA,OAAO,CAAC,CAAC,CAAC,CA2BZ;AA07CD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,eAAe,CAErE"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAcV,eAAe,EAOhB,MAAM,4BAA4B,CAAA;AAoBnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AA4K9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQ9D;AAyED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,EAAE;IACJ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACjC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE,CAAA;CAC1D,GACA,OAAO,CAAC,CAAC,CAAC,CA2BZ;AAg9CD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,eAAe,CAErE"}
package/dist/provider.js CHANGED
@@ -190,6 +190,41 @@ export function resolvePublishPorts(ports) {
190
190
  }
191
191
  return [...new Set(ports)];
192
192
  }
193
+ /**
194
+ * Give an imported tree to whoever owns the sandbox's workspace root.
195
+ *
196
+ * Docker's putArchive preserves the tar's uid/gid — 0 — while the sandbox runs
197
+ * as the image's USER. Everything the sandbox does afterwards is done by that
198
+ * user, so an unrepaired import is a tree it cannot write.
199
+ *
200
+ * It has to be done from here, and as root: an ordinary exec runs as the same
201
+ * non-root user and `chown` answers "Operation not permitted" (which a pipe
202
+ * then hides behind exit 0 — that is how the repair went unnoticed).
203
+ *
204
+ * @param dockerApi - The provider's API client, bound by the caller.
205
+ * @param containerId - The sandbox to repair.
206
+ * @param path - The absolute path that was just imported.
207
+ */
208
+ async function chownImportedTree(dockerApi, containerId, path) {
209
+ try {
210
+ const created = (await dockerApi(`/containers/${containerId}/exec`, 'POST', {
211
+ // `|| true` so an image whose workspace root is already the running user
212
+ // (or a path that vanished) is a no-op rather than a thrown import.
213
+ Cmd: ['sh', '-c', `chown -R --reference=/workspace ${shellQuote(path)} || true`],
214
+ User: 'root',
215
+ AttachStdout: false,
216
+ AttachStderr: false,
217
+ }));
218
+ if (created?.Id) {
219
+ await dockerApi(`/exec/${created.Id}/start`, 'POST', { Detach: false, Tty: false });
220
+ }
221
+ }
222
+ catch (_error) {
223
+ // Intentional noop: best-effort repair. A daemon that refuses a root exec
224
+ // leaves the tree exactly as the tar delivered it — the behaviour before
225
+ // this existed — and an import must not fail over it.
226
+ }
227
+ }
193
228
  /**
194
229
  * Available memory in bytes, or `null` when it cannot be read.
195
230
  *
@@ -1011,6 +1046,24 @@ class DockerSandboxProvider {
1011
1046
  download: (p, timeoutMs) => provider.dockerDownload(p, timeoutMs),
1012
1047
  upload: (p, body, timeoutMs) => provider.dockerUpload(p, body, timeoutMs),
1013
1048
  }, containerId, path, archive);
1049
+ // Docker's putArchive preserves the tar's uid/gid, which is 0, while the
1050
+ // sandbox runs as the image's USER (`node`, uid 1000). Without this the
1051
+ // imported tree belongs to a user nothing runs as: the executor cannot
1052
+ // write a file it just received, npm install cannot touch node_modules,
1053
+ // and Vite cannot create `node_modules/.vite-temp/…`, so the dev server
1054
+ // never starts.
1055
+ //
1056
+ // A caller cannot repair it afterwards — an ordinary exec runs as that
1057
+ // same non-root user and `chown` answers "Operation not permitted". The
1058
+ // repair has to happen here, on a root exec, which is a docker-ism and
1059
+ // belongs in the docker bond. (E2B has no equivalent step: it extracts
1060
+ // with --no-same-owner, so files already arrive on the executor's user.)
1061
+ //
1062
+ // `--reference=/workspace` takes the answer from the image itself
1063
+ // rather than naming a user, so it is correct for a root-based image
1064
+ // and a non-root one alike. Best-effort: a failure here must not fail
1065
+ // the import, and on an already-correct tree it is a no-op.
1066
+ await chownImportedTree((p, method, body) => provider.dockerApi(p, method, body), containerId, path);
1014
1067
  },
1015
1068
  onFileChange(_cb) {
1016
1069
  let active = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-code-sandbox-docker",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Docker-based code sandbox container provider",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",