@vm0/runner 3.19.1 → 3.19.2
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/index.js +97 -83
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -3046,6 +3046,97 @@ async function uploadNetworkLogs(apiUrl, sandboxToken, runId) {
|
|
|
3046
3046
|
|
|
3047
3047
|
// src/lib/executor/index.ts
|
|
3048
3048
|
var logger9 = createLogger("Executor");
|
|
3049
|
+
function setupNetworkSecurity(context, vethNsIp) {
|
|
3050
|
+
const firewallConfig = context.experimentalFirewall;
|
|
3051
|
+
if (firewallConfig?.enabled) {
|
|
3052
|
+
const mitmEnabled = firewallConfig.experimental_mitm ?? false;
|
|
3053
|
+
const sealSecretsEnabled = firewallConfig.experimental_seal_secrets ?? false;
|
|
3054
|
+
logger9.log(
|
|
3055
|
+
`Setting up network security for VM ${vethNsIp} (mitm=${mitmEnabled}, sealSecrets=${sealSecretsEnabled})`
|
|
3056
|
+
);
|
|
3057
|
+
getVMRegistry().register(vethNsIp, context.runId, context.sandboxToken, {
|
|
3058
|
+
firewallRules: firewallConfig?.rules,
|
|
3059
|
+
mitmEnabled,
|
|
3060
|
+
sealSecretsEnabled
|
|
3061
|
+
});
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
async function prepareGuest(guest, context, config) {
|
|
3065
|
+
if (config.firecracker.snapshot) {
|
|
3066
|
+
const timestamp = (Date.now() / 1e3).toFixed(3);
|
|
3067
|
+
await guest.execAsRoot(`date -s "@${timestamp}"`);
|
|
3068
|
+
}
|
|
3069
|
+
if (context.storageManifest) {
|
|
3070
|
+
await withSandboxTiming(
|
|
3071
|
+
"storage_download",
|
|
3072
|
+
() => downloadStorages(guest, context.storageManifest)
|
|
3073
|
+
);
|
|
3074
|
+
}
|
|
3075
|
+
if (context.resumeSession) {
|
|
3076
|
+
await withSandboxTiming(
|
|
3077
|
+
"session_restore",
|
|
3078
|
+
() => restoreSessionHistory(
|
|
3079
|
+
guest,
|
|
3080
|
+
context.resumeSession,
|
|
3081
|
+
context.workingDir,
|
|
3082
|
+
context.cliAgentType || "claude-code"
|
|
3083
|
+
)
|
|
3084
|
+
);
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
async function checkForOOM(guest, exitCode, durationMs) {
|
|
3088
|
+
if (exitCode === 137 || exitCode === 9) {
|
|
3089
|
+
const dmesgCheck = await guest.exec(
|
|
3090
|
+
`sudo dmesg | tail -20 | grep -iE "killed|oom" 2>/dev/null`
|
|
3091
|
+
);
|
|
3092
|
+
if (dmesgCheck.stdout.toLowerCase().includes("oom") || dmesgCheck.stdout.toLowerCase().includes("killed")) {
|
|
3093
|
+
logger9.log(`OOM detected: ${dmesgCheck.stdout}`);
|
|
3094
|
+
recordOperation({
|
|
3095
|
+
actionType: "agent_execute",
|
|
3096
|
+
durationMs,
|
|
3097
|
+
success: false
|
|
3098
|
+
});
|
|
3099
|
+
return {
|
|
3100
|
+
exitCode: 1,
|
|
3101
|
+
error: "Agent process killed by OOM killer"
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
return null;
|
|
3106
|
+
}
|
|
3107
|
+
async function cleanupJob(context, options, config, vethNsIp, vm, vsockClient, vmId) {
|
|
3108
|
+
if (context.experimentalFirewall?.enabled && vethNsIp) {
|
|
3109
|
+
logger9.log(`Cleaning up network security for VM ${vethNsIp}`);
|
|
3110
|
+
getVMRegistry().unregister(vethNsIp);
|
|
3111
|
+
if (!options.benchmarkMode) {
|
|
3112
|
+
try {
|
|
3113
|
+
await uploadNetworkLogs(
|
|
3114
|
+
config.server.url,
|
|
3115
|
+
context.sandboxToken,
|
|
3116
|
+
context.runId
|
|
3117
|
+
);
|
|
3118
|
+
} catch (err) {
|
|
3119
|
+
logger9.error(
|
|
3120
|
+
`Failed to upload network logs: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
3121
|
+
);
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
if (vm) {
|
|
3126
|
+
if (vsockClient) {
|
|
3127
|
+
const acked = await vsockClient.shutdown(2e3);
|
|
3128
|
+
if (acked) {
|
|
3129
|
+
logger9.log(`Guest acknowledged shutdown`);
|
|
3130
|
+
} else {
|
|
3131
|
+
logger9.log(`Guest shutdown timeout, proceeding with SIGKILL`);
|
|
3132
|
+
}
|
|
3133
|
+
vsockClient.close();
|
|
3134
|
+
}
|
|
3135
|
+
logger9.log(`Cleaning up VM ${vmId}...`);
|
|
3136
|
+
await withSandboxTiming("cleanup", () => vm.kill());
|
|
3137
|
+
}
|
|
3138
|
+
await clearSandboxContext();
|
|
3139
|
+
}
|
|
3049
3140
|
async function executeJob(context, config, options = {}) {
|
|
3050
3141
|
setSandboxContext({
|
|
3051
3142
|
apiUrl: config.server.url,
|
|
@@ -3109,43 +3200,11 @@ async function executeJob(context, config, options = {}) {
|
|
|
3109
3200
|
`VM ${vmId} started, guest IP: ${guestIp}, veth NS IP: ${vethNsIp}`
|
|
3110
3201
|
);
|
|
3111
3202
|
const envVars = buildEnvironmentVariables(context, config.server.url);
|
|
3112
|
-
|
|
3113
|
-
if (firewallConfig?.enabled) {
|
|
3114
|
-
const mitmEnabled = firewallConfig.experimental_mitm ?? false;
|
|
3115
|
-
const sealSecretsEnabled = firewallConfig.experimental_seal_secrets ?? false;
|
|
3116
|
-
logger9.log(
|
|
3117
|
-
`Setting up network security for VM ${vethNsIp} (mitm=${mitmEnabled}, sealSecrets=${sealSecretsEnabled})`
|
|
3118
|
-
);
|
|
3119
|
-
getVMRegistry().register(vethNsIp, context.runId, context.sandboxToken, {
|
|
3120
|
-
firewallRules: firewallConfig?.rules,
|
|
3121
|
-
mitmEnabled,
|
|
3122
|
-
sealSecretsEnabled
|
|
3123
|
-
});
|
|
3124
|
-
}
|
|
3203
|
+
setupNetworkSecurity(context, vethNsIp);
|
|
3125
3204
|
logger9.log(`Waiting for guest connection...`);
|
|
3126
3205
|
await withSandboxTiming("guest_wait", () => guestConnectionPromise);
|
|
3127
3206
|
logger9.log(`Guest client ready`);
|
|
3128
|
-
|
|
3129
|
-
const timestamp = (Date.now() / 1e3).toFixed(3);
|
|
3130
|
-
await guest.execAsRoot(`date -s "@${timestamp}"`);
|
|
3131
|
-
}
|
|
3132
|
-
if (context.storageManifest) {
|
|
3133
|
-
await withSandboxTiming(
|
|
3134
|
-
"storage_download",
|
|
3135
|
-
() => downloadStorages(guest, context.storageManifest)
|
|
3136
|
-
);
|
|
3137
|
-
}
|
|
3138
|
-
if (context.resumeSession) {
|
|
3139
|
-
await withSandboxTiming(
|
|
3140
|
-
"session_restore",
|
|
3141
|
-
() => restoreSessionHistory(
|
|
3142
|
-
guest,
|
|
3143
|
-
context.resumeSession,
|
|
3144
|
-
context.workingDir,
|
|
3145
|
-
context.cliAgentType || "claude-code"
|
|
3146
|
-
)
|
|
3147
|
-
);
|
|
3148
|
-
}
|
|
3207
|
+
await prepareGuest(guest, context, config);
|
|
3149
3208
|
const systemLogFile = `/tmp/vm0-system-${context.runId}.log`;
|
|
3150
3209
|
const startTime = Date.now();
|
|
3151
3210
|
const maxWaitMs = 2 * 60 * 60 * 1e3;
|
|
@@ -3182,23 +3241,8 @@ async function executeJob(context, config, options = {}) {
|
|
|
3182
3241
|
}
|
|
3183
3242
|
const durationMs = Date.now() - startTime;
|
|
3184
3243
|
const duration = Math.round(durationMs / 1e3);
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
`sudo dmesg | tail -20 | grep -iE "killed|oom" 2>/dev/null`
|
|
3188
|
-
);
|
|
3189
|
-
if (dmesgCheck.stdout.toLowerCase().includes("oom") || dmesgCheck.stdout.toLowerCase().includes("killed")) {
|
|
3190
|
-
logger9.log(`OOM detected: ${dmesgCheck.stdout}`);
|
|
3191
|
-
recordOperation({
|
|
3192
|
-
actionType: "agent_execute",
|
|
3193
|
-
durationMs,
|
|
3194
|
-
success: false
|
|
3195
|
-
});
|
|
3196
|
-
return {
|
|
3197
|
-
exitCode: 1,
|
|
3198
|
-
error: "Agent process killed by OOM killer"
|
|
3199
|
-
};
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3244
|
+
const oomResult = await checkForOOM(guest, exitCode, durationMs);
|
|
3245
|
+
if (oomResult) return oomResult;
|
|
3202
3246
|
recordOperation({
|
|
3203
3247
|
actionType: "agent_execute",
|
|
3204
3248
|
durationMs,
|
|
@@ -3222,37 +3266,7 @@ async function executeJob(context, config, options = {}) {
|
|
|
3222
3266
|
error: errorMsg
|
|
3223
3267
|
};
|
|
3224
3268
|
} finally {
|
|
3225
|
-
|
|
3226
|
-
logger9.log(`Cleaning up network security for VM ${vethNsIp}`);
|
|
3227
|
-
getVMRegistry().unregister(vethNsIp);
|
|
3228
|
-
if (!options.benchmarkMode) {
|
|
3229
|
-
try {
|
|
3230
|
-
await uploadNetworkLogs(
|
|
3231
|
-
config.server.url,
|
|
3232
|
-
context.sandboxToken,
|
|
3233
|
-
context.runId
|
|
3234
|
-
);
|
|
3235
|
-
} catch (err) {
|
|
3236
|
-
logger9.error(
|
|
3237
|
-
`Failed to upload network logs: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
3238
|
-
);
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
if (vm) {
|
|
3243
|
-
if (vsockClient) {
|
|
3244
|
-
const acked = await vsockClient.shutdown(2e3);
|
|
3245
|
-
if (acked) {
|
|
3246
|
-
logger9.log(`Guest acknowledged shutdown`);
|
|
3247
|
-
} else {
|
|
3248
|
-
logger9.log(`Guest shutdown timeout, proceeding with SIGKILL`);
|
|
3249
|
-
}
|
|
3250
|
-
vsockClient.close();
|
|
3251
|
-
}
|
|
3252
|
-
logger9.log(`Cleaning up VM ${vmId}...`);
|
|
3253
|
-
await withSandboxTiming("cleanup", () => vm.kill());
|
|
3254
|
-
}
|
|
3255
|
-
await clearSandboxContext();
|
|
3269
|
+
await cleanupJob(context, options, config, vethNsIp, vm, vsockClient, vmId);
|
|
3256
3270
|
}
|
|
3257
3271
|
}
|
|
3258
3272
|
|
|
@@ -4681,7 +4695,7 @@ var snapshotCommand = new Command5("snapshot").description("Generate a Firecrack
|
|
|
4681
4695
|
);
|
|
4682
4696
|
|
|
4683
4697
|
// src/index.ts
|
|
4684
|
-
var version = true ? "3.19.
|
|
4698
|
+
var version = true ? "3.19.2" : "0.1.0";
|
|
4685
4699
|
program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
|
|
4686
4700
|
program.addCommand(startCommand);
|
|
4687
4701
|
program.addCommand(doctorCommand);
|