@moinulmoin/eden 0.6.0 → 0.7.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.
- package/README.md +13 -9
- package/dist/eve-control-plane.js +32 -54
- package/dist/eve-packaging.d.ts +79 -12
- package/dist/eve-packaging.js +342 -60
- package/dist/eve-runtime-config.d.ts +7 -2
- package/dist/eve-runtime-config.js +7 -2
- package/dist/eve-runtime-image.d.ts +12 -9
- package/dist/eve-runtime-image.js +140 -62
- package/dist/eve.d.ts +1 -2
- package/dist/eve.js +1 -18
- package/dist/index.d.ts +4 -7
- package/dist/index.js +2 -10
- package/package.json +2 -2
package/dist/eve-packaging.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { createHash, } from "node:crypto";
|
|
2
2
|
import { execFile, } from "node:child_process";
|
|
3
|
-
import { chmod, lstat, mkdir, readFile, readlink, readdir, realpath, writeFile, } from "node:fs/promises";
|
|
3
|
+
import { chmod, lstat, mkdir, readFile, readlink, readdir, realpath, rm, writeFile, } from "node:fs/promises";
|
|
4
4
|
import { promisify, } from "node:util";
|
|
5
|
+
import { EVE_HOST_ENVIRONMENT as HOST_ENVIRONMENT, EVE_START_COMMAND as START_COMMAND, } from "./eve-runtime-config.js";
|
|
5
6
|
import { basename, dirname, isAbsolute, join, relative, resolve, } from "node:path";
|
|
6
7
|
const execFileAsync = promisify(execFile);
|
|
8
|
+
/** Snapshot-relative root of Eve's prepared sandbox templates. */
|
|
9
|
+
export const EVE_SANDBOX_CACHE_ROOT = ".eve/sandbox-cache";
|
|
7
10
|
export class EvePackagingError extends Error {
|
|
8
11
|
code;
|
|
9
12
|
subject;
|
|
@@ -27,6 +30,121 @@ export class EvePackagingError extends Error {
|
|
|
27
30
|
// exempt from the ldd check, and the runtime stage sets
|
|
28
31
|
// CBOR_NATIVE_ACCELERATION_DISABLED.
|
|
29
32
|
const IGNORED_BUILDS_GUARD = `node -e 'const m=JSON.parse(require("fs").readFileSync("node_modules/.modules.yaml","utf8"));const b=(m.ignoredBuilds||[]).filter((p)=>!p.startsWith("cbor-extract@"));if(b.length){console.error("ERR_PNPM_IGNORED_BUILDS Ignored build scripts: "+b.join(", "));process.exit(1)}'`;
|
|
33
|
+
/**
|
|
34
|
+
* Eden's temporary fix for upstream https://github.com/vercel/eve/issues/4440
|
|
35
|
+
* (repro: https://github.com/moinulmoin/eve-justbash-resume-repro).
|
|
36
|
+
* Eve's just-bash provider permanently refuses to resume a conversation once
|
|
37
|
+
* the sandbox template changes (skills, `agent/sandbox/workspace/`, or the
|
|
38
|
+
* sandbox definition) and never falls back, so one `eden deploy` update would
|
|
39
|
+
* break every existing conversation's sandbox forever. The isolated builder
|
|
40
|
+
* rewrites one file in the installed Eve copy so an existing session reopens
|
|
41
|
+
* against the current template instead of throwing; user files under
|
|
42
|
+
* `/workspace` always win over the template. The patch applies only when the
|
|
43
|
+
* target file's sha256 equals `EVE_SANDBOX_RESUME_PATCH_KNOWN_SHA256`, and it
|
|
44
|
+
* is removed entirely once upstream ships the fix.
|
|
45
|
+
*/
|
|
46
|
+
export const EVE_SANDBOX_RESUME_PATCH_KNOWN_SHA256 = "0ba0ac3a237c99af2f67a6028f1675bf7c04b22454b4ebfb4cd9d19e5bf5aaf8";
|
|
47
|
+
/** Marker the patched binding always contains; proves the patch shipped. */
|
|
48
|
+
export const EVE_SANDBOX_RESUME_PATCH_SIGNATURE = "edenRefreshJustBashSessionSkills";
|
|
49
|
+
/** Path of the just-bash binding inside the resolved Eve package root. */
|
|
50
|
+
const EVE_JUST_BASH_BINDING_PATH = "dist/src/execution/sandbox/bindings/just-bash.js";
|
|
51
|
+
/** The exact `resume()` implementation in eve 0.68.0, 0.71.2, and 0.72.1. */
|
|
52
|
+
export const EVE_JUST_BASH_RESUME_ORIGINAL = `async resume(e,n,r){let i=requirePreparedJustBashArtifact(n),a=requireJustBashSessionState(r),o=createSandboxProviderIdentity({artifact:i,version:1}),s=sessionRootPath(e,i);if(a.generation!==o||a.rootPath!==s)throw Error(\`just-bash session state is incompatible with this environment.\`);if(!await pathExists(a.rootPath))throw Error(\`just-bash session root "\${a.rootPath}" no longer exists.\`);return await openHandle(e,a.rootPath,t)}`;
|
|
53
|
+
/**
|
|
54
|
+
* The replacement `resume()`: a session whose template generation moved is
|
|
55
|
+
* contained to the same sessions directory and reopened with its authored
|
|
56
|
+
* skills refreshed from the current template. A session folder that is gone
|
|
57
|
+
* (for example a deploy that could not carry it) is recreated from the
|
|
58
|
+
* current template instead of failing every later sandbox call.
|
|
59
|
+
*/
|
|
60
|
+
export const EVE_SANDBOX_RESUME_PATCHED = `async resume(e,n,r){let i=requirePreparedJustBashArtifact(n),a=requireJustBashSessionState(r),o=createSandboxProviderIdentity({artifact:i,version:1}),s=sessionRootPath(e,i);if((a.generation!==o||a.rootPath!==s)&&dirname(a.rootPath)!==dirname(s))throw Error(\`just-bash session state is incompatible with this environment.\`);await ensureSessionRoot(i,a.rootPath);if(a.generation!==o)await edenRefreshJustBashSessionSkills(i.templateRootPath,a.rootPath);return await openHandle(e,a.rootPath,t)}`;
|
|
61
|
+
/**
|
|
62
|
+
* Helpers appended to the patched binding. They use only identifiers the
|
|
63
|
+
* module already imports (`readdir`, `rm`, `join`, `pathExists`,
|
|
64
|
+
* `copyDirectoryAtomically`). Skills live at `$HOME/.agents/skills` inside a
|
|
65
|
+
* just-bash root, so the session keeps the same path relative to its `fs`
|
|
66
|
+
* directory as the template; the template's `fs` is scanned because `$HOME`
|
|
67
|
+
* is only known inside the sandbox.
|
|
68
|
+
*/
|
|
69
|
+
export const EVE_SANDBOX_RESUME_PATCH_HELPERS = `async function edenRefreshJustBashSessionSkills(e,t){let n=await edenFindTemplateSkillsRelativePath(join(e,"fs"));if(n===void 0)return;let r=join(t,"fs",n);await rm(r,{force:!0,recursive:!0}),await copyDirectoryAtomically(join(e,"fs",n),r)}
|
|
70
|
+
async function edenFindTemplateSkillsRelativePath(e){let t=[["",0]];for(;t.length>0;){let n=t.shift(),r=n[0],i=n[1];if(i>3)continue;let a=[];try{a=await readdir(join(e,r),{withFileTypes:!0})}catch{a=[]}for(let o of a){if(!o.isDirectory())continue;let s=r===""?o.name:r+"/"+o.name;if(o.name===".agents")return await pathExists(join(e,s,"skills"))?s+"/skills":void 0;t.push([s,i+1])}}return void 0}
|
|
71
|
+
`;
|
|
72
|
+
/**
|
|
73
|
+
* The CommonJS patcher the isolated builder runs between the frozen install
|
|
74
|
+
* and `eve build` (and again for the production reinstall). It never touches
|
|
75
|
+
* project files, applies only against the known sha256, verifies the
|
|
76
|
+
* replacement matched exactly once, validates the result with `node --check`,
|
|
77
|
+
* and breaks hardlinks by writing a temp file and renaming it into place.
|
|
78
|
+
*/
|
|
79
|
+
export const EVE_SANDBOX_RESUME_PATCH_SCRIPT = `// Eden temporary fix for https://github.com/vercel/eve/issues/4440: Eve's
|
|
80
|
+
// just-bash provider permanently refuses to resume a conversation after the
|
|
81
|
+
// sandbox template changes (skills, agent/sandbox/workspace/, sandbox
|
|
82
|
+
// definition) and never falls back. This rewrites one file in the installed
|
|
83
|
+
// Eve copy so an existing session reopens against the current template. It
|
|
84
|
+
// runs only against the sha256 Eden knows and is removed once upstream
|
|
85
|
+
// ships the fix.
|
|
86
|
+
const fs = require("node:fs");
|
|
87
|
+
const path = require("node:path");
|
|
88
|
+
const crypto = require("node:crypto");
|
|
89
|
+
const { spawnSync } = require("node:child_process");
|
|
90
|
+
const KNOWN_SHA256 = ${JSON.stringify(EVE_SANDBOX_RESUME_PATCH_KNOWN_SHA256)};
|
|
91
|
+
const SIGNATURE = ${JSON.stringify(EVE_SANDBOX_RESUME_PATCH_SIGNATURE)};
|
|
92
|
+
const BINDING_PATH = ${JSON.stringify(EVE_JUST_BASH_BINDING_PATH)};
|
|
93
|
+
const ORIGINAL = ${JSON.stringify(EVE_JUST_BASH_RESUME_ORIGINAL)};
|
|
94
|
+
const PATCHED_RESUME = ${JSON.stringify(EVE_SANDBOX_RESUME_PATCHED)};
|
|
95
|
+
const HELPERS = ${JSON.stringify(EVE_SANDBOX_RESUME_PATCH_HELPERS)};
|
|
96
|
+
function finish(outcome, detail) {
|
|
97
|
+
console.log("eden-eve-sandbox-resume-patch: " + outcome + " (" + detail + ")");
|
|
98
|
+
}
|
|
99
|
+
let packageJsonPath;
|
|
100
|
+
try {
|
|
101
|
+
packageJsonPath = fs.realpathSync("node_modules/eve/package.json");
|
|
102
|
+
} catch {
|
|
103
|
+
finish("absent", "no project-local eve package to patch");
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
const binding = path.join(path.dirname(packageJsonPath), BINDING_PATH);
|
|
107
|
+
let source;
|
|
108
|
+
try {
|
|
109
|
+
source = fs.readFileSync(binding, "utf8");
|
|
110
|
+
} catch {
|
|
111
|
+
finish("absent", "this eve build has no just-bash binding");
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
if (source.includes(SIGNATURE)) {
|
|
115
|
+
finish("applied", "already patched");
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
const digest = crypto.createHash("sha256").update(source).digest("hex");
|
|
119
|
+
if (digest !== KNOWN_SHA256) {
|
|
120
|
+
finish("skipped", "sha256 " + digest + " is not a version Eden knows (eve#4440)");
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
const first = source.indexOf(ORIGINAL);
|
|
124
|
+
if (first === -1 || source.indexOf(ORIGINAL, first + 1) !== -1) {
|
|
125
|
+
console.error("eden-eve-sandbox-resume-patch: the known resume implementation did not match exactly once; refusing to patch");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const patched = source.slice(0, first) + PATCHED_RESUME +
|
|
129
|
+
source.slice(first + ORIGINAL.length) + "\\n" + HELPERS + "\\n";
|
|
130
|
+
const temporary = binding + ".tmp.js";
|
|
131
|
+
fs.rmSync(temporary, { force: true });
|
|
132
|
+
fs.writeFileSync(temporary, patched);
|
|
133
|
+
const parsed = spawnSync(process.execPath, ["--check", temporary], { encoding: "utf8" });
|
|
134
|
+
if (parsed.status !== 0) {
|
|
135
|
+
fs.rmSync(temporary, { force: true });
|
|
136
|
+
console.error("eden-eve-sandbox-resume-patch: the patched file failed node --check; refusing to install it" + (typeof parsed.stderr === "string" ? "\\n" + parsed.stderr : ""));
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
// Rename (not write) so any hardlink to the original inode is broken.
|
|
140
|
+
fs.renameSync(temporary, binding);
|
|
141
|
+
finish("applied", "temporary eve#4440 fix written into the isolated builder image");
|
|
142
|
+
`;
|
|
143
|
+
/** The heredoc COPY + RUN inserted after each frozen install in the builder. */
|
|
144
|
+
const EVE_SANDBOX_RESUME_PATCH_DOCKERFILE_STEP = `COPY <<'EDEN_EVE_PATCH_EOF' /tmp/eden-eve-sandbox-resume-patch.cjs
|
|
145
|
+
${EVE_SANDBOX_RESUME_PATCH_SCRIPT}EDEN_EVE_PATCH_EOF
|
|
146
|
+
RUN node /tmp/eden-eve-sandbox-resume-patch.cjs
|
|
147
|
+
`;
|
|
30
148
|
const INSTALL_COMMAND = [
|
|
31
149
|
"corepack",
|
|
32
150
|
"pnpm",
|
|
@@ -34,14 +152,6 @@ const INSTALL_COMMAND = [
|
|
|
34
152
|
"--frozen-lockfile",
|
|
35
153
|
];
|
|
36
154
|
const BUILD_COMMAND = ["./node_modules/.bin/eve", "build"];
|
|
37
|
-
const START_COMMAND = [
|
|
38
|
-
"./node_modules/.bin/eve",
|
|
39
|
-
"start",
|
|
40
|
-
"--host",
|
|
41
|
-
"0.0.0.0",
|
|
42
|
-
"--port",
|
|
43
|
-
"8080",
|
|
44
|
-
];
|
|
45
155
|
const EVE_ENTRYPOINT = ".output/server/index.mjs";
|
|
46
156
|
const EVE_EXCLUDED_DIRECTORY_NAMES = new Set([
|
|
47
157
|
".eden",
|
|
@@ -78,27 +188,45 @@ const EVE_COMPETING_LOCKFILES = new Set([
|
|
|
78
188
|
"package-lock.json",
|
|
79
189
|
"yarn.lock",
|
|
80
190
|
]);
|
|
81
|
-
|
|
82
|
-
HOST: "0.0.0.0",
|
|
83
|
-
NITRO_HOST: "0.0.0.0",
|
|
84
|
-
PORT: "8080",
|
|
85
|
-
NITRO_PORT: "8080",
|
|
86
|
-
NODE_ENV: "production",
|
|
87
|
-
};
|
|
88
|
-
function sha256(value) {
|
|
191
|
+
export function sha256(value) {
|
|
89
192
|
return createHash("sha256").update(value).digest("hex");
|
|
90
193
|
}
|
|
91
|
-
function jsonBytes(value) {
|
|
194
|
+
export function jsonBytes(value) {
|
|
92
195
|
return Buffer.from(`${JSON.stringify(value)}\n`, "utf8");
|
|
93
196
|
}
|
|
94
|
-
function isWithin(root, candidate) {
|
|
197
|
+
export function isWithin(root, candidate) {
|
|
95
198
|
const normalizedRoot = root.endsWith("/") ? root.slice(0, -1) : root;
|
|
96
199
|
return candidate === normalizedRoot ||
|
|
97
200
|
candidate.startsWith(`${normalizedRoot}/`);
|
|
98
201
|
}
|
|
99
|
-
function safeRelativePath(root, candidate) {
|
|
202
|
+
export function safeRelativePath(root, candidate) {
|
|
100
203
|
return relative(root, candidate).split("\\").join("/");
|
|
101
204
|
}
|
|
205
|
+
export const IMAGE_ID_PATTERN = /^sha256:[0-9a-f]{64}$/u;
|
|
206
|
+
const NODE_IMAGE_PATTERN = /^node:24\.17\.0(?:-[a-z0-9][a-z0-9._-]*)?$/u;
|
|
207
|
+
export function imageReference(nodeImage, reason, remediation) {
|
|
208
|
+
if (!NODE_IMAGE_PATTERN.test(nodeImage.reference) ||
|
|
209
|
+
!IMAGE_ID_PATTERN.test(nodeImage.digest)) {
|
|
210
|
+
throw new EvePackagingError({
|
|
211
|
+
code: "DOCKER_PLATFORM_BLOCKED",
|
|
212
|
+
subject: "node-24-image",
|
|
213
|
+
reason,
|
|
214
|
+
remediation,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return `${nodeImage.reference}@${nodeImage.digest}`;
|
|
218
|
+
}
|
|
219
|
+
function safeDockerEnvironment() {
|
|
220
|
+
return {
|
|
221
|
+
PATH: process.env.PATH,
|
|
222
|
+
HOME: process.env.HOME,
|
|
223
|
+
TMPDIR: process.env.TMPDIR,
|
|
224
|
+
LANG: process.env.LANG,
|
|
225
|
+
LC_ALL: process.env.LC_ALL,
|
|
226
|
+
DOCKER_HOST: process.env.DOCKER_HOST,
|
|
227
|
+
DOCKER_CONTEXT: process.env.DOCKER_CONTEXT,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
102
230
|
function isAllowedSystemAlias(path) {
|
|
103
231
|
const normalized = resolve(path);
|
|
104
232
|
return normalized === "/var" || normalized === "/tmp";
|
|
@@ -770,6 +898,10 @@ async function verifySnapshotInputs(snapshotRoot, inputs) {
|
|
|
770
898
|
if (firstSegment !== undefined && generatedRoots.has(firstSegment)) {
|
|
771
899
|
continue;
|
|
772
900
|
}
|
|
901
|
+
if (relativePath === EVE_SANDBOX_CACHE_ROOT ||
|
|
902
|
+
relativePath.startsWith(`${EVE_SANDBOX_CACHE_ROOT}/`)) {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
773
905
|
const candidate = join(directory, entry.name);
|
|
774
906
|
if (entry.isSymbolicLink() || !entry.isDirectory()) {
|
|
775
907
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
@@ -928,16 +1060,7 @@ export async function eveSnapshotSourceEntries(snapshotRoot) {
|
|
|
928
1060
|
return names;
|
|
929
1061
|
}
|
|
930
1062
|
async function writeDockerBuildFiles(options) {
|
|
931
|
-
|
|
932
|
-
!/^node:24\.17\.0(?:-[a-z0-9][a-z0-9._-]*)?$/u.test(options.nodeImage.reference)) {
|
|
933
|
-
throw new EvePackagingError({
|
|
934
|
-
code: "DOCKER_PLATFORM_BLOCKED",
|
|
935
|
-
subject: "node-24-image",
|
|
936
|
-
reason: "The Linux/amd64 builder requires an immutable Node 24 image digest.",
|
|
937
|
-
remediation: "Supply a verified Node 24 image reference and sha256 digest.",
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
const image = `${options.nodeImage.reference}@${options.nodeImage.digest}`;
|
|
1063
|
+
const image = imageReference(options.nodeImage, "The Linux/amd64 builder requires an immutable Node 24 image digest.", "Supply a verified Node 24 image reference and sha256 digest.");
|
|
941
1064
|
const installSources = ["package.json", "pnpm-lock.yaml"];
|
|
942
1065
|
if ((await lstat(join(options.snapshotRoot, "pnpm-workspace.yaml"))
|
|
943
1066
|
.catch(() => undefined))?.isFile() === true) {
|
|
@@ -956,16 +1079,18 @@ RUN corepack enable \\
|
|
|
956
1079
|
&& test "$(sha256sum pnpm-lock.yaml | cut -d ' ' -f1)" = "${options.lockfileSha256}" \\
|
|
957
1080
|
&& corepack pnpm install --frozen-lockfile --config.node-linker=hoisted --config.strict-dep-builds=false \\
|
|
958
1081
|
&& ${IGNORED_BUILDS_GUARD}
|
|
959
|
-
RUN test "$(sha256sum pnpm-lock.yaml | cut -d ' ' -f1)" = "${options.lockfileSha256}"
|
|
1082
|
+
${EVE_SANDBOX_RESUME_PATCH_DOCKERFILE_STEP}RUN test "$(sha256sum pnpm-lock.yaml | cut -d ' ' -f1)" = "${options.lockfileSha256}"
|
|
960
1083
|
COPY . ./
|
|
961
1084
|
RUN test -x ./node_modules/.bin/eve \\
|
|
962
|
-
&& ./node_modules/.bin/eve build
|
|
1085
|
+
&& ./node_modules/.bin/eve build \\
|
|
1086
|
+
&& mkdir -p .eve/sandbox-cache
|
|
963
1087
|
|
|
964
1088
|
FROM builder AS runtime-deps
|
|
965
1089
|
RUN rm -rf node_modules \\
|
|
966
1090
|
&& corepack pnpm install --frozen-lockfile --prod --config.node-linker=hoisted --config.strict-dep-builds=false \\
|
|
967
1091
|
&& ${IGNORED_BUILDS_GUARD} \\
|
|
968
1092
|
&& for l in node_modules/.bin/*; do t=$(readlink "$l") || continue; case "$t" in /*) ln -sfn "$(realpath --relative-to=node_modules/.bin "$t")" "$l" ;; esac; done
|
|
1093
|
+
${EVE_SANDBOX_RESUME_PATCH_DOCKERFILE_STEP}
|
|
969
1094
|
|
|
970
1095
|
FROM --platform=linux/amd64 ${image} AS runtime
|
|
971
1096
|
WORKDIR /app
|
|
@@ -975,6 +1100,12 @@ ENV HOST=0.0.0.0 \\
|
|
|
975
1100
|
NITRO_PORT=8080 \\
|
|
976
1101
|
NODE_ENV=production
|
|
977
1102
|
COPY --from=builder /workspace/.output /app/.output
|
|
1103
|
+
# Eve's prepared just-bash sandbox template: the builder stage's eve build
|
|
1104
|
+
# prewarm wrote it under /workspace/.eve/sandbox-cache, and the runtime sandbox
|
|
1105
|
+
# resolves it at /app/.eve/sandbox-cache (bash/read_file/write_file fail
|
|
1106
|
+
# without it). The mkdir in the build step guarantees the source exists even
|
|
1107
|
+
# when this Eve build prepared no template.
|
|
1108
|
+
COPY --from=builder /workspace/.eve/sandbox-cache /app/.eve/sandbox-cache
|
|
978
1109
|
${runtimeSourceCopies}
|
|
979
1110
|
COPY --from=runtime-deps /workspace/node_modules /app/node_modules
|
|
980
1111
|
EXPOSE 8080
|
|
@@ -1221,10 +1352,123 @@ async function scanGeneratedOutput(snapshotRoot) {
|
|
|
1221
1352
|
fileCount: files.length,
|
|
1222
1353
|
};
|
|
1223
1354
|
}
|
|
1355
|
+
/**
|
|
1356
|
+
* A generous sanity bound for the prepared sandbox-template tree (templates
|
|
1357
|
+
* carry the sandbox filesystem seeds and authored skills; the minimal Eve
|
|
1358
|
+
* fixture produces ~1 KiB). Anything larger means the builder extracted more
|
|
1359
|
+
* than Eve's build-time prewarm could have written.
|
|
1360
|
+
*/
|
|
1361
|
+
const EVE_SANDBOX_CACHE_MAX_BYTES = 64 * 1024 * 1024;
|
|
1362
|
+
/**
|
|
1363
|
+
* Validates the prepared sandbox-template tree the builder extracted into
|
|
1364
|
+
* `<snapshot>/.eve/sandbox-cache` with the same rigor as `.output`: regular
|
|
1365
|
+
* files and directories only, no symbolic links, no special files, stable
|
|
1366
|
+
* reads inside the immutable snapshot, and a total-size sanity bound.
|
|
1367
|
+
* Returns `null` when this Eve build prepared no sandbox template.
|
|
1368
|
+
*/
|
|
1369
|
+
async function scanGeneratedSandboxCache(snapshotRoot) {
|
|
1370
|
+
const cacheRoot = join(snapshotRoot, EVE_SANDBOX_CACHE_ROOT);
|
|
1371
|
+
const rootDetails = await lstat(cacheRoot).catch(() => undefined);
|
|
1372
|
+
if (rootDetails === undefined)
|
|
1373
|
+
return null;
|
|
1374
|
+
const rootCanonical = await realpath(cacheRoot).catch(() => undefined);
|
|
1375
|
+
if (!rootDetails.isDirectory() ||
|
|
1376
|
+
rootDetails.isSymbolicLink() ||
|
|
1377
|
+
rootCanonical === undefined ||
|
|
1378
|
+
!isWithin(snapshotRoot, resolve(rootCanonical))) {
|
|
1379
|
+
throw new EvePackagingError({
|
|
1380
|
+
code: "UNSUPPORTED_EVE_OUTPUT",
|
|
1381
|
+
subject: EVE_SANDBOX_CACHE_ROOT,
|
|
1382
|
+
reason: "The prepared sandbox template root is missing, a symbolic link, or escapes the immutable snapshot.",
|
|
1383
|
+
remediation: "Rebuild the candidate so the isolated builder extracts a regular .eve/sandbox-cache directory.",
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
const files = [];
|
|
1387
|
+
let totalBytes = 0;
|
|
1388
|
+
const visit = async (directory, relativeDirectory) => {
|
|
1389
|
+
const directoryDetails = await lstat(directory).catch(() => undefined);
|
|
1390
|
+
const directoryCanonical = await realpath(directory).catch(() => undefined);
|
|
1391
|
+
if (directoryDetails === undefined ||
|
|
1392
|
+
!directoryDetails.isDirectory() ||
|
|
1393
|
+
directoryDetails.isSymbolicLink() ||
|
|
1394
|
+
directoryCanonical === undefined ||
|
|
1395
|
+
!isWithin(snapshotRoot, resolve(directoryCanonical))) {
|
|
1396
|
+
throw new EvePackagingError({
|
|
1397
|
+
code: "UNSUPPORTED_EVE_OUTPUT",
|
|
1398
|
+
subject: relativeDirectory,
|
|
1399
|
+
reason: "The prepared sandbox template tree escaped or changed during validation.",
|
|
1400
|
+
remediation: "Rebuild the candidate so the isolated builder extracts regular template files.",
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
1404
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
1405
|
+
for (const entry of entries) {
|
|
1406
|
+
const relativePath = relativeDirectory.length === 0
|
|
1407
|
+
? entry.name
|
|
1408
|
+
: `${relativeDirectory}/${entry.name}`;
|
|
1409
|
+
const candidate = join(directory, entry.name);
|
|
1410
|
+
if (entry.isSymbolicLink()) {
|
|
1411
|
+
throw new EvePackagingError({
|
|
1412
|
+
code: "UNSUPPORTED_EVE_OUTPUT",
|
|
1413
|
+
subject: `${EVE_SANDBOX_CACHE_ROOT}/${relativePath}`,
|
|
1414
|
+
reason: "The prepared sandbox template tree contains a symbolic link.",
|
|
1415
|
+
remediation: "Rebuild the candidate so the isolated builder extracts regular template files only.",
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
if (entry.isDirectory()) {
|
|
1419
|
+
await visit(candidate, relativePath);
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
if (!entry.isFile()) {
|
|
1423
|
+
throw new EvePackagingError({
|
|
1424
|
+
code: "UNSUPPORTED_EVE_OUTPUT",
|
|
1425
|
+
subject: `${EVE_SANDBOX_CACHE_ROOT}/${relativePath}`,
|
|
1426
|
+
reason: "The prepared sandbox template tree contains a device, socket, FIFO, or other unsupported file.",
|
|
1427
|
+
remediation: "Rebuild the candidate so the isolated builder extracts regular template files only.",
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
let stable;
|
|
1431
|
+
try {
|
|
1432
|
+
stable = await readStableFile(candidate, snapshotRoot);
|
|
1433
|
+
}
|
|
1434
|
+
catch {
|
|
1435
|
+
throw new EvePackagingError({
|
|
1436
|
+
code: "UNSUPPORTED_EVE_OUTPUT",
|
|
1437
|
+
subject: `${EVE_SANDBOX_CACHE_ROOT}/${relativePath}`,
|
|
1438
|
+
reason: "The prepared sandbox template file is unreadable or changed during validation.",
|
|
1439
|
+
remediation: "Rebuild the candidate so the isolated builder extracts a stable template tree.",
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
totalBytes += stable.bytes.byteLength;
|
|
1443
|
+
if (totalBytes > EVE_SANDBOX_CACHE_MAX_BYTES) {
|
|
1444
|
+
throw new EvePackagingError({
|
|
1445
|
+
code: "UNSUPPORTED_EVE_OUTPUT",
|
|
1446
|
+
subject: EVE_SANDBOX_CACHE_ROOT,
|
|
1447
|
+
reason: `The prepared sandbox template tree exceeds the ${EVE_SANDBOX_CACHE_MAX_BYTES}-byte sanity bound.`,
|
|
1448
|
+
remediation: "Rebuild the candidate; the extracted template tree must contain only Eve's prepared templates.",
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
files.push({
|
|
1452
|
+
relativePath: `${EVE_SANDBOX_CACHE_ROOT}/${relativePath}`,
|
|
1453
|
+
sha256: stable.sha256,
|
|
1454
|
+
byteLength: stable.bytes.byteLength,
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
};
|
|
1458
|
+
await visit(cacheRoot, "");
|
|
1459
|
+
return {
|
|
1460
|
+
present: true,
|
|
1461
|
+
root: EVE_SANDBOX_CACHE_ROOT,
|
|
1462
|
+
outputDigest: sha256(jsonBytes(files)),
|
|
1463
|
+
fileCount: files.length,
|
|
1464
|
+
totalBytes,
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1224
1467
|
async function assertGeneratedTreesExcludeSecrets(snapshotRoot) {
|
|
1225
1468
|
const roots = [
|
|
1226
1469
|
join(snapshotRoot, "node_modules"),
|
|
1227
1470
|
join(snapshotRoot, ".output"),
|
|
1471
|
+
join(snapshotRoot, EVE_SANDBOX_CACHE_ROOT),
|
|
1228
1472
|
];
|
|
1229
1473
|
const visit = async (directory, relativeDirectory) => {
|
|
1230
1474
|
const directoryDetails = await lstat(directory).catch(() => undefined);
|
|
@@ -1301,7 +1545,7 @@ async function assertGeneratedTreesExcludeSecrets(snapshotRoot) {
|
|
|
1301
1545
|
}
|
|
1302
1546
|
}
|
|
1303
1547
|
}
|
|
1304
|
-
function safeError(error) {
|
|
1548
|
+
export function safeError(error) {
|
|
1305
1549
|
return {
|
|
1306
1550
|
code: error.code,
|
|
1307
1551
|
subject: error.subject,
|
|
@@ -1447,12 +1691,11 @@ function blockedResult(error, extra = {}) {
|
|
|
1447
1691
|
status: "blocked",
|
|
1448
1692
|
returnCode: error.code,
|
|
1449
1693
|
deployable: false,
|
|
1450
|
-
project:
|
|
1694
|
+
project: null,
|
|
1451
1695
|
candidate: null,
|
|
1452
1696
|
snapshot: null,
|
|
1453
1697
|
toolchain: null,
|
|
1454
1698
|
image: null,
|
|
1455
|
-
runtime: null,
|
|
1456
1699
|
secrets: {
|
|
1457
1700
|
runtimeVariableNames: [],
|
|
1458
1701
|
valuesRecorded: false,
|
|
@@ -1464,19 +1707,39 @@ function blockedResult(error, extra = {}) {
|
|
|
1464
1707
|
excludedFromManifestsAndLogs: true,
|
|
1465
1708
|
redactionRegisteredBeforeChildren: false,
|
|
1466
1709
|
},
|
|
1467
|
-
checks:
|
|
1710
|
+
checks: [{
|
|
1468
1711
|
id: error.code,
|
|
1469
1712
|
status: "blocked",
|
|
1470
1713
|
subject: error.subject,
|
|
1471
1714
|
reason: error.message,
|
|
1472
1715
|
remediation: error.remediation,
|
|
1473
1716
|
}],
|
|
1717
|
+
sandboxResumePatch: "absent",
|
|
1474
1718
|
candidateImageId: null,
|
|
1475
1719
|
candidateImageRetainedLocally: false,
|
|
1476
1720
|
writtenPaths: extra.writtenPaths ?? [],
|
|
1477
1721
|
error: safeError(error),
|
|
1478
1722
|
};
|
|
1479
1723
|
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Decides the sandbox-resume patch outcome from the `node_modules` the
|
|
1726
|
+
* builder copied out of the finished image: the shipped just-bash binding is
|
|
1727
|
+
* the single source of truth and stays correct under Docker layer caching
|
|
1728
|
+
* (a cached patch step still ships the patched file). Reading never throws —
|
|
1729
|
+
* an unreadable tree counts as `absent`.
|
|
1730
|
+
*/
|
|
1731
|
+
async function detectEveSandboxResumePatch(snapshotRoot) {
|
|
1732
|
+
try {
|
|
1733
|
+
const packageJsonPath = await realpath(join(snapshotRoot, "node_modules/eve/package.json"));
|
|
1734
|
+
const binding = await readFile(join(dirname(packageJsonPath), EVE_JUST_BASH_BINDING_PATH), "utf8");
|
|
1735
|
+
return binding.includes(EVE_SANDBOX_RESUME_PATCH_SIGNATURE)
|
|
1736
|
+
? "applied"
|
|
1737
|
+
: "skipped";
|
|
1738
|
+
}
|
|
1739
|
+
catch {
|
|
1740
|
+
return "absent";
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1480
1743
|
async function currentInputIdentity(runtimeConfig) {
|
|
1481
1744
|
const token = (value) => {
|
|
1482
1745
|
if (typeof value === "string")
|
|
@@ -1743,7 +2006,9 @@ export async function buildEveProjectSnapshot(options) {
|
|
|
1743
2006
|
return blockedResult(cleanupError ?? dependencyError, { writtenPaths });
|
|
1744
2007
|
}
|
|
1745
2008
|
const eve = await resolveProjectLocalEve(snapshotRoot);
|
|
2009
|
+
const sandboxResumePatch = await detectEveSandboxResumePatch(snapshotRoot);
|
|
1746
2010
|
const output = await scanGeneratedOutput(snapshotRoot);
|
|
2011
|
+
const sandboxCache = await scanGeneratedSandboxCache(snapshotRoot);
|
|
1747
2012
|
await assertGeneratedTreesExcludeSecrets(snapshotRoot);
|
|
1748
2013
|
const snapshotSourceDigest = await snapshotDigest(snapshotRoot);
|
|
1749
2014
|
const runtimeManifestPath = join(generationRoot, "runtime-manifest.json");
|
|
@@ -1758,6 +2023,7 @@ export async function buildEveProjectSnapshot(options) {
|
|
|
1758
2023
|
sourceDigest: initialInputs.sourceDigest,
|
|
1759
2024
|
snapshotDigest: snapshotSourceDigest,
|
|
1760
2025
|
generatedOutput: output,
|
|
2026
|
+
sandboxCache,
|
|
1761
2027
|
artifactPath: EVE_ENTRYPOINT,
|
|
1762
2028
|
platform: "linux/amd64",
|
|
1763
2029
|
runtimeVariableNames,
|
|
@@ -1791,10 +2057,8 @@ export async function buildEveProjectSnapshot(options) {
|
|
|
1791
2057
|
excludedCategories: [...new Set(initialInputs.excludedRelativePaths.map((path) => isPathExcluded(path, undefined).category ?? "generated-state"))].sort(),
|
|
1792
2058
|
sourceRaceChecked: true,
|
|
1793
2059
|
};
|
|
1794
|
-
if (
|
|
1795
|
-
|
|
1796
|
-
(buildResult.imageId !== undefined &&
|
|
1797
|
-
buildResult.imagePlatform !== "linux/amd64")) {
|
|
2060
|
+
if (buildResult.imageId !== undefined &&
|
|
2061
|
+
!IMAGE_ID_PATTERN.test(buildResult.imageId)) {
|
|
1798
2062
|
const imageError = new EvePackagingError({
|
|
1799
2063
|
code: "DOCKER_PLATFORM_BLOCKED",
|
|
1800
2064
|
subject: "linux/amd64 image",
|
|
@@ -1835,6 +2099,7 @@ export async function buildEveProjectSnapshot(options) {
|
|
|
1835
2099
|
sourceDigest: initialInputs.sourceDigest,
|
|
1836
2100
|
snapshotDigest: snapshotSourceDigest,
|
|
1837
2101
|
generatedOutput: output,
|
|
2102
|
+
sandboxCache,
|
|
1838
2103
|
...(initialRuntimeInputIdentity === undefined
|
|
1839
2104
|
? {}
|
|
1840
2105
|
: { runtimeConfigInputIdentity: initialRuntimeInputIdentity }),
|
|
@@ -1868,7 +2133,6 @@ export async function buildEveProjectSnapshot(options) {
|
|
|
1868
2133
|
},
|
|
1869
2134
|
image,
|
|
1870
2135
|
candidate,
|
|
1871
|
-
runtime: null,
|
|
1872
2136
|
secrets: {
|
|
1873
2137
|
runtimeVariableNames,
|
|
1874
2138
|
valuesRecorded: false,
|
|
@@ -1916,7 +2180,17 @@ export async function buildEveProjectSnapshot(options) {
|
|
|
1916
2180
|
reason: "The resolved Eve executable is inside the isolated project dependency tree.",
|
|
1917
2181
|
remediation: null,
|
|
1918
2182
|
},
|
|
2183
|
+
...(sandboxResumePatch === "applied"
|
|
2184
|
+
? [{
|
|
2185
|
+
id: "EVE_SANDBOX_RESUME_PATCH",
|
|
2186
|
+
status: "pass",
|
|
2187
|
+
subject: "eve-sandbox-resume",
|
|
2188
|
+
reason: "applied temporary fix for eve#4440",
|
|
2189
|
+
remediation: null,
|
|
2190
|
+
}]
|
|
2191
|
+
: []),
|
|
1919
2192
|
],
|
|
2193
|
+
sandboxResumePatch,
|
|
1920
2194
|
candidateImageId: buildResult.imageId ?? null,
|
|
1921
2195
|
candidateImageRetainedLocally: buildResult.imageId !== undefined,
|
|
1922
2196
|
writtenPaths,
|
|
@@ -2049,15 +2323,7 @@ export function createDockerEveProjectBuilder(options) {
|
|
|
2049
2323
|
});
|
|
2050
2324
|
}
|
|
2051
2325
|
const imageIdFile = join(request.generationRoot, "image-id");
|
|
2052
|
-
const safeEnv =
|
|
2053
|
-
PATH: process.env.PATH,
|
|
2054
|
-
HOME: process.env.HOME,
|
|
2055
|
-
TMPDIR: process.env.TMPDIR,
|
|
2056
|
-
LANG: process.env.LANG,
|
|
2057
|
-
LC_ALL: process.env.LC_ALL,
|
|
2058
|
-
DOCKER_HOST: process.env.DOCKER_HOST,
|
|
2059
|
-
DOCKER_CONTEXT: process.env.DOCKER_CONTEXT,
|
|
2060
|
-
};
|
|
2326
|
+
const safeEnv = safeDockerEnvironment();
|
|
2061
2327
|
let containerId;
|
|
2062
2328
|
let imageBuilt = false;
|
|
2063
2329
|
let retainImage = false;
|
|
@@ -2100,7 +2366,7 @@ export function createDockerEveProjectBuilder(options) {
|
|
|
2100
2366
|
], { env: safeEnv, cwd: request.generationRoot, maxBuffer: 1024 * 1024 });
|
|
2101
2367
|
imageBuilt = true;
|
|
2102
2368
|
builtImageId = (await readFile(imageIdFile, "utf8")).trim();
|
|
2103
|
-
if (
|
|
2369
|
+
if (!IMAGE_ID_PATTERN.test(builtImageId)) {
|
|
2104
2370
|
throw new EvePackagingError({
|
|
2105
2371
|
code: "DOCKER_PLATFORM_BLOCKED",
|
|
2106
2372
|
subject: "image identity",
|
|
@@ -2139,6 +2405,30 @@ export function createDockerEveProjectBuilder(options) {
|
|
|
2139
2405
|
}
|
|
2140
2406
|
await execFileAsync(dockerCommand, ["cp", `${containerId}:/app/.output`, join(request.snapshotRoot, ".output")], { env: safeEnv, cwd: request.generationRoot });
|
|
2141
2407
|
await execFileAsync(dockerCommand, ["cp", `${containerId}:/app/node_modules`, join(request.snapshotRoot, "node_modules")], { env: safeEnv, cwd: request.generationRoot });
|
|
2408
|
+
// The builder stage's `eve build` prewarm writes the just-bash sandbox
|
|
2409
|
+
// template under its workdir; the runtime stage copies it to
|
|
2410
|
+
// /app/.eve/sandbox-cache (the mkdir in the Dockerfile guarantees the
|
|
2411
|
+
// path exists). Extract exactly that subtree so runtime sandboxes can
|
|
2412
|
+
// resolve their template; never the rest of `.eve` (sessions, locks,
|
|
2413
|
+
// builds). Treated as absent when the container has no such path.
|
|
2414
|
+
const sandboxCacheTarget = join(request.snapshotRoot, EVE_SANDBOX_CACHE_ROOT);
|
|
2415
|
+
await ensureSnapshotDirectory(request.snapshotRoot, dirname(sandboxCacheTarget));
|
|
2416
|
+
try {
|
|
2417
|
+
await execFileAsync(dockerCommand, ["cp", `${containerId}:/app/${EVE_SANDBOX_CACHE_ROOT}`, sandboxCacheTarget], { env: safeEnv, cwd: request.generationRoot });
|
|
2418
|
+
}
|
|
2419
|
+
catch (error) {
|
|
2420
|
+
const stderr = typeof error === "object" &&
|
|
2421
|
+
error !== null &&
|
|
2422
|
+
"stderr" in error &&
|
|
2423
|
+
typeof error.stderr === "string"
|
|
2424
|
+
? error.stderr
|
|
2425
|
+
: "";
|
|
2426
|
+
if (!/(?:could not find|no such|not found|does not exist)/iu.test(stderr)) {
|
|
2427
|
+
throw error;
|
|
2428
|
+
}
|
|
2429
|
+
// Absent: remove the `.eve` parent this extraction created.
|
|
2430
|
+
await rm(dirname(sandboxCacheTarget), { recursive: true, force: true }).catch(() => undefined);
|
|
2431
|
+
}
|
|
2142
2432
|
const result = {
|
|
2143
2433
|
imageId: builtImageId,
|
|
2144
2434
|
imagePlatform: "linux/amd64",
|
|
@@ -2174,15 +2464,7 @@ export function createDockerEveProjectBuilder(options) {
|
|
|
2174
2464
|
const imageReference = result.imageReference;
|
|
2175
2465
|
if (imageReference === undefined)
|
|
2176
2466
|
return;
|
|
2177
|
-
const safeEnv =
|
|
2178
|
-
PATH: process.env.PATH,
|
|
2179
|
-
HOME: process.env.HOME,
|
|
2180
|
-
TMPDIR: process.env.TMPDIR,
|
|
2181
|
-
LANG: process.env.LANG,
|
|
2182
|
-
LC_ALL: process.env.LC_ALL,
|
|
2183
|
-
DOCKER_HOST: process.env.DOCKER_HOST,
|
|
2184
|
-
DOCKER_CONTEXT: process.env.DOCKER_CONTEXT,
|
|
2185
|
-
};
|
|
2467
|
+
const safeEnv = safeDockerEnvironment();
|
|
2186
2468
|
await execFileAsync(dockerCommand, ["image", "rm", "--force", imageReference], { env: safeEnv });
|
|
2187
2469
|
const remainingImage = await execFileAsync(dockerCommand, ["image", "inspect", imageReference, "--format", "{{.Id}}"], { env: safeEnv }).catch(() => undefined);
|
|
2188
2470
|
if (remainingImage !== undefined && remainingImage.stdout.trim().length > 0) {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
export declare const EVE_RESERVED_HOST_VARIABLES: readonly ["HOST", "NITRO_HOST", "PORT", "NITRO_PORT", "NODE_ENV", "NODE_EXTRA_CA_CERTS", "WORKFLOW_LOCAL_BASE_URL", "EDEN_WORLD_URL", "EDEN_EVE_DEPLOYMENT_ID", "EDEN_EVE_GENERATION_ID"];
|
|
2
2
|
export type EveReservedHostVariable = (typeof EVE_RESERVED_HOST_VARIABLES)[number];
|
|
3
3
|
export declare const EVE_START_COMMAND: readonly ["./node_modules/.bin/eve", "start", "--host", "0.0.0.0", "--port", "8080"];
|
|
4
|
+
export declare const EVE_HOST_ENVIRONMENT: Readonly<{
|
|
5
|
+
readonly HOST: "0.0.0.0";
|
|
6
|
+
readonly NITRO_HOST: "0.0.0.0";
|
|
7
|
+
readonly PORT: "8080";
|
|
8
|
+
readonly NITRO_PORT: "8080";
|
|
9
|
+
readonly NODE_ENV: "production";
|
|
10
|
+
}>;
|
|
4
11
|
type EveRuntimeValueMap = Readonly<Record<string, string>>;
|
|
5
12
|
export type EveRuntimeConfigErrorCode = "EVE_ENV_FILE_NOT_FOUND" | "EVE_ENV_FILE_INVALID" | "EVE_ENV_FILE_UNREADABLE" | "EVE_ENV_FILE_ENCODING" | "EVE_ENV_FILE_MALFORMED" | "EVE_ENV_FILE_DUPLICATE" | "EVE_ENV_RESERVED_VARIABLE" | "EVE_ENV_FILE_RACE" | "EVE_RUNTIME_INJECTION_INVALID" | "EVE_RUNTIME_PROTECTED_STORE_UNAVAILABLE" | "EVE_RUNTIME_PROTECTED_UPLOAD_FAILED" | "EVE_RUNTIME_LOCAL_INJECTION_UNSUPPORTED";
|
|
6
13
|
export declare class EveRuntimeConfigError extends Error {
|
|
@@ -119,8 +126,6 @@ export declare class EveRuntimeConfig {
|
|
|
119
126
|
export declare function readEveRuntimeConfig(inputPath: string, options?: {
|
|
120
127
|
readonly cwd?: string;
|
|
121
128
|
}): Promise<EveRuntimeConfig>;
|
|
122
|
-
export declare const parseEveRuntimeConfig: typeof readEveRuntimeConfig;
|
|
123
|
-
export declare const loadEveRuntimeConfig: typeof readEveRuntimeConfig;
|
|
124
129
|
export declare function prepareEveRuntimeInjection(config: EveRuntimeConfig, options: EveRuntimeInjectionOptions): Promise<EveRuntimeInjection>;
|
|
125
130
|
export {};
|
|
126
131
|
//# sourceMappingURL=eve-runtime-config.d.ts.map
|
|
@@ -21,6 +21,13 @@ export const EVE_START_COMMAND = Object.freeze([
|
|
|
21
21
|
"--port",
|
|
22
22
|
"8080",
|
|
23
23
|
]);
|
|
24
|
+
export const EVE_HOST_ENVIRONMENT = Object.freeze({
|
|
25
|
+
HOST: "0.0.0.0",
|
|
26
|
+
NITRO_HOST: "0.0.0.0",
|
|
27
|
+
PORT: "8080",
|
|
28
|
+
NITRO_PORT: "8080",
|
|
29
|
+
NODE_ENV: "production",
|
|
30
|
+
});
|
|
24
31
|
const EVE_ENVIRONMENT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
25
32
|
const EVE_RUNTIME_METADATA_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
26
33
|
const EVE_ENV_FILE_SOURCE = "--env-file";
|
|
@@ -323,8 +330,6 @@ export async function readEveRuntimeConfig(inputPath, options = {}) {
|
|
|
323
330
|
activeRedactionRegistries.add(redaction);
|
|
324
331
|
return EveRuntimeConfig.from(observation, values, redaction);
|
|
325
332
|
}
|
|
326
|
-
export const parseEveRuntimeConfig = readEveRuntimeConfig;
|
|
327
|
-
export const loadEveRuntimeConfig = readEveRuntimeConfig;
|
|
328
333
|
function validateProtectedPutResult(result) {
|
|
329
334
|
if (typeof result !== "object" ||
|
|
330
335
|
result === null ||
|