@vm0/runner 3.5.0 → 3.6.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/index.js +146 -227
- package/package.json +1 -6
package/index.js
CHANGED
|
@@ -857,53 +857,51 @@ function checkNetworkPrerequisites() {
|
|
|
857
857
|
errors
|
|
858
858
|
};
|
|
859
859
|
}
|
|
860
|
-
async function
|
|
861
|
-
const comment =
|
|
860
|
+
async function setupCIDRProxyRules(proxyPort) {
|
|
861
|
+
const comment = "vm0:cidr-proxy";
|
|
862
862
|
console.log(
|
|
863
|
-
`Setting up proxy rules for
|
|
863
|
+
`Setting up CIDR proxy rules for ${BRIDGE_CIDR} -> port ${proxyPort}`
|
|
864
864
|
);
|
|
865
865
|
try {
|
|
866
866
|
await execCommand(
|
|
867
|
-
`iptables -t nat -C PREROUTING -s ${
|
|
867
|
+
`iptables -t nat -C PREROUTING -s ${BRIDGE_CIDR} -p tcp --dport 80 -j REDIRECT --to-port ${proxyPort} -m comment --comment "${comment}"`
|
|
868
868
|
);
|
|
869
|
-
console.log(
|
|
869
|
+
console.log("CIDR proxy rule for port 80 already exists");
|
|
870
870
|
} catch {
|
|
871
871
|
await execCommand(
|
|
872
|
-
`iptables -t nat -A PREROUTING -s ${
|
|
872
|
+
`iptables -t nat -A PREROUTING -s ${BRIDGE_CIDR} -p tcp --dport 80 -j REDIRECT --to-port ${proxyPort} -m comment --comment "${comment}"`
|
|
873
873
|
);
|
|
874
|
-
console.log(
|
|
874
|
+
console.log("CIDR proxy rule for port 80 added");
|
|
875
875
|
}
|
|
876
876
|
try {
|
|
877
877
|
await execCommand(
|
|
878
|
-
`iptables -t nat -C PREROUTING -s ${
|
|
878
|
+
`iptables -t nat -C PREROUTING -s ${BRIDGE_CIDR} -p tcp --dport 443 -j REDIRECT --to-port ${proxyPort} -m comment --comment "${comment}"`
|
|
879
879
|
);
|
|
880
|
-
console.log(
|
|
880
|
+
console.log("CIDR proxy rule for port 443 already exists");
|
|
881
881
|
} catch {
|
|
882
882
|
await execCommand(
|
|
883
|
-
`iptables -t nat -A PREROUTING -s ${
|
|
883
|
+
`iptables -t nat -A PREROUTING -s ${BRIDGE_CIDR} -p tcp --dport 443 -j REDIRECT --to-port ${proxyPort} -m comment --comment "${comment}"`
|
|
884
884
|
);
|
|
885
|
-
console.log(
|
|
885
|
+
console.log("CIDR proxy rule for port 443 added");
|
|
886
886
|
}
|
|
887
|
-
console.log(`Proxy rules configured for VM ${vmIp}`);
|
|
888
887
|
}
|
|
889
|
-
async function
|
|
890
|
-
const comment =
|
|
891
|
-
console.log(
|
|
888
|
+
async function cleanupCIDRProxyRules(proxyPort) {
|
|
889
|
+
const comment = "vm0:cidr-proxy";
|
|
890
|
+
console.log("Cleaning up CIDR proxy rules...");
|
|
892
891
|
try {
|
|
893
892
|
await execCommand(
|
|
894
|
-
`iptables -t nat -D PREROUTING -s ${
|
|
893
|
+
`iptables -t nat -D PREROUTING -s ${BRIDGE_CIDR} -p tcp --dport 80 -j REDIRECT --to-port ${proxyPort} -m comment --comment "${comment}"`
|
|
895
894
|
);
|
|
896
|
-
console.log(
|
|
895
|
+
console.log("CIDR proxy rule for port 80 removed");
|
|
897
896
|
} catch {
|
|
898
897
|
}
|
|
899
898
|
try {
|
|
900
899
|
await execCommand(
|
|
901
|
-
`iptables -t nat -D PREROUTING -s ${
|
|
900
|
+
`iptables -t nat -D PREROUTING -s ${BRIDGE_CIDR} -p tcp --dport 443 -j REDIRECT --to-port ${proxyPort} -m comment --comment "${comment}"`
|
|
902
901
|
);
|
|
903
|
-
console.log(
|
|
902
|
+
console.log("CIDR proxy rule for port 443 removed");
|
|
904
903
|
} catch {
|
|
905
904
|
}
|
|
906
|
-
console.log(`Proxy rules cleanup complete for VM ${vmIp}`);
|
|
907
905
|
}
|
|
908
906
|
async function listTapDevices() {
|
|
909
907
|
try {
|
|
@@ -8654,7 +8652,10 @@ def tls_clienthello(data: tls.ClientHelloData) -> None:
|
|
|
8654
8652
|
|
|
8655
8653
|
vm_info = get_vm_info(client_ip)
|
|
8656
8654
|
if not vm_info:
|
|
8657
|
-
|
|
8655
|
+
# Not a registered VM - pass through without MITM interception
|
|
8656
|
+
# This is critical for CIDR-based rules where all VM traffic is redirected
|
|
8657
|
+
data.ignore_connection = True
|
|
8658
|
+
return
|
|
8658
8659
|
|
|
8659
8660
|
# If MITM is enabled, let the normal flow handle it
|
|
8660
8661
|
if vm_info.get("mitmEnabled", False):
|
|
@@ -9125,171 +9126,80 @@ function initProxyManager(config) {
|
|
|
9125
9126
|
return globalProxyManager;
|
|
9126
9127
|
}
|
|
9127
9128
|
|
|
9128
|
-
// src/lib/metrics/
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
var meterProvider = null;
|
|
9138
|
-
var initialized = false;
|
|
9139
|
-
var enabled = false;
|
|
9140
|
-
var _runnerLabel = "";
|
|
9141
|
-
function initMetrics(config) {
|
|
9142
|
-
if (initialized) return;
|
|
9143
|
-
initialized = true;
|
|
9144
|
-
_runnerLabel = config.runnerLabel;
|
|
9145
|
-
if (!config.axiomToken) {
|
|
9146
|
-
console.log("[metrics] AXIOM_TOKEN not configured, metrics disabled");
|
|
9147
|
-
return;
|
|
9148
|
-
}
|
|
9149
|
-
const env = config.environment ?? "dev";
|
|
9150
|
-
const exporter = new OTLPMetricExporter({
|
|
9151
|
-
url: "https://api.axiom.co/v1/metrics",
|
|
9152
|
-
headers: {
|
|
9153
|
-
Authorization: `Bearer ${config.axiomToken}`,
|
|
9154
|
-
"X-Axiom-Dataset": `vm0-sandbox-op-log-${env}`
|
|
9155
|
-
}
|
|
9156
|
-
});
|
|
9157
|
-
meterProvider = new MeterProvider({
|
|
9158
|
-
resource: new Resource({
|
|
9159
|
-
[ATTR_SERVICE_NAME]: config.serviceName,
|
|
9160
|
-
"deployment.environment": env,
|
|
9161
|
-
"runner.label": config.runnerLabel
|
|
9162
|
-
}),
|
|
9163
|
-
readers: [
|
|
9164
|
-
new PeriodicExportingMetricReader({
|
|
9165
|
-
exporter,
|
|
9166
|
-
exportIntervalMillis: config.exportIntervalMs ?? 3e4
|
|
9167
|
-
})
|
|
9168
|
-
]
|
|
9169
|
-
});
|
|
9170
|
-
metrics.setGlobalMeterProvider(meterProvider);
|
|
9171
|
-
enabled = true;
|
|
9172
|
-
console.log(
|
|
9173
|
-
`[metrics] initialized for ${config.serviceName} (${env}), runner: ${config.runnerLabel}`
|
|
9174
|
-
);
|
|
9175
|
-
}
|
|
9176
|
-
function isMetricsEnabled() {
|
|
9177
|
-
return enabled;
|
|
9178
|
-
}
|
|
9179
|
-
function getRunnerLabel() {
|
|
9180
|
-
return _runnerLabel;
|
|
9181
|
-
}
|
|
9182
|
-
function getMeter(name) {
|
|
9183
|
-
return metrics.getMeter(name);
|
|
9129
|
+
// src/lib/metrics/instruments.ts
|
|
9130
|
+
var FLUSH_THRESHOLD_MS = 3e4;
|
|
9131
|
+
var sandboxContext = null;
|
|
9132
|
+
var pendingOps = [];
|
|
9133
|
+
var oldestPendingTime = null;
|
|
9134
|
+
function setSandboxContext(ctx) {
|
|
9135
|
+
sandboxContext = ctx;
|
|
9136
|
+
pendingOps = [];
|
|
9137
|
+
oldestPendingTime = null;
|
|
9184
9138
|
}
|
|
9185
|
-
async function
|
|
9186
|
-
|
|
9187
|
-
|
|
9139
|
+
async function clearSandboxContext() {
|
|
9140
|
+
const ctx = sandboxContext;
|
|
9141
|
+
const ops = pendingOps;
|
|
9142
|
+
sandboxContext = null;
|
|
9143
|
+
pendingOps = [];
|
|
9144
|
+
oldestPendingTime = null;
|
|
9145
|
+
if (ctx && ops.length > 0) {
|
|
9146
|
+
await flushOpsWithContext(ctx, ops);
|
|
9188
9147
|
}
|
|
9189
9148
|
}
|
|
9190
|
-
async function
|
|
9191
|
-
if (
|
|
9192
|
-
|
|
9193
|
-
|
|
9149
|
+
async function flushOps() {
|
|
9150
|
+
if (!sandboxContext || pendingOps.length === 0) return;
|
|
9151
|
+
const ctx = sandboxContext;
|
|
9152
|
+
const ops = pendingOps;
|
|
9153
|
+
pendingOps = [];
|
|
9154
|
+
oldestPendingTime = null;
|
|
9155
|
+
await flushOpsWithContext(ctx, ops);
|
|
9194
9156
|
}
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
var sandboxOperationTotal = null;
|
|
9201
|
-
var sandboxOperationErrorsTotal = null;
|
|
9202
|
-
var sandboxOperationDuration = null;
|
|
9203
|
-
function getRunnerInstruments() {
|
|
9204
|
-
if (!runnerOperationTotal) {
|
|
9205
|
-
const meter = getMeter("vm0-runner");
|
|
9206
|
-
runnerOperationTotal = meter.createCounter("runner_operation_total", {
|
|
9207
|
-
description: "Total number of runner operations"
|
|
9208
|
-
});
|
|
9209
|
-
runnerOperationErrorsTotal = meter.createCounter(
|
|
9210
|
-
"runner_operation_errors_total",
|
|
9211
|
-
{
|
|
9212
|
-
description: "Total number of runner operation errors"
|
|
9213
|
-
}
|
|
9214
|
-
);
|
|
9215
|
-
runnerOperationDuration = meter.createHistogram(
|
|
9216
|
-
"runner_operation_duration_ms",
|
|
9217
|
-
{
|
|
9218
|
-
description: "Runner operation duration in milliseconds",
|
|
9219
|
-
unit: "ms"
|
|
9220
|
-
}
|
|
9221
|
-
);
|
|
9222
|
-
}
|
|
9223
|
-
return {
|
|
9224
|
-
runnerOperationTotal,
|
|
9225
|
-
runnerOperationErrorsTotal,
|
|
9226
|
-
runnerOperationDuration
|
|
9157
|
+
async function flushOpsWithContext(ctx, ops) {
|
|
9158
|
+
const { apiUrl, runId, sandboxToken } = ctx;
|
|
9159
|
+
const headers = {
|
|
9160
|
+
Authorization: `Bearer ${sandboxToken}`,
|
|
9161
|
+
"Content-Type": "application/json"
|
|
9227
9162
|
};
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9163
|
+
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
9164
|
+
if (bypassSecret) {
|
|
9165
|
+
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
9166
|
+
}
|
|
9167
|
+
try {
|
|
9168
|
+
const response = await fetch(`${apiUrl}/api/webhooks/agent/telemetry`, {
|
|
9169
|
+
method: "POST",
|
|
9170
|
+
headers,
|
|
9171
|
+
body: JSON.stringify({
|
|
9172
|
+
runId,
|
|
9173
|
+
sandboxOperations: ops
|
|
9174
|
+
})
|
|
9234
9175
|
});
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
{
|
|
9244
|
-
description: "Sandbox operation duration in milliseconds",
|
|
9245
|
-
unit: "ms"
|
|
9246
|
-
}
|
|
9247
|
-
);
|
|
9176
|
+
await response.text();
|
|
9177
|
+
if (!response.ok) {
|
|
9178
|
+
console.warn(
|
|
9179
|
+
`[metrics] Failed to flush operations: HTTP ${response.status}`
|
|
9180
|
+
);
|
|
9181
|
+
}
|
|
9182
|
+
} catch (err) {
|
|
9183
|
+
console.warn(`[metrics] Failed to flush operations: ${err}`);
|
|
9248
9184
|
}
|
|
9249
|
-
return {
|
|
9250
|
-
sandboxOperationTotal,
|
|
9251
|
-
sandboxOperationErrorsTotal,
|
|
9252
|
-
sandboxOperationDuration
|
|
9253
|
-
};
|
|
9254
9185
|
}
|
|
9255
|
-
function
|
|
9256
|
-
if (!
|
|
9257
|
-
|
|
9258
|
-
runnerOperationTotal: runnerOperationTotal2,
|
|
9259
|
-
runnerOperationErrorsTotal: runnerOperationErrorsTotal2,
|
|
9260
|
-
runnerOperationDuration: runnerOperationDuration2
|
|
9261
|
-
} = getRunnerInstruments();
|
|
9262
|
-
const labels = {
|
|
9263
|
-
action_type: attrs.actionType,
|
|
9264
|
-
runner_label: getRunnerLabel()
|
|
9265
|
-
};
|
|
9266
|
-
runnerOperationTotal2.add(1, labels);
|
|
9267
|
-
if (!attrs.success) {
|
|
9268
|
-
runnerOperationErrorsTotal2.add(1, labels);
|
|
9186
|
+
function recordOperation(attrs) {
|
|
9187
|
+
if (!sandboxContext) {
|
|
9188
|
+
return;
|
|
9269
9189
|
}
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
}
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
const {
|
|
9278
|
-
sandboxOperationTotal: sandboxOperationTotal2,
|
|
9279
|
-
sandboxOperationErrorsTotal: sandboxOperationErrorsTotal2,
|
|
9280
|
-
sandboxOperationDuration: sandboxOperationDuration2
|
|
9281
|
-
} = getSandboxInstruments();
|
|
9282
|
-
const labels = {
|
|
9283
|
-
sandbox_type: "runner",
|
|
9284
|
-
action_type: attrs.actionType
|
|
9285
|
-
};
|
|
9286
|
-
sandboxOperationTotal2.add(1, labels);
|
|
9287
|
-
if (!attrs.success) {
|
|
9288
|
-
sandboxOperationErrorsTotal2.add(1, labels);
|
|
9190
|
+
const now = Date.now();
|
|
9191
|
+
if (oldestPendingTime && now - oldestPendingTime >= FLUSH_THRESHOLD_MS) {
|
|
9192
|
+
flushOps().catch(() => {
|
|
9193
|
+
});
|
|
9194
|
+
}
|
|
9195
|
+
if (oldestPendingTime === null) {
|
|
9196
|
+
oldestPendingTime = now;
|
|
9289
9197
|
}
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9198
|
+
pendingOps.push({
|
|
9199
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9200
|
+
action_type: attrs.actionType,
|
|
9201
|
+
duration_ms: attrs.durationMs,
|
|
9202
|
+
success: attrs.success
|
|
9293
9203
|
});
|
|
9294
9204
|
}
|
|
9295
9205
|
|
|
@@ -9303,7 +9213,7 @@ async function withRunnerTiming(actionType, fn) {
|
|
|
9303
9213
|
success = false;
|
|
9304
9214
|
throw error;
|
|
9305
9215
|
} finally {
|
|
9306
|
-
|
|
9216
|
+
recordOperation({
|
|
9307
9217
|
actionType,
|
|
9308
9218
|
durationMs: Date.now() - startTime,
|
|
9309
9219
|
success
|
|
@@ -9319,7 +9229,7 @@ async function withSandboxTiming(actionType, fn) {
|
|
|
9319
9229
|
success = false;
|
|
9320
9230
|
throw error;
|
|
9321
9231
|
} finally {
|
|
9322
|
-
|
|
9232
|
+
recordOperation({
|
|
9323
9233
|
actionType,
|
|
9324
9234
|
durationMs: Date.now() - startTime,
|
|
9325
9235
|
success
|
|
@@ -9487,15 +9397,18 @@ async function installProxyCA(guest, caCertPath) {
|
|
|
9487
9397
|
);
|
|
9488
9398
|
}
|
|
9489
9399
|
const caCert = fs8.readFileSync(caCertPath, "utf-8");
|
|
9400
|
+
const certWithNewline = caCert.endsWith("\n") ? caCert : caCert + "\n";
|
|
9490
9401
|
console.log(
|
|
9491
|
-
`[Executor] Installing proxy CA certificate (${
|
|
9402
|
+
`[Executor] Installing proxy CA certificate (${certWithNewline.length} bytes)`
|
|
9492
9403
|
);
|
|
9493
9404
|
await guest.writeFileWithSudo(
|
|
9494
9405
|
"/usr/local/share/ca-certificates/vm0-proxy-ca.crt",
|
|
9495
|
-
|
|
9406
|
+
certWithNewline
|
|
9407
|
+
);
|
|
9408
|
+
await guest.execOrThrow(
|
|
9409
|
+
"cat /usr/local/share/ca-certificates/vm0-proxy-ca.crt | sudo tee -a /etc/ssl/certs/ca-certificates.crt > /dev/null"
|
|
9496
9410
|
);
|
|
9497
|
-
|
|
9498
|
-
console.log(`[Executor] Proxy CA certificate installed successfully`);
|
|
9411
|
+
console.log("[Executor] Proxy CA certificate installed successfully");
|
|
9499
9412
|
}
|
|
9500
9413
|
|
|
9501
9414
|
// src/lib/executor.ts
|
|
@@ -9553,6 +9466,18 @@ async function reportPreflightFailure(apiUrl, runId, sandboxToken, error, bypass
|
|
|
9553
9466
|
}
|
|
9554
9467
|
}
|
|
9555
9468
|
async function executeJob(context, config, options = {}) {
|
|
9469
|
+
setSandboxContext({
|
|
9470
|
+
apiUrl: config.server.url,
|
|
9471
|
+
runId: context.runId,
|
|
9472
|
+
sandboxToken: context.sandboxToken
|
|
9473
|
+
});
|
|
9474
|
+
if (context.apiStartTime) {
|
|
9475
|
+
recordOperation({
|
|
9476
|
+
actionType: "api_to_vm_start",
|
|
9477
|
+
durationMs: Date.now() - context.apiStartTime,
|
|
9478
|
+
success: true
|
|
9479
|
+
});
|
|
9480
|
+
}
|
|
9556
9481
|
const vmId = getVmIdFromRunId(context.runId);
|
|
9557
9482
|
let vm = null;
|
|
9558
9483
|
let guestIp = null;
|
|
@@ -9594,19 +9519,25 @@ async function executeJob(context, config, options = {}) {
|
|
|
9594
9519
|
log(
|
|
9595
9520
|
`[Executor] Setting up network security for VM ${guestIp} (mitm=${mitmEnabled}, sealSecrets=${sealSecretsEnabled})`
|
|
9596
9521
|
);
|
|
9597
|
-
await
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9522
|
+
await withSandboxTiming("network_setup", async () => {
|
|
9523
|
+
getVMRegistry().register(
|
|
9524
|
+
guestIp,
|
|
9525
|
+
context.runId,
|
|
9526
|
+
context.sandboxToken,
|
|
9527
|
+
{
|
|
9528
|
+
firewallRules: firewallConfig?.rules,
|
|
9529
|
+
mitmEnabled,
|
|
9530
|
+
sealSecretsEnabled
|
|
9531
|
+
}
|
|
9607
9532
|
);
|
|
9608
|
-
|
|
9609
|
-
|
|
9533
|
+
if (mitmEnabled) {
|
|
9534
|
+
const caCertPath = path4.join(
|
|
9535
|
+
config.proxy.ca_dir,
|
|
9536
|
+
"mitmproxy-ca-cert.pem"
|
|
9537
|
+
);
|
|
9538
|
+
await installProxyCA(guest, caCertPath);
|
|
9539
|
+
}
|
|
9540
|
+
});
|
|
9610
9541
|
}
|
|
9611
9542
|
if (context.storageManifest) {
|
|
9612
9543
|
await withSandboxTiming(
|
|
@@ -9634,12 +9565,15 @@ async function executeJob(context, config, options = {}) {
|
|
|
9634
9565
|
if (!options.benchmarkMode) {
|
|
9635
9566
|
log(`[Executor] Running preflight connectivity check...`);
|
|
9636
9567
|
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
9637
|
-
const preflight = await
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9568
|
+
const preflight = await withSandboxTiming(
|
|
9569
|
+
"preflight_check",
|
|
9570
|
+
() => runPreflightCheck(
|
|
9571
|
+
guest,
|
|
9572
|
+
config.server.url,
|
|
9573
|
+
context.runId,
|
|
9574
|
+
context.sandboxToken,
|
|
9575
|
+
bypassSecret
|
|
9576
|
+
)
|
|
9643
9577
|
);
|
|
9644
9578
|
if (!preflight.success) {
|
|
9645
9579
|
log(`[Executor] Preflight check failed: ${preflight.error}`);
|
|
@@ -9711,7 +9645,7 @@ async function executeJob(context, config, options = {}) {
|
|
|
9711
9645
|
);
|
|
9712
9646
|
}
|
|
9713
9647
|
const durationMs2 = Date.now() - startTime;
|
|
9714
|
-
|
|
9648
|
+
recordOperation({
|
|
9715
9649
|
actionType: "agent_execute",
|
|
9716
9650
|
durationMs: durationMs2,
|
|
9717
9651
|
success: false
|
|
@@ -9727,7 +9661,7 @@ async function executeJob(context, config, options = {}) {
|
|
|
9727
9661
|
const duration = Math.round(durationMs / 1e3);
|
|
9728
9662
|
if (!completed) {
|
|
9729
9663
|
log(`[Executor] Agent timed out after ${duration}s`);
|
|
9730
|
-
|
|
9664
|
+
recordOperation({
|
|
9731
9665
|
actionType: "agent_execute",
|
|
9732
9666
|
durationMs,
|
|
9733
9667
|
success: false
|
|
@@ -9737,7 +9671,7 @@ async function executeJob(context, config, options = {}) {
|
|
|
9737
9671
|
error: `Agent execution timed out after ${duration}s`
|
|
9738
9672
|
};
|
|
9739
9673
|
}
|
|
9740
|
-
|
|
9674
|
+
recordOperation({
|
|
9741
9675
|
actionType: "agent_execute",
|
|
9742
9676
|
durationMs,
|
|
9743
9677
|
success: exitCode === 0
|
|
@@ -9765,13 +9699,6 @@ async function executeJob(context, config, options = {}) {
|
|
|
9765
9699
|
} finally {
|
|
9766
9700
|
if (context.experimentalFirewall?.enabled && guestIp) {
|
|
9767
9701
|
log(`[Executor] Cleaning up network security for VM ${guestIp}`);
|
|
9768
|
-
try {
|
|
9769
|
-
await removeVMProxyRules(guestIp, config.proxy.port, config.name);
|
|
9770
|
-
} catch (err) {
|
|
9771
|
-
console.error(
|
|
9772
|
-
`[Executor] Failed to remove VM proxy rules: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
9773
|
-
);
|
|
9774
|
-
}
|
|
9775
9702
|
getVMRegistry().unregister(guestIp);
|
|
9776
9703
|
if (!options.benchmarkMode) {
|
|
9777
9704
|
try {
|
|
@@ -9791,6 +9718,7 @@ async function executeJob(context, config, options = {}) {
|
|
|
9791
9718
|
log(`[Executor] Cleaning up VM ${vmId}...`);
|
|
9792
9719
|
await withSandboxTiming("cleanup", () => vm.kill());
|
|
9793
9720
|
}
|
|
9721
|
+
await clearSandboxContext();
|
|
9794
9722
|
}
|
|
9795
9723
|
}
|
|
9796
9724
|
|
|
@@ -9826,18 +9754,6 @@ function createStatusUpdater(statusFilePath, state) {
|
|
|
9826
9754
|
// src/lib/runner/setup.ts
|
|
9827
9755
|
async function setupEnvironment(options) {
|
|
9828
9756
|
const { config } = options;
|
|
9829
|
-
const datasetSuffix = process.env.AXIOM_DATASET_SUFFIX;
|
|
9830
|
-
if (!datasetSuffix) {
|
|
9831
|
-
throw new Error(
|
|
9832
|
-
"AXIOM_DATASET_SUFFIX is required. Set to 'dev' or 'prod'."
|
|
9833
|
-
);
|
|
9834
|
-
}
|
|
9835
|
-
initMetrics({
|
|
9836
|
-
serviceName: "vm0-runner",
|
|
9837
|
-
runnerLabel: config.name,
|
|
9838
|
-
axiomToken: process.env.AXIOM_TOKEN,
|
|
9839
|
-
environment: datasetSuffix
|
|
9840
|
-
});
|
|
9841
9757
|
const networkCheck = checkNetworkPrerequisites();
|
|
9842
9758
|
if (!networkCheck.ok) {
|
|
9843
9759
|
console.error("Network prerequisites not met:");
|
|
@@ -9866,6 +9782,8 @@ async function setupEnvironment(options) {
|
|
|
9866
9782
|
await proxyManager.start();
|
|
9867
9783
|
proxyEnabled = true;
|
|
9868
9784
|
console.log("Network proxy initialized successfully");
|
|
9785
|
+
console.log("Setting up CIDR proxy rules...");
|
|
9786
|
+
await setupCIDRProxyRules(config.proxy.port);
|
|
9869
9787
|
} catch (err) {
|
|
9870
9788
|
console.warn(
|
|
9871
9789
|
`Network proxy not available: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
@@ -9874,16 +9792,17 @@ async function setupEnvironment(options) {
|
|
|
9874
9792
|
"Jobs with experimentalFirewall enabled will run without network interception"
|
|
9875
9793
|
);
|
|
9876
9794
|
}
|
|
9877
|
-
return { proxyEnabled };
|
|
9795
|
+
return { proxyEnabled, proxyPort: config.proxy.port };
|
|
9878
9796
|
}
|
|
9879
9797
|
async function cleanupEnvironment(resources) {
|
|
9798
|
+
if (resources.proxyEnabled) {
|
|
9799
|
+
console.log("Cleaning up CIDR proxy rules...");
|
|
9800
|
+
await cleanupCIDRProxyRules(resources.proxyPort);
|
|
9801
|
+
}
|
|
9880
9802
|
if (resources.proxyEnabled) {
|
|
9881
9803
|
console.log("Stopping network proxy...");
|
|
9882
9804
|
await getProxyManager().stop();
|
|
9883
9805
|
}
|
|
9884
|
-
console.log("Flushing metrics...");
|
|
9885
|
-
await flushMetrics();
|
|
9886
|
-
await shutdownMetrics();
|
|
9887
9806
|
}
|
|
9888
9807
|
|
|
9889
9808
|
// src/lib/runner/signals.ts
|
|
@@ -10720,7 +10639,7 @@ var benchmarkCommand = new Command4("benchmark").description(
|
|
|
10720
10639
|
});
|
|
10721
10640
|
|
|
10722
10641
|
// src/index.ts
|
|
10723
|
-
var version = true ? "3.
|
|
10642
|
+
var version = true ? "3.6.0" : "0.1.0";
|
|
10724
10643
|
program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
|
|
10725
10644
|
program.addCommand(startCommand);
|
|
10726
10645
|
program.addCommand(doctorCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vm0/runner",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Self-hosted runner for VM0 agents",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,11 +15,6 @@
|
|
|
15
15
|
"."
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@opentelemetry/api": "^1.9.0",
|
|
19
|
-
"@opentelemetry/exporter-metrics-otlp-proto": "^0.52.0",
|
|
20
|
-
"@opentelemetry/resources": "^1.25.0",
|
|
21
|
-
"@opentelemetry/sdk-metrics": "^1.25.0",
|
|
22
|
-
"@opentelemetry/semantic-conventions": "^1.25.0",
|
|
23
18
|
"ably": "^2.17.0",
|
|
24
19
|
"commander": "^14.0.0",
|
|
25
20
|
"yaml": "^2.3.4",
|