@decocms/sandbox-controller 0.16.2 → 0.16.4
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.
- package/dist/index.d.ts +10 -0
- package/dist/index.js +25 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3730,6 +3730,15 @@ interface FreestyleSandboxProviderOptions {
|
|
|
3730
3730
|
image?: string;
|
|
3731
3731
|
/** The org-fs sidecar image. Default: the chart's `orgFs.image`. */
|
|
3732
3732
|
orgFsSidecarImage?: string;
|
|
3733
|
+
/**
|
|
3734
|
+
* What the daemon signs the bot's commits with, as the sandbox-env chart's
|
|
3735
|
+
* `commitSigning` does for pods. Unset leaves commits unsigned. The key goes
|
|
3736
|
+
* into the base snapshot, so code in any of these sandboxes can read it.
|
|
3737
|
+
*/
|
|
3738
|
+
commitSigning?: {
|
|
3739
|
+
email: string;
|
|
3740
|
+
privateKey: string;
|
|
3741
|
+
};
|
|
3733
3742
|
/** Pause a VM after this long without network activity. Default 5 min. */
|
|
3734
3743
|
idleTimeoutSeconds?: number;
|
|
3735
3744
|
/**
|
|
@@ -3760,6 +3769,7 @@ declare class FreestyleSandboxProvider implements SandboxProvider {
|
|
|
3760
3769
|
private readonly image;
|
|
3761
3770
|
private readonly sidecarImage;
|
|
3762
3771
|
private readonly allowUserNamespaces;
|
|
3772
|
+
private readonly commitSigning;
|
|
3763
3773
|
private readonly idleTimeoutSeconds;
|
|
3764
3774
|
private readonly idlePauseMs;
|
|
3765
3775
|
private readonly autoDeleteSeconds;
|
package/dist/index.js
CHANGED
|
@@ -4521,6 +4521,7 @@ function tenantPoolReader(store, cluster, { refreshMs = DEFAULT_TENANT_POOL_REFR
|
|
|
4521
4521
|
|
|
4522
4522
|
// ../sandbox/server/provider/freestyle.ts
|
|
4523
4523
|
import { createHash as createHash3, createHmac, randomBytes as randomBytes2 } from "crypto";
|
|
4524
|
+
import { dirname } from "path";
|
|
4524
4525
|
|
|
4525
4526
|
// ../../node_modules/.bun/freestyle@0.2.16/node_modules/freestyle/dist/errors.js
|
|
4526
4527
|
var FreestyleApiError = class _FreestyleApiError extends Error {
|
|
@@ -6804,7 +6805,7 @@ var Freestyle = class {
|
|
|
6804
6805
|
// ../sandbox/package.json
|
|
6805
6806
|
var package_default = {
|
|
6806
6807
|
name: "@decocms/sandbox",
|
|
6807
|
-
version: "1.96.
|
|
6808
|
+
version: "1.96.4",
|
|
6808
6809
|
private: true,
|
|
6809
6810
|
type: "module",
|
|
6810
6811
|
description: "Sandbox runtime for isolated Studio tool execution",
|
|
@@ -6888,6 +6889,8 @@ var DEFAULT_SIDECAR_IMAGE = "ghcr.io/decocms/studio/orgfs-sidecar:0.2.0";
|
|
|
6888
6889
|
var HOST_ORG_DIR = "/srv/sandbox/org";
|
|
6889
6890
|
var HOST_CTL_DIR = "/srv/sandbox/orgfs-ctl";
|
|
6890
6891
|
var CTL_DIR = "/run/orgfs";
|
|
6892
|
+
var HOST_SIGNING_KEY = "/srv/sandbox/git-signing-key";
|
|
6893
|
+
var SIGNING_KEY_FILE = "/run/git-signing/key";
|
|
6891
6894
|
var HOST_SETUP = [
|
|
6892
6895
|
`mkdir -p ${HOST_ORG_DIR} ${HOST_CTL_DIR}`,
|
|
6893
6896
|
`grep -q ' ${HOST_ORG_DIR} ' /etc/fstab || printf '%s\\n' '${HOST_ORG_DIR} ${HOST_ORG_DIR} none bind,rshared 0 0' 'tmpfs ${HOST_CTL_DIR} tmpfs uid=1000,gid=1000,mode=0755,size=1m 0 0' >> /etc/fstab`,
|
|
@@ -6924,6 +6927,7 @@ var FreestyleSandboxProvider = class {
|
|
|
6924
6927
|
image;
|
|
6925
6928
|
sidecarImage;
|
|
6926
6929
|
allowUserNamespaces;
|
|
6930
|
+
commitSigning;
|
|
6927
6931
|
idleTimeoutSeconds;
|
|
6928
6932
|
idlePauseMs;
|
|
6929
6933
|
autoDeleteSeconds;
|
|
@@ -6965,6 +6969,7 @@ var FreestyleSandboxProvider = class {
|
|
|
6965
6969
|
this.image = opts.image ?? `ghcr.io/decocms/studio/studio-sandbox-go:${package_default.version}`;
|
|
6966
6970
|
this.sidecarImage = opts.orgFsSidecarImage ?? DEFAULT_SIDECAR_IMAGE;
|
|
6967
6971
|
this.allowUserNamespaces = opts.allowUserNamespaces ?? false;
|
|
6972
|
+
this.commitSigning = opts.commitSigning;
|
|
6968
6973
|
this.idleTimeoutSeconds = opts.idleTimeoutSeconds ?? 5 * 60;
|
|
6969
6974
|
this.idlePauseMs = opts.idlePauseMs ?? 10 * 6e4;
|
|
6970
6975
|
this.autoDeleteSeconds = opts.autoDeleteSeconds ?? 24 * 60 * 60;
|
|
@@ -7031,9 +7036,13 @@ var FreestyleSandboxProvider = class {
|
|
|
7031
7036
|
baseSnapshot() {
|
|
7032
7037
|
const { image, sidecarImage } = this;
|
|
7033
7038
|
const namespaceMode = this.allowUserNamespaces ? "\nuser-namespaces" : "";
|
|
7039
|
+
const signing = this.commitSigning ? `
|
|
7040
|
+
signing
|
|
7041
|
+
${this.commitSigning.email}
|
|
7042
|
+
${this.commitSigning.privateKey}` : "";
|
|
7034
7043
|
const slug = `studio-sandbox-${createHash3("sha256").update(`${image}
|
|
7035
7044
|
${sidecarImage}
|
|
7036
|
-
running${namespaceMode}`).digest("hex").slice(0, 16)}`;
|
|
7045
|
+
running${namespaceMode}${signing}`).digest("hex").slice(0, 16)}`;
|
|
7037
7046
|
if (this.knownSnapshots.has(slug)) return Promise.resolve(slug);
|
|
7038
7047
|
return this.snapshotInflight.run(slug, async () => {
|
|
7039
7048
|
if (await this.snapshotExists(slug)) {
|
|
@@ -7086,9 +7095,21 @@ running${namespaceMode}`).digest("hex").slice(0, 16)}`;
|
|
|
7086
7095
|
APP_ROOT: WORKDIR,
|
|
7087
7096
|
PROXY_PORT: String(DAEMON_PORT),
|
|
7088
7097
|
ORGFS_SIDECAR_CONFIG_PATH: `${CTL_DIR}/config.json`,
|
|
7089
|
-
ORGFS_SIDECAR_STATUS_PATH: `${CTL_DIR}/status.json
|
|
7098
|
+
ORGFS_SIDECAR_STATUS_PATH: `${CTL_DIR}/status.json`,
|
|
7099
|
+
...this.commitSigning && {
|
|
7100
|
+
GIT_SIGNING_KEY_FILE: SIGNING_KEY_FILE,
|
|
7101
|
+
GIT_SIGNING_KEY_EMAIL: this.commitSigning.email
|
|
7102
|
+
}
|
|
7090
7103
|
};
|
|
7091
7104
|
const envFlags = Object.keys(env).map((k) => `-e ${shellQuote(k)}`).join(" ");
|
|
7105
|
+
if (this.commitSigning) {
|
|
7106
|
+
await this.run(
|
|
7107
|
+
vm,
|
|
7108
|
+
`printf '%s' "$GIT_SIGNING_KEY" | sudo sh -c 'mkdir -p ${dirname(HOST_SIGNING_KEY)} && umask 377 && cat > ${HOST_SIGNING_KEY} && chown 1000:1000 ${HOST_SIGNING_KEY}'`,
|
|
7109
|
+
{ env: { GIT_SIGNING_KEY: this.commitSigning.privateKey } }
|
|
7110
|
+
);
|
|
7111
|
+
}
|
|
7112
|
+
const signingKeyMount = this.commitSigning ? ` -v ${HOST_SIGNING_KEY}:${SIGNING_KEY_FILE}:ro` : "";
|
|
7092
7113
|
await this.run(
|
|
7093
7114
|
vm,
|
|
7094
7115
|
`sudo sh -c ${shellQuote(HOST_SETUP)} && docker run -d --name ${SIDECAR} --restart=always --privileged --device /dev/fuse -e APP_ROOT=${WORKDIR} -e ORGFS_FEED_IDLE_MS=60000 -v ${HOST_ORG_DIR}:${WORKDIR}/org:rshared -v ${HOST_CTL_DIR}:${CTL_DIR} ${shellQuote(this.sidecarImage)}`,
|
|
@@ -7097,7 +7118,7 @@ running${namespaceMode}`).digest("hex").slice(0, 16)}`;
|
|
|
7097
7118
|
await this.run(
|
|
7098
7119
|
vm,
|
|
7099
7120
|
// Codex's read-only sandbox uses bubblewrap inside this per-user VM.
|
|
7100
|
-
`docker run -d --name ${CONTAINER} --restart=always${this.allowUserNamespaces ? " --security-opt seccomp=unconfined --security-opt apparmor=unconfined" : ""} -p ${DAEMON_PORT}:${DAEMON_PORT} -v ${HOST_ORG_DIR}:${WORKDIR}/org:rslave -v ${HOST_CTL_DIR}:${CTL_DIR} ${envFlags} ${shellQuote(this.image)}`,
|
|
7121
|
+
`docker run -d --name ${CONTAINER} --restart=always${this.allowUserNamespaces ? " --security-opt seccomp=unconfined --security-opt apparmor=unconfined" : ""} -p ${DAEMON_PORT}:${DAEMON_PORT} -v ${HOST_ORG_DIR}:${WORKDIR}/org:rslave -v ${HOST_CTL_DIR}:${CTL_DIR}${signingKeyMount} ${envFlags} ${shellQuote(this.image)}`,
|
|
7101
7122
|
{ env, timeoutMs: IMAGE_PULL_TIMEOUT_MS }
|
|
7102
7123
|
);
|
|
7103
7124
|
}
|