@vm0/runner 2.3.2 → 2.4.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 +902 -616
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -4816,25 +4816,143 @@ var apiErrorSchema = z3.object({
|
|
|
4816
4816
|
});
|
|
4817
4817
|
|
|
4818
4818
|
// ../../packages/core/src/contracts/composes.ts
|
|
4819
|
+
import { z as z5 } from "zod";
|
|
4820
|
+
|
|
4821
|
+
// ../../packages/core/src/contracts/runners.ts
|
|
4819
4822
|
import { z as z4 } from "zod";
|
|
4820
4823
|
var c = initContract();
|
|
4821
|
-
var
|
|
4824
|
+
var firewallRuleSchema = z4.object({
|
|
4825
|
+
domain: z4.string().optional(),
|
|
4826
|
+
ip: z4.string().optional(),
|
|
4827
|
+
/** Terminal rule - value is the action (ALLOW or DENY) */
|
|
4828
|
+
final: z4.enum(["ALLOW", "DENY"]).optional(),
|
|
4829
|
+
/** Action for domain/ip rules */
|
|
4830
|
+
action: z4.enum(["ALLOW", "DENY"]).optional()
|
|
4831
|
+
});
|
|
4832
|
+
var experimentalFirewallSchema = z4.object({
|
|
4833
|
+
enabled: z4.boolean(),
|
|
4834
|
+
rules: z4.array(firewallRuleSchema).optional(),
|
|
4835
|
+
experimental_mitm: z4.boolean().optional(),
|
|
4836
|
+
experimental_seal_secrets: z4.boolean().optional()
|
|
4837
|
+
});
|
|
4838
|
+
var runnerGroupSchema = z4.string().regex(
|
|
4839
|
+
/^[a-z0-9-]+\/[a-z0-9-]+$/,
|
|
4840
|
+
"Runner group must be in scope/name format (e.g., acme/production)"
|
|
4841
|
+
);
|
|
4842
|
+
var jobSchema = z4.object({
|
|
4843
|
+
runId: z4.string().uuid(),
|
|
4844
|
+
prompt: z4.string(),
|
|
4845
|
+
agentComposeVersionId: z4.string(),
|
|
4846
|
+
vars: z4.record(z4.string(), z4.string()).nullable(),
|
|
4847
|
+
secretNames: z4.array(z4.string()).nullable(),
|
|
4848
|
+
checkpointId: z4.string().uuid().nullable()
|
|
4849
|
+
});
|
|
4850
|
+
var runnersPollContract = c.router({
|
|
4851
|
+
poll: {
|
|
4852
|
+
method: "POST",
|
|
4853
|
+
path: "/api/runners/poll",
|
|
4854
|
+
body: z4.object({
|
|
4855
|
+
group: runnerGroupSchema
|
|
4856
|
+
}),
|
|
4857
|
+
responses: {
|
|
4858
|
+
200: z4.object({
|
|
4859
|
+
job: jobSchema.nullable()
|
|
4860
|
+
}),
|
|
4861
|
+
400: apiErrorSchema,
|
|
4862
|
+
401: apiErrorSchema,
|
|
4863
|
+
500: apiErrorSchema
|
|
4864
|
+
},
|
|
4865
|
+
summary: "Poll for pending jobs (long-polling with 30s timeout)"
|
|
4866
|
+
}
|
|
4867
|
+
});
|
|
4868
|
+
var storageEntrySchema = z4.object({
|
|
4869
|
+
mountPath: z4.string(),
|
|
4870
|
+
archiveUrl: z4.string().nullable()
|
|
4871
|
+
});
|
|
4872
|
+
var artifactEntrySchema = z4.object({
|
|
4873
|
+
mountPath: z4.string(),
|
|
4874
|
+
archiveUrl: z4.string().nullable(),
|
|
4875
|
+
vasStorageName: z4.string(),
|
|
4876
|
+
vasVersionId: z4.string()
|
|
4877
|
+
});
|
|
4878
|
+
var storageManifestSchema = z4.object({
|
|
4879
|
+
storages: z4.array(storageEntrySchema),
|
|
4880
|
+
artifact: artifactEntrySchema.nullable()
|
|
4881
|
+
});
|
|
4882
|
+
var resumeSessionSchema = z4.object({
|
|
4883
|
+
sessionId: z4.string(),
|
|
4884
|
+
sessionHistory: z4.string()
|
|
4885
|
+
});
|
|
4886
|
+
var storedExecutionContextSchema = z4.object({
|
|
4887
|
+
workingDir: z4.string(),
|
|
4888
|
+
storageManifest: storageManifestSchema.nullable(),
|
|
4889
|
+
environment: z4.record(z4.string(), z4.string()).nullable(),
|
|
4890
|
+
resumeSession: resumeSessionSchema.nullable(),
|
|
4891
|
+
encryptedSecrets: z4.string().nullable(),
|
|
4892
|
+
// AES-256-GCM encrypted secrets
|
|
4893
|
+
cliAgentType: z4.string(),
|
|
4894
|
+
experimentalFirewall: experimentalFirewallSchema.optional()
|
|
4895
|
+
});
|
|
4896
|
+
var executionContextSchema = z4.object({
|
|
4897
|
+
runId: z4.string().uuid(),
|
|
4898
|
+
prompt: z4.string(),
|
|
4899
|
+
agentComposeVersionId: z4.string(),
|
|
4900
|
+
vars: z4.record(z4.string(), z4.string()).nullable(),
|
|
4901
|
+
secretNames: z4.array(z4.string()).nullable(),
|
|
4902
|
+
checkpointId: z4.string().uuid().nullable(),
|
|
4903
|
+
sandboxToken: z4.string(),
|
|
4904
|
+
// New fields for E2B parity:
|
|
4905
|
+
workingDir: z4.string(),
|
|
4906
|
+
storageManifest: storageManifestSchema.nullable(),
|
|
4907
|
+
environment: z4.record(z4.string(), z4.string()).nullable(),
|
|
4908
|
+
resumeSession: resumeSessionSchema.nullable(),
|
|
4909
|
+
secretValues: z4.array(z4.string()).nullable(),
|
|
4910
|
+
cliAgentType: z4.string(),
|
|
4911
|
+
// Experimental firewall configuration
|
|
4912
|
+
experimentalFirewall: experimentalFirewallSchema.optional()
|
|
4913
|
+
});
|
|
4914
|
+
var runnersJobClaimContract = c.router({
|
|
4915
|
+
claim: {
|
|
4916
|
+
method: "POST",
|
|
4917
|
+
path: "/api/runners/jobs/:id/claim",
|
|
4918
|
+
pathParams: z4.object({
|
|
4919
|
+
id: z4.string().uuid()
|
|
4920
|
+
}),
|
|
4921
|
+
body: z4.object({}),
|
|
4922
|
+
responses: {
|
|
4923
|
+
200: executionContextSchema,
|
|
4924
|
+
400: apiErrorSchema,
|
|
4925
|
+
401: apiErrorSchema,
|
|
4926
|
+
403: apiErrorSchema,
|
|
4927
|
+
// Job does not belong to user
|
|
4928
|
+
404: apiErrorSchema,
|
|
4929
|
+
409: apiErrorSchema,
|
|
4930
|
+
// Already claimed
|
|
4931
|
+
500: apiErrorSchema
|
|
4932
|
+
},
|
|
4933
|
+
summary: "Claim a pending job for execution"
|
|
4934
|
+
}
|
|
4935
|
+
});
|
|
4936
|
+
|
|
4937
|
+
// ../../packages/core/src/contracts/composes.ts
|
|
4938
|
+
var c2 = initContract();
|
|
4939
|
+
var composeVersionQuerySchema = z5.preprocess(
|
|
4822
4940
|
(val) => val === void 0 || val === null ? void 0 : String(val),
|
|
4823
|
-
|
|
4941
|
+
z5.string().min(1, "Missing version query parameter").regex(
|
|
4824
4942
|
/^[a-f0-9]{8,64}$|^latest$/i,
|
|
4825
4943
|
"Version must be 8-64 hex characters or 'latest'"
|
|
4826
4944
|
)
|
|
4827
4945
|
);
|
|
4828
|
-
var agentNameSchema =
|
|
4946
|
+
var agentNameSchema = z5.string().min(3, "Agent name must be at least 3 characters").max(64, "Agent name must be 64 characters or less").regex(
|
|
4829
4947
|
/^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/,
|
|
4830
4948
|
"Agent name must start and end with letter or number, and contain only letters, numbers, and hyphens"
|
|
4831
4949
|
);
|
|
4832
|
-
var volumeConfigSchema =
|
|
4833
|
-
name:
|
|
4834
|
-
version:
|
|
4950
|
+
var volumeConfigSchema = z5.object({
|
|
4951
|
+
name: z5.string().min(1, "Volume name is required"),
|
|
4952
|
+
version: z5.string().min(1, "Volume version is required")
|
|
4835
4953
|
});
|
|
4836
4954
|
var SUPPORTED_APPS = ["github"];
|
|
4837
|
-
var appStringSchema =
|
|
4955
|
+
var appStringSchema = z5.string().regex(
|
|
4838
4956
|
/^[a-z]+(:(?:latest|dev))?$/,
|
|
4839
4957
|
"App must be in format 'app' or 'app:tag' (e.g., 'github', 'github:dev')"
|
|
4840
4958
|
).refine(
|
|
@@ -4844,74 +4962,80 @@ var appStringSchema = z4.string().regex(
|
|
|
4844
4962
|
},
|
|
4845
4963
|
`Unsupported app. Supported apps: ${SUPPORTED_APPS.join(", ")}`
|
|
4846
4964
|
);
|
|
4847
|
-
var agentDefinitionSchema =
|
|
4848
|
-
description:
|
|
4965
|
+
var agentDefinitionSchema = z5.object({
|
|
4966
|
+
description: z5.string().optional(),
|
|
4849
4967
|
/**
|
|
4850
4968
|
* @deprecated Use `apps` field instead for pre-installed tools.
|
|
4851
4969
|
* This field will be removed in a future version.
|
|
4852
4970
|
*/
|
|
4853
|
-
image:
|
|
4854
|
-
provider:
|
|
4971
|
+
image: z5.string().optional(),
|
|
4972
|
+
provider: z5.string().min(1, "Provider is required"),
|
|
4855
4973
|
/**
|
|
4856
4974
|
* Array of pre-installed apps/tools for the agent environment.
|
|
4857
4975
|
* Format: "app" or "app:tag" (e.g., "github", "github:dev", "github:latest")
|
|
4858
4976
|
* Default tag is "latest" if not specified.
|
|
4859
4977
|
* Currently supported apps: "github" (includes GitHub CLI)
|
|
4860
4978
|
*/
|
|
4861
|
-
apps:
|
|
4862
|
-
volumes:
|
|
4863
|
-
working_dir:
|
|
4979
|
+
apps: z5.array(appStringSchema).optional(),
|
|
4980
|
+
volumes: z5.array(z5.string()).optional(),
|
|
4981
|
+
working_dir: z5.string().optional(),
|
|
4864
4982
|
// Optional when provider supports auto-config
|
|
4865
|
-
environment:
|
|
4983
|
+
environment: z5.record(z5.string(), z5.string()).optional(),
|
|
4866
4984
|
/**
|
|
4867
4985
|
* Enable network security mode for secrets.
|
|
4868
4986
|
* When true, secrets are encrypted into proxy tokens and all traffic
|
|
4869
4987
|
* is routed through mitmproxy -> VM0 Proxy for decryption.
|
|
4870
4988
|
* Default: false (plaintext secrets in env vars)
|
|
4871
4989
|
*/
|
|
4872
|
-
experimental_network_security:
|
|
4990
|
+
experimental_network_security: z5.boolean().optional().default(false),
|
|
4873
4991
|
/**
|
|
4874
4992
|
* Path to instructions file (e.g., AGENTS.md).
|
|
4875
4993
|
* Auto-uploaded as volume and mounted at /home/user/.claude/CLAUDE.md
|
|
4876
4994
|
*/
|
|
4877
|
-
instructions:
|
|
4995
|
+
instructions: z5.string().optional(),
|
|
4878
4996
|
/**
|
|
4879
4997
|
* Array of GitHub tree URLs for agent skills.
|
|
4880
4998
|
* Each skill is auto-downloaded and mounted at /home/user/.claude/skills/{skillName}/
|
|
4881
4999
|
*/
|
|
4882
|
-
skills:
|
|
5000
|
+
skills: z5.array(z5.string()).optional(),
|
|
4883
5001
|
/**
|
|
4884
5002
|
* Route this agent to a self-hosted runner instead of E2B.
|
|
4885
5003
|
* When specified, runs will be queued for the specified runner group.
|
|
4886
5004
|
*/
|
|
4887
|
-
experimental_runner:
|
|
4888
|
-
group:
|
|
5005
|
+
experimental_runner: z5.object({
|
|
5006
|
+
group: z5.string().regex(
|
|
4889
5007
|
/^[a-z0-9-]+\/[a-z0-9-]+$/,
|
|
4890
5008
|
"Runner group must be in scope/name format (e.g., acme/production)"
|
|
4891
5009
|
)
|
|
4892
|
-
}).optional()
|
|
5010
|
+
}).optional(),
|
|
5011
|
+
/**
|
|
5012
|
+
* Experimental firewall configuration for network egress control.
|
|
5013
|
+
* Requires experimental_runner to be configured.
|
|
5014
|
+
* When enabled, filters outbound traffic by domain/IP rules.
|
|
5015
|
+
*/
|
|
5016
|
+
experimental_firewall: experimentalFirewallSchema.optional()
|
|
4893
5017
|
});
|
|
4894
|
-
var agentComposeContentSchema =
|
|
4895
|
-
version:
|
|
4896
|
-
agents:
|
|
4897
|
-
volumes:
|
|
5018
|
+
var agentComposeContentSchema = z5.object({
|
|
5019
|
+
version: z5.string().min(1, "Version is required"),
|
|
5020
|
+
agents: z5.record(z5.string(), agentDefinitionSchema),
|
|
5021
|
+
volumes: z5.record(z5.string(), volumeConfigSchema).optional()
|
|
4898
5022
|
});
|
|
4899
|
-
var composeResponseSchema =
|
|
4900
|
-
id:
|
|
4901
|
-
name:
|
|
4902
|
-
headVersionId:
|
|
5023
|
+
var composeResponseSchema = z5.object({
|
|
5024
|
+
id: z5.string(),
|
|
5025
|
+
name: z5.string(),
|
|
5026
|
+
headVersionId: z5.string().nullable(),
|
|
4903
5027
|
content: agentComposeContentSchema.nullable(),
|
|
4904
|
-
createdAt:
|
|
4905
|
-
updatedAt:
|
|
5028
|
+
createdAt: z5.string(),
|
|
5029
|
+
updatedAt: z5.string()
|
|
4906
5030
|
});
|
|
4907
|
-
var createComposeResponseSchema =
|
|
4908
|
-
composeId:
|
|
4909
|
-
name:
|
|
4910
|
-
versionId:
|
|
4911
|
-
action:
|
|
4912
|
-
updatedAt:
|
|
5031
|
+
var createComposeResponseSchema = z5.object({
|
|
5032
|
+
composeId: z5.string(),
|
|
5033
|
+
name: z5.string(),
|
|
5034
|
+
versionId: z5.string(),
|
|
5035
|
+
action: z5.enum(["created", "existing"]),
|
|
5036
|
+
updatedAt: z5.string()
|
|
4913
5037
|
});
|
|
4914
|
-
var composesMainContract =
|
|
5038
|
+
var composesMainContract = c2.router({
|
|
4915
5039
|
/**
|
|
4916
5040
|
* GET /api/agent/composes?name={name}&scope={scope}
|
|
4917
5041
|
* Get agent compose by name with HEAD version content
|
|
@@ -4920,9 +5044,9 @@ var composesMainContract = c.router({
|
|
|
4920
5044
|
getByName: {
|
|
4921
5045
|
method: "GET",
|
|
4922
5046
|
path: "/api/agent/composes",
|
|
4923
|
-
query:
|
|
4924
|
-
name:
|
|
4925
|
-
scope:
|
|
5047
|
+
query: z5.object({
|
|
5048
|
+
name: z5.string().min(1, "Missing name query parameter"),
|
|
5049
|
+
scope: z5.string().optional()
|
|
4926
5050
|
}),
|
|
4927
5051
|
responses: {
|
|
4928
5052
|
200: composeResponseSchema,
|
|
@@ -4941,7 +5065,7 @@ var composesMainContract = c.router({
|
|
|
4941
5065
|
create: {
|
|
4942
5066
|
method: "POST",
|
|
4943
5067
|
path: "/api/agent/composes",
|
|
4944
|
-
body:
|
|
5068
|
+
body: z5.object({
|
|
4945
5069
|
content: agentComposeContentSchema
|
|
4946
5070
|
}),
|
|
4947
5071
|
responses: {
|
|
@@ -4953,7 +5077,7 @@ var composesMainContract = c.router({
|
|
|
4953
5077
|
summary: "Create or update agent compose version"
|
|
4954
5078
|
}
|
|
4955
5079
|
});
|
|
4956
|
-
var composesByIdContract =
|
|
5080
|
+
var composesByIdContract = c2.router({
|
|
4957
5081
|
/**
|
|
4958
5082
|
* GET /api/agent/composes/:id
|
|
4959
5083
|
* Get agent compose by ID with HEAD version content
|
|
@@ -4961,8 +5085,8 @@ var composesByIdContract = c.router({
|
|
|
4961
5085
|
getById: {
|
|
4962
5086
|
method: "GET",
|
|
4963
5087
|
path: "/api/agent/composes/:id",
|
|
4964
|
-
pathParams:
|
|
4965
|
-
id:
|
|
5088
|
+
pathParams: z5.object({
|
|
5089
|
+
id: z5.string().min(1, "Compose ID is required")
|
|
4966
5090
|
}),
|
|
4967
5091
|
responses: {
|
|
4968
5092
|
200: composeResponseSchema,
|
|
@@ -4972,7 +5096,7 @@ var composesByIdContract = c.router({
|
|
|
4972
5096
|
summary: "Get agent compose by ID"
|
|
4973
5097
|
}
|
|
4974
5098
|
});
|
|
4975
|
-
var composesVersionsContract =
|
|
5099
|
+
var composesVersionsContract = c2.router({
|
|
4976
5100
|
/**
|
|
4977
5101
|
* GET /api/agent/composes/versions?composeId={id}&version={hash|tag}
|
|
4978
5102
|
* Resolve a version specifier to a full version ID
|
|
@@ -4980,14 +5104,14 @@ var composesVersionsContract = c.router({
|
|
|
4980
5104
|
resolveVersion: {
|
|
4981
5105
|
method: "GET",
|
|
4982
5106
|
path: "/api/agent/composes/versions",
|
|
4983
|
-
query:
|
|
4984
|
-
composeId:
|
|
5107
|
+
query: z5.object({
|
|
5108
|
+
composeId: z5.string().min(1, "Missing composeId query parameter"),
|
|
4985
5109
|
version: composeVersionQuerySchema
|
|
4986
5110
|
}),
|
|
4987
5111
|
responses: {
|
|
4988
|
-
200:
|
|
4989
|
-
versionId:
|
|
4990
|
-
tag:
|
|
5112
|
+
200: z5.object({
|
|
5113
|
+
versionId: z5.string(),
|
|
5114
|
+
tag: z5.string().optional()
|
|
4991
5115
|
}),
|
|
4992
5116
|
400: apiErrorSchema,
|
|
4993
5117
|
401: apiErrorSchema,
|
|
@@ -4996,12 +5120,12 @@ var composesVersionsContract = c.router({
|
|
|
4996
5120
|
summary: "Resolve version specifier to full version ID"
|
|
4997
5121
|
}
|
|
4998
5122
|
});
|
|
4999
|
-
var composeListItemSchema =
|
|
5000
|
-
name:
|
|
5001
|
-
headVersionId:
|
|
5002
|
-
updatedAt:
|
|
5123
|
+
var composeListItemSchema = z5.object({
|
|
5124
|
+
name: z5.string(),
|
|
5125
|
+
headVersionId: z5.string().nullable(),
|
|
5126
|
+
updatedAt: z5.string()
|
|
5003
5127
|
});
|
|
5004
|
-
var composesListContract =
|
|
5128
|
+
var composesListContract = c2.router({
|
|
5005
5129
|
/**
|
|
5006
5130
|
* GET /api/agent/composes/list?scope={scope}
|
|
5007
5131
|
* List all agent composes for a scope
|
|
@@ -5010,12 +5134,12 @@ var composesListContract = c.router({
|
|
|
5010
5134
|
list: {
|
|
5011
5135
|
method: "GET",
|
|
5012
5136
|
path: "/api/agent/composes/list",
|
|
5013
|
-
query:
|
|
5014
|
-
scope:
|
|
5137
|
+
query: z5.object({
|
|
5138
|
+
scope: z5.string().optional()
|
|
5015
5139
|
}),
|
|
5016
5140
|
responses: {
|
|
5017
|
-
200:
|
|
5018
|
-
composes:
|
|
5141
|
+
200: z5.object({
|
|
5142
|
+
composes: z5.array(composeListItemSchema)
|
|
5019
5143
|
}),
|
|
5020
5144
|
400: apiErrorSchema,
|
|
5021
5145
|
401: apiErrorSchema
|
|
@@ -5025,83 +5149,83 @@ var composesListContract = c.router({
|
|
|
5025
5149
|
});
|
|
5026
5150
|
|
|
5027
5151
|
// ../../packages/core/src/contracts/runs.ts
|
|
5028
|
-
import { z as
|
|
5029
|
-
var
|
|
5030
|
-
var runStatusSchema =
|
|
5152
|
+
import { z as z6 } from "zod";
|
|
5153
|
+
var c3 = initContract();
|
|
5154
|
+
var runStatusSchema = z6.enum([
|
|
5031
5155
|
"pending",
|
|
5032
5156
|
"running",
|
|
5033
5157
|
"completed",
|
|
5034
5158
|
"failed",
|
|
5035
5159
|
"timeout"
|
|
5036
5160
|
]);
|
|
5037
|
-
var unifiedRunRequestSchema =
|
|
5161
|
+
var unifiedRunRequestSchema = z6.object({
|
|
5038
5162
|
// High-level shortcuts (mutually exclusive with each other)
|
|
5039
|
-
checkpointId:
|
|
5040
|
-
sessionId:
|
|
5163
|
+
checkpointId: z6.string().optional(),
|
|
5164
|
+
sessionId: z6.string().optional(),
|
|
5041
5165
|
// Base parameters (can be used directly or overridden after shortcut expansion)
|
|
5042
|
-
agentComposeId:
|
|
5043
|
-
agentComposeVersionId:
|
|
5044
|
-
conversationId:
|
|
5045
|
-
artifactName:
|
|
5046
|
-
artifactVersion:
|
|
5047
|
-
vars:
|
|
5048
|
-
secrets:
|
|
5049
|
-
volumeVersions:
|
|
5166
|
+
agentComposeId: z6.string().optional(),
|
|
5167
|
+
agentComposeVersionId: z6.string().optional(),
|
|
5168
|
+
conversationId: z6.string().optional(),
|
|
5169
|
+
artifactName: z6.string().optional(),
|
|
5170
|
+
artifactVersion: z6.string().optional(),
|
|
5171
|
+
vars: z6.record(z6.string(), z6.string()).optional(),
|
|
5172
|
+
secrets: z6.record(z6.string(), z6.string()).optional(),
|
|
5173
|
+
volumeVersions: z6.record(z6.string(), z6.string()).optional(),
|
|
5050
5174
|
// Required
|
|
5051
|
-
prompt:
|
|
5175
|
+
prompt: z6.string().min(1, "Missing prompt")
|
|
5052
5176
|
});
|
|
5053
|
-
var createRunResponseSchema =
|
|
5054
|
-
runId:
|
|
5177
|
+
var createRunResponseSchema = z6.object({
|
|
5178
|
+
runId: z6.string(),
|
|
5055
5179
|
status: runStatusSchema,
|
|
5056
|
-
sandboxId:
|
|
5057
|
-
output:
|
|
5058
|
-
error:
|
|
5059
|
-
executionTimeMs:
|
|
5060
|
-
createdAt:
|
|
5061
|
-
});
|
|
5062
|
-
var getRunResponseSchema =
|
|
5063
|
-
runId:
|
|
5064
|
-
agentComposeVersionId:
|
|
5180
|
+
sandboxId: z6.string().optional(),
|
|
5181
|
+
output: z6.string().optional(),
|
|
5182
|
+
error: z6.string().optional(),
|
|
5183
|
+
executionTimeMs: z6.number().optional(),
|
|
5184
|
+
createdAt: z6.string()
|
|
5185
|
+
});
|
|
5186
|
+
var getRunResponseSchema = z6.object({
|
|
5187
|
+
runId: z6.string(),
|
|
5188
|
+
agentComposeVersionId: z6.string(),
|
|
5065
5189
|
status: runStatusSchema,
|
|
5066
|
-
prompt:
|
|
5067
|
-
vars:
|
|
5068
|
-
sandboxId:
|
|
5069
|
-
result:
|
|
5070
|
-
output:
|
|
5071
|
-
executionTimeMs:
|
|
5190
|
+
prompt: z6.string(),
|
|
5191
|
+
vars: z6.record(z6.string(), z6.string()).optional(),
|
|
5192
|
+
sandboxId: z6.string().optional(),
|
|
5193
|
+
result: z6.object({
|
|
5194
|
+
output: z6.string(),
|
|
5195
|
+
executionTimeMs: z6.number()
|
|
5072
5196
|
}).optional(),
|
|
5073
|
-
error:
|
|
5074
|
-
createdAt:
|
|
5075
|
-
startedAt:
|
|
5076
|
-
completedAt:
|
|
5077
|
-
});
|
|
5078
|
-
var runEventSchema =
|
|
5079
|
-
sequenceNumber:
|
|
5080
|
-
eventType:
|
|
5081
|
-
eventData:
|
|
5082
|
-
createdAt:
|
|
5083
|
-
});
|
|
5084
|
-
var runResultSchema =
|
|
5085
|
-
checkpointId:
|
|
5086
|
-
agentSessionId:
|
|
5087
|
-
conversationId:
|
|
5088
|
-
artifact:
|
|
5197
|
+
error: z6.string().optional(),
|
|
5198
|
+
createdAt: z6.string(),
|
|
5199
|
+
startedAt: z6.string().optional(),
|
|
5200
|
+
completedAt: z6.string().optional()
|
|
5201
|
+
});
|
|
5202
|
+
var runEventSchema = z6.object({
|
|
5203
|
+
sequenceNumber: z6.number(),
|
|
5204
|
+
eventType: z6.string(),
|
|
5205
|
+
eventData: z6.unknown(),
|
|
5206
|
+
createdAt: z6.string()
|
|
5207
|
+
});
|
|
5208
|
+
var runResultSchema = z6.object({
|
|
5209
|
+
checkpointId: z6.string(),
|
|
5210
|
+
agentSessionId: z6.string(),
|
|
5211
|
+
conversationId: z6.string(),
|
|
5212
|
+
artifact: z6.record(z6.string(), z6.string()).optional(),
|
|
5089
5213
|
// optional when run has no artifact
|
|
5090
|
-
volumes:
|
|
5214
|
+
volumes: z6.record(z6.string(), z6.string()).optional()
|
|
5091
5215
|
});
|
|
5092
|
-
var runStateSchema =
|
|
5216
|
+
var runStateSchema = z6.object({
|
|
5093
5217
|
status: runStatusSchema,
|
|
5094
5218
|
result: runResultSchema.optional(),
|
|
5095
|
-
error:
|
|
5219
|
+
error: z6.string().optional()
|
|
5096
5220
|
});
|
|
5097
|
-
var eventsResponseSchema =
|
|
5098
|
-
events:
|
|
5099
|
-
hasMore:
|
|
5100
|
-
nextSequence:
|
|
5221
|
+
var eventsResponseSchema = z6.object({
|
|
5222
|
+
events: z6.array(runEventSchema),
|
|
5223
|
+
hasMore: z6.boolean(),
|
|
5224
|
+
nextSequence: z6.number(),
|
|
5101
5225
|
run: runStateSchema,
|
|
5102
|
-
provider:
|
|
5226
|
+
provider: z6.string()
|
|
5103
5227
|
});
|
|
5104
|
-
var runsMainContract =
|
|
5228
|
+
var runsMainContract = c3.router({
|
|
5105
5229
|
/**
|
|
5106
5230
|
* POST /api/agent/runs
|
|
5107
5231
|
* Create and execute a new agent run
|
|
@@ -5119,7 +5243,7 @@ var runsMainContract = c2.router({
|
|
|
5119
5243
|
summary: "Create and execute agent run"
|
|
5120
5244
|
}
|
|
5121
5245
|
});
|
|
5122
|
-
var runsByIdContract =
|
|
5246
|
+
var runsByIdContract = c3.router({
|
|
5123
5247
|
/**
|
|
5124
5248
|
* GET /api/agent/runs/:id
|
|
5125
5249
|
* Get agent run status and results
|
|
@@ -5127,8 +5251,8 @@ var runsByIdContract = c2.router({
|
|
|
5127
5251
|
getById: {
|
|
5128
5252
|
method: "GET",
|
|
5129
5253
|
path: "/api/agent/runs/:id",
|
|
5130
|
-
pathParams:
|
|
5131
|
-
id:
|
|
5254
|
+
pathParams: z6.object({
|
|
5255
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5132
5256
|
}),
|
|
5133
5257
|
responses: {
|
|
5134
5258
|
200: getRunResponseSchema,
|
|
@@ -5139,7 +5263,7 @@ var runsByIdContract = c2.router({
|
|
|
5139
5263
|
summary: "Get agent run by ID"
|
|
5140
5264
|
}
|
|
5141
5265
|
});
|
|
5142
|
-
var runEventsContract =
|
|
5266
|
+
var runEventsContract = c3.router({
|
|
5143
5267
|
/**
|
|
5144
5268
|
* GET /api/agent/runs/:id/events
|
|
5145
5269
|
* Poll for agent run events with pagination
|
|
@@ -5147,12 +5271,12 @@ var runEventsContract = c2.router({
|
|
|
5147
5271
|
getEvents: {
|
|
5148
5272
|
method: "GET",
|
|
5149
5273
|
path: "/api/agent/runs/:id/events",
|
|
5150
|
-
pathParams:
|
|
5151
|
-
id:
|
|
5274
|
+
pathParams: z6.object({
|
|
5275
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5152
5276
|
}),
|
|
5153
|
-
query:
|
|
5154
|
-
since:
|
|
5155
|
-
limit:
|
|
5277
|
+
query: z6.object({
|
|
5278
|
+
since: z6.coerce.number().default(0),
|
|
5279
|
+
limit: z6.coerce.number().default(100)
|
|
5156
5280
|
}),
|
|
5157
5281
|
responses: {
|
|
5158
5282
|
200: eventsResponseSchema,
|
|
@@ -5162,45 +5286,45 @@ var runEventsContract = c2.router({
|
|
|
5162
5286
|
summary: "Get agent run events"
|
|
5163
5287
|
}
|
|
5164
5288
|
});
|
|
5165
|
-
var telemetryMetricSchema =
|
|
5166
|
-
ts:
|
|
5167
|
-
cpu:
|
|
5168
|
-
mem_used:
|
|
5169
|
-
mem_total:
|
|
5170
|
-
disk_used:
|
|
5171
|
-
disk_total:
|
|
5172
|
-
});
|
|
5173
|
-
var systemLogResponseSchema =
|
|
5174
|
-
systemLog:
|
|
5175
|
-
hasMore:
|
|
5176
|
-
});
|
|
5177
|
-
var metricsResponseSchema =
|
|
5178
|
-
metrics:
|
|
5179
|
-
hasMore:
|
|
5180
|
-
});
|
|
5181
|
-
var agentEventsResponseSchema =
|
|
5182
|
-
events:
|
|
5183
|
-
hasMore:
|
|
5184
|
-
provider:
|
|
5185
|
-
});
|
|
5186
|
-
var networkLogEntrySchema =
|
|
5187
|
-
timestamp:
|
|
5188
|
-
method:
|
|
5189
|
-
url:
|
|
5190
|
-
status:
|
|
5191
|
-
latency_ms:
|
|
5192
|
-
request_size:
|
|
5193
|
-
response_size:
|
|
5194
|
-
});
|
|
5195
|
-
var networkLogsResponseSchema =
|
|
5196
|
-
networkLogs:
|
|
5197
|
-
hasMore:
|
|
5198
|
-
});
|
|
5199
|
-
var telemetryResponseSchema =
|
|
5200
|
-
systemLog:
|
|
5201
|
-
metrics:
|
|
5202
|
-
});
|
|
5203
|
-
var runTelemetryContract =
|
|
5289
|
+
var telemetryMetricSchema = z6.object({
|
|
5290
|
+
ts: z6.string(),
|
|
5291
|
+
cpu: z6.number(),
|
|
5292
|
+
mem_used: z6.number(),
|
|
5293
|
+
mem_total: z6.number(),
|
|
5294
|
+
disk_used: z6.number(),
|
|
5295
|
+
disk_total: z6.number()
|
|
5296
|
+
});
|
|
5297
|
+
var systemLogResponseSchema = z6.object({
|
|
5298
|
+
systemLog: z6.string(),
|
|
5299
|
+
hasMore: z6.boolean()
|
|
5300
|
+
});
|
|
5301
|
+
var metricsResponseSchema = z6.object({
|
|
5302
|
+
metrics: z6.array(telemetryMetricSchema),
|
|
5303
|
+
hasMore: z6.boolean()
|
|
5304
|
+
});
|
|
5305
|
+
var agentEventsResponseSchema = z6.object({
|
|
5306
|
+
events: z6.array(runEventSchema),
|
|
5307
|
+
hasMore: z6.boolean(),
|
|
5308
|
+
provider: z6.string()
|
|
5309
|
+
});
|
|
5310
|
+
var networkLogEntrySchema = z6.object({
|
|
5311
|
+
timestamp: z6.string(),
|
|
5312
|
+
method: z6.string(),
|
|
5313
|
+
url: z6.string(),
|
|
5314
|
+
status: z6.number(),
|
|
5315
|
+
latency_ms: z6.number(),
|
|
5316
|
+
request_size: z6.number(),
|
|
5317
|
+
response_size: z6.number()
|
|
5318
|
+
});
|
|
5319
|
+
var networkLogsResponseSchema = z6.object({
|
|
5320
|
+
networkLogs: z6.array(networkLogEntrySchema),
|
|
5321
|
+
hasMore: z6.boolean()
|
|
5322
|
+
});
|
|
5323
|
+
var telemetryResponseSchema = z6.object({
|
|
5324
|
+
systemLog: z6.string(),
|
|
5325
|
+
metrics: z6.array(telemetryMetricSchema)
|
|
5326
|
+
});
|
|
5327
|
+
var runTelemetryContract = c3.router({
|
|
5204
5328
|
/**
|
|
5205
5329
|
* GET /api/agent/runs/:id/telemetry
|
|
5206
5330
|
* Get aggregated telemetry data for a run (legacy combined format)
|
|
@@ -5208,8 +5332,8 @@ var runTelemetryContract = c2.router({
|
|
|
5208
5332
|
getTelemetry: {
|
|
5209
5333
|
method: "GET",
|
|
5210
5334
|
path: "/api/agent/runs/:id/telemetry",
|
|
5211
|
-
pathParams:
|
|
5212
|
-
id:
|
|
5335
|
+
pathParams: z6.object({
|
|
5336
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5213
5337
|
}),
|
|
5214
5338
|
responses: {
|
|
5215
5339
|
200: telemetryResponseSchema,
|
|
@@ -5219,7 +5343,7 @@ var runTelemetryContract = c2.router({
|
|
|
5219
5343
|
summary: "Get run telemetry data"
|
|
5220
5344
|
}
|
|
5221
5345
|
});
|
|
5222
|
-
var runSystemLogContract =
|
|
5346
|
+
var runSystemLogContract = c3.router({
|
|
5223
5347
|
/**
|
|
5224
5348
|
* GET /api/agent/runs/:id/telemetry/system-log
|
|
5225
5349
|
* Get system log with pagination
|
|
@@ -5227,13 +5351,13 @@ var runSystemLogContract = c2.router({
|
|
|
5227
5351
|
getSystemLog: {
|
|
5228
5352
|
method: "GET",
|
|
5229
5353
|
path: "/api/agent/runs/:id/telemetry/system-log",
|
|
5230
|
-
pathParams:
|
|
5231
|
-
id:
|
|
5354
|
+
pathParams: z6.object({
|
|
5355
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5232
5356
|
}),
|
|
5233
|
-
query:
|
|
5234
|
-
since:
|
|
5235
|
-
limit:
|
|
5236
|
-
order:
|
|
5357
|
+
query: z6.object({
|
|
5358
|
+
since: z6.coerce.number().optional(),
|
|
5359
|
+
limit: z6.coerce.number().min(1).max(100).default(5),
|
|
5360
|
+
order: z6.enum(["asc", "desc"]).default("desc")
|
|
5237
5361
|
}),
|
|
5238
5362
|
responses: {
|
|
5239
5363
|
200: systemLogResponseSchema,
|
|
@@ -5243,7 +5367,7 @@ var runSystemLogContract = c2.router({
|
|
|
5243
5367
|
summary: "Get system log with pagination"
|
|
5244
5368
|
}
|
|
5245
5369
|
});
|
|
5246
|
-
var runMetricsContract =
|
|
5370
|
+
var runMetricsContract = c3.router({
|
|
5247
5371
|
/**
|
|
5248
5372
|
* GET /api/agent/runs/:id/telemetry/metrics
|
|
5249
5373
|
* Get metrics with pagination
|
|
@@ -5251,13 +5375,13 @@ var runMetricsContract = c2.router({
|
|
|
5251
5375
|
getMetrics: {
|
|
5252
5376
|
method: "GET",
|
|
5253
5377
|
path: "/api/agent/runs/:id/telemetry/metrics",
|
|
5254
|
-
pathParams:
|
|
5255
|
-
id:
|
|
5378
|
+
pathParams: z6.object({
|
|
5379
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5256
5380
|
}),
|
|
5257
|
-
query:
|
|
5258
|
-
since:
|
|
5259
|
-
limit:
|
|
5260
|
-
order:
|
|
5381
|
+
query: z6.object({
|
|
5382
|
+
since: z6.coerce.number().optional(),
|
|
5383
|
+
limit: z6.coerce.number().min(1).max(100).default(5),
|
|
5384
|
+
order: z6.enum(["asc", "desc"]).default("desc")
|
|
5261
5385
|
}),
|
|
5262
5386
|
responses: {
|
|
5263
5387
|
200: metricsResponseSchema,
|
|
@@ -5267,7 +5391,7 @@ var runMetricsContract = c2.router({
|
|
|
5267
5391
|
summary: "Get metrics with pagination"
|
|
5268
5392
|
}
|
|
5269
5393
|
});
|
|
5270
|
-
var runAgentEventsContract =
|
|
5394
|
+
var runAgentEventsContract = c3.router({
|
|
5271
5395
|
/**
|
|
5272
5396
|
* GET /api/agent/runs/:id/telemetry/agent
|
|
5273
5397
|
* Get agent events with pagination (for vm0 logs default)
|
|
@@ -5275,13 +5399,13 @@ var runAgentEventsContract = c2.router({
|
|
|
5275
5399
|
getAgentEvents: {
|
|
5276
5400
|
method: "GET",
|
|
5277
5401
|
path: "/api/agent/runs/:id/telemetry/agent",
|
|
5278
|
-
pathParams:
|
|
5279
|
-
id:
|
|
5402
|
+
pathParams: z6.object({
|
|
5403
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5280
5404
|
}),
|
|
5281
|
-
query:
|
|
5282
|
-
since:
|
|
5283
|
-
limit:
|
|
5284
|
-
order:
|
|
5405
|
+
query: z6.object({
|
|
5406
|
+
since: z6.coerce.number().optional(),
|
|
5407
|
+
limit: z6.coerce.number().min(1).max(100).default(5),
|
|
5408
|
+
order: z6.enum(["asc", "desc"]).default("desc")
|
|
5285
5409
|
}),
|
|
5286
5410
|
responses: {
|
|
5287
5411
|
200: agentEventsResponseSchema,
|
|
@@ -5291,7 +5415,7 @@ var runAgentEventsContract = c2.router({
|
|
|
5291
5415
|
summary: "Get agent events with pagination"
|
|
5292
5416
|
}
|
|
5293
5417
|
});
|
|
5294
|
-
var runNetworkLogsContract =
|
|
5418
|
+
var runNetworkLogsContract = c3.router({
|
|
5295
5419
|
/**
|
|
5296
5420
|
* GET /api/agent/runs/:id/telemetry/network
|
|
5297
5421
|
* Get network logs with pagination (for vm0 logs --network)
|
|
@@ -5299,13 +5423,13 @@ var runNetworkLogsContract = c2.router({
|
|
|
5299
5423
|
getNetworkLogs: {
|
|
5300
5424
|
method: "GET",
|
|
5301
5425
|
path: "/api/agent/runs/:id/telemetry/network",
|
|
5302
|
-
pathParams:
|
|
5303
|
-
id:
|
|
5426
|
+
pathParams: z6.object({
|
|
5427
|
+
id: z6.string().min(1, "Run ID is required")
|
|
5304
5428
|
}),
|
|
5305
|
-
query:
|
|
5306
|
-
since:
|
|
5307
|
-
limit:
|
|
5308
|
-
order:
|
|
5429
|
+
query: z6.object({
|
|
5430
|
+
since: z6.coerce.number().optional(),
|
|
5431
|
+
limit: z6.coerce.number().min(1).max(100).default(5),
|
|
5432
|
+
order: z6.enum(["asc", "desc"]).default("desc")
|
|
5309
5433
|
}),
|
|
5310
5434
|
responses: {
|
|
5311
5435
|
200: networkLogsResponseSchema,
|
|
@@ -5317,22 +5441,22 @@ var runNetworkLogsContract = c2.router({
|
|
|
5317
5441
|
});
|
|
5318
5442
|
|
|
5319
5443
|
// ../../packages/core/src/contracts/storages.ts
|
|
5320
|
-
import { z as
|
|
5321
|
-
var
|
|
5322
|
-
var storageTypeSchema =
|
|
5323
|
-
var versionQuerySchema =
|
|
5444
|
+
import { z as z7 } from "zod";
|
|
5445
|
+
var c4 = initContract();
|
|
5446
|
+
var storageTypeSchema = z7.enum(["volume", "artifact"]);
|
|
5447
|
+
var versionQuerySchema = z7.preprocess(
|
|
5324
5448
|
(val) => val === void 0 || val === null ? void 0 : String(val),
|
|
5325
|
-
|
|
5449
|
+
z7.string().regex(/^[a-f0-9]{8,64}$/i, "Version must be 8-64 hex characters").optional()
|
|
5326
5450
|
);
|
|
5327
|
-
var uploadStorageResponseSchema =
|
|
5328
|
-
name:
|
|
5329
|
-
versionId:
|
|
5330
|
-
size:
|
|
5331
|
-
fileCount:
|
|
5451
|
+
var uploadStorageResponseSchema = z7.object({
|
|
5452
|
+
name: z7.string(),
|
|
5453
|
+
versionId: z7.string(),
|
|
5454
|
+
size: z7.number(),
|
|
5455
|
+
fileCount: z7.number(),
|
|
5332
5456
|
type: storageTypeSchema,
|
|
5333
|
-
deduplicated:
|
|
5457
|
+
deduplicated: z7.boolean()
|
|
5334
5458
|
});
|
|
5335
|
-
var storagesContract =
|
|
5459
|
+
var storagesContract = c4.router({
|
|
5336
5460
|
/**
|
|
5337
5461
|
* POST /api/storages
|
|
5338
5462
|
* Upload a storage (tar.gz file)
|
|
@@ -5348,7 +5472,7 @@ var storagesContract = c3.router({
|
|
|
5348
5472
|
method: "POST",
|
|
5349
5473
|
path: "/api/storages",
|
|
5350
5474
|
contentType: "multipart/form-data",
|
|
5351
|
-
body:
|
|
5475
|
+
body: c4.type(),
|
|
5352
5476
|
responses: {
|
|
5353
5477
|
200: uploadStorageResponseSchema,
|
|
5354
5478
|
400: apiErrorSchema,
|
|
@@ -5370,15 +5494,15 @@ var storagesContract = c3.router({
|
|
|
5370
5494
|
download: {
|
|
5371
5495
|
method: "GET",
|
|
5372
5496
|
path: "/api/storages",
|
|
5373
|
-
query:
|
|
5374
|
-
name:
|
|
5497
|
+
query: z7.object({
|
|
5498
|
+
name: z7.string().min(1, "Storage name is required"),
|
|
5375
5499
|
version: versionQuerySchema
|
|
5376
5500
|
}),
|
|
5377
5501
|
responses: {
|
|
5378
5502
|
// Binary response - actual handling done at route level
|
|
5379
|
-
200:
|
|
5503
|
+
200: c4.otherResponse({
|
|
5380
5504
|
contentType: "application/gzip",
|
|
5381
|
-
body:
|
|
5505
|
+
body: c4.type()
|
|
5382
5506
|
}),
|
|
5383
5507
|
400: apiErrorSchema,
|
|
5384
5508
|
401: apiErrorSchema,
|
|
@@ -5388,40 +5512,40 @@ var storagesContract = c3.router({
|
|
|
5388
5512
|
summary: "Download storage archive"
|
|
5389
5513
|
}
|
|
5390
5514
|
});
|
|
5391
|
-
var fileEntryWithHashSchema =
|
|
5392
|
-
path:
|
|
5393
|
-
hash:
|
|
5394
|
-
size:
|
|
5515
|
+
var fileEntryWithHashSchema = z7.object({
|
|
5516
|
+
path: z7.string().min(1, "File path is required"),
|
|
5517
|
+
hash: z7.string().length(64, "Hash must be SHA-256 (64 hex chars)"),
|
|
5518
|
+
size: z7.number().int().min(0, "Size must be non-negative")
|
|
5395
5519
|
});
|
|
5396
|
-
var storageChangesSchema =
|
|
5397
|
-
added:
|
|
5398
|
-
modified:
|
|
5399
|
-
deleted:
|
|
5520
|
+
var storageChangesSchema = z7.object({
|
|
5521
|
+
added: z7.array(z7.string()),
|
|
5522
|
+
modified: z7.array(z7.string()),
|
|
5523
|
+
deleted: z7.array(z7.string())
|
|
5400
5524
|
});
|
|
5401
|
-
var presignedUploadSchema =
|
|
5402
|
-
key:
|
|
5403
|
-
presignedUrl:
|
|
5525
|
+
var presignedUploadSchema = z7.object({
|
|
5526
|
+
key: z7.string(),
|
|
5527
|
+
presignedUrl: z7.string().url()
|
|
5404
5528
|
});
|
|
5405
|
-
var storagesPrepareContract =
|
|
5529
|
+
var storagesPrepareContract = c4.router({
|
|
5406
5530
|
prepare: {
|
|
5407
5531
|
method: "POST",
|
|
5408
5532
|
path: "/api/storages/prepare",
|
|
5409
|
-
body:
|
|
5410
|
-
storageName:
|
|
5533
|
+
body: z7.object({
|
|
5534
|
+
storageName: z7.string().min(1, "Storage name is required"),
|
|
5411
5535
|
storageType: storageTypeSchema,
|
|
5412
|
-
files:
|
|
5413
|
-
force:
|
|
5414
|
-
runId:
|
|
5536
|
+
files: z7.array(fileEntryWithHashSchema),
|
|
5537
|
+
force: z7.boolean().optional(),
|
|
5538
|
+
runId: z7.string().optional(),
|
|
5415
5539
|
// For sandbox auth
|
|
5416
|
-
baseVersion:
|
|
5540
|
+
baseVersion: z7.string().optional(),
|
|
5417
5541
|
// For incremental uploads
|
|
5418
5542
|
changes: storageChangesSchema.optional()
|
|
5419
5543
|
}),
|
|
5420
5544
|
responses: {
|
|
5421
|
-
200:
|
|
5422
|
-
versionId:
|
|
5423
|
-
existing:
|
|
5424
|
-
uploads:
|
|
5545
|
+
200: z7.object({
|
|
5546
|
+
versionId: z7.string(),
|
|
5547
|
+
existing: z7.boolean(),
|
|
5548
|
+
uploads: z7.object({
|
|
5425
5549
|
archive: presignedUploadSchema,
|
|
5426
5550
|
manifest: presignedUploadSchema
|
|
5427
5551
|
}).optional()
|
|
@@ -5434,26 +5558,26 @@ var storagesPrepareContract = c3.router({
|
|
|
5434
5558
|
summary: "Prepare for direct S3 upload"
|
|
5435
5559
|
}
|
|
5436
5560
|
});
|
|
5437
|
-
var storagesCommitContract =
|
|
5561
|
+
var storagesCommitContract = c4.router({
|
|
5438
5562
|
commit: {
|
|
5439
5563
|
method: "POST",
|
|
5440
5564
|
path: "/api/storages/commit",
|
|
5441
|
-
body:
|
|
5442
|
-
storageName:
|
|
5565
|
+
body: z7.object({
|
|
5566
|
+
storageName: z7.string().min(1, "Storage name is required"),
|
|
5443
5567
|
storageType: storageTypeSchema,
|
|
5444
|
-
versionId:
|
|
5445
|
-
files:
|
|
5446
|
-
runId:
|
|
5447
|
-
message:
|
|
5568
|
+
versionId: z7.string().min(1, "Version ID is required"),
|
|
5569
|
+
files: z7.array(fileEntryWithHashSchema),
|
|
5570
|
+
runId: z7.string().optional(),
|
|
5571
|
+
message: z7.string().optional()
|
|
5448
5572
|
}),
|
|
5449
5573
|
responses: {
|
|
5450
|
-
200:
|
|
5451
|
-
success:
|
|
5452
|
-
versionId:
|
|
5453
|
-
storageName:
|
|
5454
|
-
size:
|
|
5455
|
-
fileCount:
|
|
5456
|
-
deduplicated:
|
|
5574
|
+
200: z7.object({
|
|
5575
|
+
success: z7.literal(true),
|
|
5576
|
+
versionId: z7.string(),
|
|
5577
|
+
storageName: z7.string(),
|
|
5578
|
+
size: z7.number(),
|
|
5579
|
+
fileCount: z7.number(),
|
|
5580
|
+
deduplicated: z7.boolean().optional()
|
|
5457
5581
|
}),
|
|
5458
5582
|
400: apiErrorSchema,
|
|
5459
5583
|
401: apiErrorSchema,
|
|
@@ -5465,30 +5589,30 @@ var storagesCommitContract = c3.router({
|
|
|
5465
5589
|
summary: "Commit uploaded storage"
|
|
5466
5590
|
}
|
|
5467
5591
|
});
|
|
5468
|
-
var storagesDownloadContract =
|
|
5592
|
+
var storagesDownloadContract = c4.router({
|
|
5469
5593
|
download: {
|
|
5470
5594
|
method: "GET",
|
|
5471
5595
|
path: "/api/storages/download",
|
|
5472
|
-
query:
|
|
5473
|
-
name:
|
|
5596
|
+
query: z7.object({
|
|
5597
|
+
name: z7.string().min(1, "Storage name is required"),
|
|
5474
5598
|
type: storageTypeSchema,
|
|
5475
5599
|
version: versionQuerySchema
|
|
5476
5600
|
}),
|
|
5477
5601
|
responses: {
|
|
5478
5602
|
// Normal response with presigned URL
|
|
5479
|
-
200:
|
|
5480
|
-
|
|
5481
|
-
url:
|
|
5482
|
-
versionId:
|
|
5483
|
-
fileCount:
|
|
5484
|
-
size:
|
|
5603
|
+
200: z7.union([
|
|
5604
|
+
z7.object({
|
|
5605
|
+
url: z7.string().url(),
|
|
5606
|
+
versionId: z7.string(),
|
|
5607
|
+
fileCount: z7.number(),
|
|
5608
|
+
size: z7.number()
|
|
5485
5609
|
}),
|
|
5486
5610
|
// Empty artifact response
|
|
5487
|
-
|
|
5488
|
-
empty:
|
|
5489
|
-
versionId:
|
|
5490
|
-
fileCount:
|
|
5491
|
-
size:
|
|
5611
|
+
z7.object({
|
|
5612
|
+
empty: z7.literal(true),
|
|
5613
|
+
versionId: z7.string(),
|
|
5614
|
+
fileCount: z7.literal(0),
|
|
5615
|
+
size: z7.literal(0)
|
|
5492
5616
|
})
|
|
5493
5617
|
]),
|
|
5494
5618
|
400: apiErrorSchema,
|
|
@@ -5499,20 +5623,20 @@ var storagesDownloadContract = c3.router({
|
|
|
5499
5623
|
summary: "Get presigned download URL"
|
|
5500
5624
|
}
|
|
5501
5625
|
});
|
|
5502
|
-
var storagesListContract =
|
|
5626
|
+
var storagesListContract = c4.router({
|
|
5503
5627
|
list: {
|
|
5504
5628
|
method: "GET",
|
|
5505
5629
|
path: "/api/storages/list",
|
|
5506
|
-
query:
|
|
5630
|
+
query: z7.object({
|
|
5507
5631
|
type: storageTypeSchema
|
|
5508
5632
|
}),
|
|
5509
5633
|
responses: {
|
|
5510
|
-
200:
|
|
5511
|
-
|
|
5512
|
-
name:
|
|
5513
|
-
size:
|
|
5514
|
-
fileCount:
|
|
5515
|
-
updatedAt:
|
|
5634
|
+
200: z7.array(
|
|
5635
|
+
z7.object({
|
|
5636
|
+
name: z7.string(),
|
|
5637
|
+
size: z7.number(),
|
|
5638
|
+
fileCount: z7.number(),
|
|
5639
|
+
updatedAt: z7.string()
|
|
5516
5640
|
})
|
|
5517
5641
|
),
|
|
5518
5642
|
401: apiErrorSchema,
|
|
@@ -5523,20 +5647,20 @@ var storagesListContract = c3.router({
|
|
|
5523
5647
|
});
|
|
5524
5648
|
|
|
5525
5649
|
// ../../packages/core/src/contracts/webhooks.ts
|
|
5526
|
-
import { z as
|
|
5527
|
-
var
|
|
5528
|
-
var agentEventSchema =
|
|
5529
|
-
type:
|
|
5530
|
-
sequenceNumber:
|
|
5650
|
+
import { z as z8 } from "zod";
|
|
5651
|
+
var c5 = initContract();
|
|
5652
|
+
var agentEventSchema = z8.object({
|
|
5653
|
+
type: z8.string(),
|
|
5654
|
+
sequenceNumber: z8.number().int().positive()
|
|
5531
5655
|
}).passthrough();
|
|
5532
|
-
var artifactSnapshotSchema =
|
|
5533
|
-
artifactName:
|
|
5534
|
-
artifactVersion:
|
|
5656
|
+
var artifactSnapshotSchema = z8.object({
|
|
5657
|
+
artifactName: z8.string(),
|
|
5658
|
+
artifactVersion: z8.string()
|
|
5535
5659
|
});
|
|
5536
|
-
var volumeVersionsSnapshotSchema =
|
|
5537
|
-
versions:
|
|
5660
|
+
var volumeVersionsSnapshotSchema = z8.object({
|
|
5661
|
+
versions: z8.record(z8.string(), z8.string())
|
|
5538
5662
|
});
|
|
5539
|
-
var webhookEventsContract =
|
|
5663
|
+
var webhookEventsContract = c5.router({
|
|
5540
5664
|
/**
|
|
5541
5665
|
* POST /api/webhooks/agent/events
|
|
5542
5666
|
* Receive agent events from E2B sandbox
|
|
@@ -5544,15 +5668,15 @@ var webhookEventsContract = c4.router({
|
|
|
5544
5668
|
send: {
|
|
5545
5669
|
method: "POST",
|
|
5546
5670
|
path: "/api/webhooks/agent/events",
|
|
5547
|
-
body:
|
|
5548
|
-
runId:
|
|
5549
|
-
events:
|
|
5671
|
+
body: z8.object({
|
|
5672
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5673
|
+
events: z8.array(agentEventSchema).min(1, "events array cannot be empty")
|
|
5550
5674
|
}),
|
|
5551
5675
|
responses: {
|
|
5552
|
-
200:
|
|
5553
|
-
received:
|
|
5554
|
-
firstSequence:
|
|
5555
|
-
lastSequence:
|
|
5676
|
+
200: z8.object({
|
|
5677
|
+
received: z8.number(),
|
|
5678
|
+
firstSequence: z8.number(),
|
|
5679
|
+
lastSequence: z8.number()
|
|
5556
5680
|
}),
|
|
5557
5681
|
400: apiErrorSchema,
|
|
5558
5682
|
401: apiErrorSchema,
|
|
@@ -5562,7 +5686,7 @@ var webhookEventsContract = c4.router({
|
|
|
5562
5686
|
summary: "Receive agent events from sandbox"
|
|
5563
5687
|
}
|
|
5564
5688
|
});
|
|
5565
|
-
var webhookCompleteContract =
|
|
5689
|
+
var webhookCompleteContract = c5.router({
|
|
5566
5690
|
/**
|
|
5567
5691
|
* POST /api/webhooks/agent/complete
|
|
5568
5692
|
* Handle agent run completion (success or failure)
|
|
@@ -5570,15 +5694,15 @@ var webhookCompleteContract = c4.router({
|
|
|
5570
5694
|
complete: {
|
|
5571
5695
|
method: "POST",
|
|
5572
5696
|
path: "/api/webhooks/agent/complete",
|
|
5573
|
-
body:
|
|
5574
|
-
runId:
|
|
5575
|
-
exitCode:
|
|
5576
|
-
error:
|
|
5697
|
+
body: z8.object({
|
|
5698
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5699
|
+
exitCode: z8.number(),
|
|
5700
|
+
error: z8.string().optional()
|
|
5577
5701
|
}),
|
|
5578
5702
|
responses: {
|
|
5579
|
-
200:
|
|
5580
|
-
success:
|
|
5581
|
-
status:
|
|
5703
|
+
200: z8.object({
|
|
5704
|
+
success: z8.boolean(),
|
|
5705
|
+
status: z8.enum(["completed", "failed"])
|
|
5582
5706
|
}),
|
|
5583
5707
|
400: apiErrorSchema,
|
|
5584
5708
|
401: apiErrorSchema,
|
|
@@ -5588,7 +5712,7 @@ var webhookCompleteContract = c4.router({
|
|
|
5588
5712
|
summary: "Handle agent run completion"
|
|
5589
5713
|
}
|
|
5590
5714
|
});
|
|
5591
|
-
var webhookCheckpointsContract =
|
|
5715
|
+
var webhookCheckpointsContract = c5.router({
|
|
5592
5716
|
/**
|
|
5593
5717
|
* POST /api/webhooks/agent/checkpoints
|
|
5594
5718
|
* Create checkpoint for completed agent run
|
|
@@ -5596,21 +5720,21 @@ var webhookCheckpointsContract = c4.router({
|
|
|
5596
5720
|
create: {
|
|
5597
5721
|
method: "POST",
|
|
5598
5722
|
path: "/api/webhooks/agent/checkpoints",
|
|
5599
|
-
body:
|
|
5600
|
-
runId:
|
|
5601
|
-
cliAgentType:
|
|
5602
|
-
cliAgentSessionId:
|
|
5603
|
-
cliAgentSessionHistory:
|
|
5723
|
+
body: z8.object({
|
|
5724
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5725
|
+
cliAgentType: z8.string().min(1, "cliAgentType is required"),
|
|
5726
|
+
cliAgentSessionId: z8.string().min(1, "cliAgentSessionId is required"),
|
|
5727
|
+
cliAgentSessionHistory: z8.string().min(1, "cliAgentSessionHistory is required"),
|
|
5604
5728
|
artifactSnapshot: artifactSnapshotSchema.optional(),
|
|
5605
5729
|
volumeVersionsSnapshot: volumeVersionsSnapshotSchema.optional()
|
|
5606
5730
|
}),
|
|
5607
5731
|
responses: {
|
|
5608
|
-
200:
|
|
5609
|
-
checkpointId:
|
|
5610
|
-
agentSessionId:
|
|
5611
|
-
conversationId:
|
|
5732
|
+
200: z8.object({
|
|
5733
|
+
checkpointId: z8.string(),
|
|
5734
|
+
agentSessionId: z8.string(),
|
|
5735
|
+
conversationId: z8.string(),
|
|
5612
5736
|
artifact: artifactSnapshotSchema.optional(),
|
|
5613
|
-
volumes:
|
|
5737
|
+
volumes: z8.record(z8.string(), z8.string()).optional()
|
|
5614
5738
|
}),
|
|
5615
5739
|
400: apiErrorSchema,
|
|
5616
5740
|
401: apiErrorSchema,
|
|
@@ -5620,7 +5744,7 @@ var webhookCheckpointsContract = c4.router({
|
|
|
5620
5744
|
summary: "Create checkpoint for agent run"
|
|
5621
5745
|
}
|
|
5622
5746
|
});
|
|
5623
|
-
var webhookHeartbeatContract =
|
|
5747
|
+
var webhookHeartbeatContract = c5.router({
|
|
5624
5748
|
/**
|
|
5625
5749
|
* POST /api/webhooks/agent/heartbeat
|
|
5626
5750
|
* Receive heartbeat signals from E2B sandbox
|
|
@@ -5628,12 +5752,12 @@ var webhookHeartbeatContract = c4.router({
|
|
|
5628
5752
|
send: {
|
|
5629
5753
|
method: "POST",
|
|
5630
5754
|
path: "/api/webhooks/agent/heartbeat",
|
|
5631
|
-
body:
|
|
5632
|
-
runId:
|
|
5755
|
+
body: z8.object({
|
|
5756
|
+
runId: z8.string().min(1, "runId is required")
|
|
5633
5757
|
}),
|
|
5634
5758
|
responses: {
|
|
5635
|
-
200:
|
|
5636
|
-
ok:
|
|
5759
|
+
200: z8.object({
|
|
5760
|
+
ok: z8.boolean()
|
|
5637
5761
|
}),
|
|
5638
5762
|
400: apiErrorSchema,
|
|
5639
5763
|
401: apiErrorSchema,
|
|
@@ -5643,7 +5767,7 @@ var webhookHeartbeatContract = c4.router({
|
|
|
5643
5767
|
summary: "Receive heartbeat from sandbox"
|
|
5644
5768
|
}
|
|
5645
5769
|
});
|
|
5646
|
-
var webhookStoragesContract =
|
|
5770
|
+
var webhookStoragesContract = c5.router({
|
|
5647
5771
|
/**
|
|
5648
5772
|
* POST /api/webhooks/agent/storages
|
|
5649
5773
|
* Create a new version of a storage from sandbox
|
|
@@ -5658,13 +5782,13 @@ var webhookStoragesContract = c4.router({
|
|
|
5658
5782
|
method: "POST",
|
|
5659
5783
|
path: "/api/webhooks/agent/storages",
|
|
5660
5784
|
contentType: "multipart/form-data",
|
|
5661
|
-
body:
|
|
5785
|
+
body: c5.type(),
|
|
5662
5786
|
responses: {
|
|
5663
|
-
200:
|
|
5664
|
-
versionId:
|
|
5665
|
-
storageName:
|
|
5666
|
-
size:
|
|
5667
|
-
fileCount:
|
|
5787
|
+
200: z8.object({
|
|
5788
|
+
versionId: z8.string(),
|
|
5789
|
+
storageName: z8.string(),
|
|
5790
|
+
size: z8.number(),
|
|
5791
|
+
fileCount: z8.number()
|
|
5668
5792
|
}),
|
|
5669
5793
|
400: apiErrorSchema,
|
|
5670
5794
|
401: apiErrorSchema,
|
|
@@ -5674,7 +5798,7 @@ var webhookStoragesContract = c4.router({
|
|
|
5674
5798
|
summary: "Upload storage version from sandbox"
|
|
5675
5799
|
}
|
|
5676
5800
|
});
|
|
5677
|
-
var webhookStoragesIncrementalContract =
|
|
5801
|
+
var webhookStoragesIncrementalContract = c5.router({
|
|
5678
5802
|
/**
|
|
5679
5803
|
* POST /api/webhooks/agent/storages/incremental
|
|
5680
5804
|
* Create a new version using incremental upload
|
|
@@ -5691,19 +5815,19 @@ var webhookStoragesIncrementalContract = c4.router({
|
|
|
5691
5815
|
method: "POST",
|
|
5692
5816
|
path: "/api/webhooks/agent/storages/incremental",
|
|
5693
5817
|
contentType: "multipart/form-data",
|
|
5694
|
-
body:
|
|
5818
|
+
body: c5.type(),
|
|
5695
5819
|
responses: {
|
|
5696
|
-
200:
|
|
5697
|
-
versionId:
|
|
5698
|
-
storageName:
|
|
5699
|
-
size:
|
|
5700
|
-
fileCount:
|
|
5701
|
-
incrementalStats:
|
|
5702
|
-
addedFiles:
|
|
5703
|
-
modifiedFiles:
|
|
5704
|
-
deletedFiles:
|
|
5705
|
-
unchangedFiles:
|
|
5706
|
-
bytesUploaded:
|
|
5820
|
+
200: z8.object({
|
|
5821
|
+
versionId: z8.string(),
|
|
5822
|
+
storageName: z8.string(),
|
|
5823
|
+
size: z8.number(),
|
|
5824
|
+
fileCount: z8.number(),
|
|
5825
|
+
incrementalStats: z8.object({
|
|
5826
|
+
addedFiles: z8.number(),
|
|
5827
|
+
modifiedFiles: z8.number(),
|
|
5828
|
+
deletedFiles: z8.number(),
|
|
5829
|
+
unchangedFiles: z8.number(),
|
|
5830
|
+
bytesUploaded: z8.number()
|
|
5707
5831
|
}).optional()
|
|
5708
5832
|
}),
|
|
5709
5833
|
400: apiErrorSchema,
|
|
@@ -5714,24 +5838,24 @@ var webhookStoragesIncrementalContract = c4.router({
|
|
|
5714
5838
|
summary: "Upload storage version incrementally from sandbox"
|
|
5715
5839
|
}
|
|
5716
5840
|
});
|
|
5717
|
-
var metricDataSchema =
|
|
5718
|
-
ts:
|
|
5719
|
-
cpu:
|
|
5720
|
-
mem_used:
|
|
5721
|
-
mem_total:
|
|
5722
|
-
disk_used:
|
|
5723
|
-
disk_total:
|
|
5724
|
-
});
|
|
5725
|
-
var networkLogSchema =
|
|
5726
|
-
timestamp:
|
|
5727
|
-
method:
|
|
5728
|
-
url:
|
|
5729
|
-
status:
|
|
5730
|
-
latency_ms:
|
|
5731
|
-
request_size:
|
|
5732
|
-
response_size:
|
|
5733
|
-
});
|
|
5734
|
-
var webhookTelemetryContract =
|
|
5841
|
+
var metricDataSchema = z8.object({
|
|
5842
|
+
ts: z8.string(),
|
|
5843
|
+
cpu: z8.number(),
|
|
5844
|
+
mem_used: z8.number(),
|
|
5845
|
+
mem_total: z8.number(),
|
|
5846
|
+
disk_used: z8.number(),
|
|
5847
|
+
disk_total: z8.number()
|
|
5848
|
+
});
|
|
5849
|
+
var networkLogSchema = z8.object({
|
|
5850
|
+
timestamp: z8.string(),
|
|
5851
|
+
method: z8.string(),
|
|
5852
|
+
url: z8.string(),
|
|
5853
|
+
status: z8.number(),
|
|
5854
|
+
latency_ms: z8.number(),
|
|
5855
|
+
request_size: z8.number(),
|
|
5856
|
+
response_size: z8.number()
|
|
5857
|
+
});
|
|
5858
|
+
var webhookTelemetryContract = c5.router({
|
|
5735
5859
|
/**
|
|
5736
5860
|
* POST /api/webhooks/agent/telemetry
|
|
5737
5861
|
* Receive telemetry data (system log, metrics, and network logs) from sandbox
|
|
@@ -5739,16 +5863,16 @@ var webhookTelemetryContract = c4.router({
|
|
|
5739
5863
|
send: {
|
|
5740
5864
|
method: "POST",
|
|
5741
5865
|
path: "/api/webhooks/agent/telemetry",
|
|
5742
|
-
body:
|
|
5743
|
-
runId:
|
|
5744
|
-
systemLog:
|
|
5745
|
-
metrics:
|
|
5746
|
-
networkLogs:
|
|
5866
|
+
body: z8.object({
|
|
5867
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5868
|
+
systemLog: z8.string().optional(),
|
|
5869
|
+
metrics: z8.array(metricDataSchema).optional(),
|
|
5870
|
+
networkLogs: z8.array(networkLogSchema).optional()
|
|
5747
5871
|
}),
|
|
5748
5872
|
responses: {
|
|
5749
|
-
200:
|
|
5750
|
-
success:
|
|
5751
|
-
id:
|
|
5873
|
+
200: z8.object({
|
|
5874
|
+
success: z8.boolean(),
|
|
5875
|
+
id: z8.string()
|
|
5752
5876
|
}),
|
|
5753
5877
|
400: apiErrorSchema,
|
|
5754
5878
|
401: apiErrorSchema,
|
|
@@ -5758,25 +5882,25 @@ var webhookTelemetryContract = c4.router({
|
|
|
5758
5882
|
summary: "Receive telemetry data from sandbox"
|
|
5759
5883
|
}
|
|
5760
5884
|
});
|
|
5761
|
-
var webhookStoragesPrepareContract =
|
|
5885
|
+
var webhookStoragesPrepareContract = c5.router({
|
|
5762
5886
|
prepare: {
|
|
5763
5887
|
method: "POST",
|
|
5764
5888
|
path: "/api/webhooks/agent/storages/prepare",
|
|
5765
|
-
body:
|
|
5766
|
-
runId:
|
|
5889
|
+
body: z8.object({
|
|
5890
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5767
5891
|
// Required for webhook auth
|
|
5768
|
-
storageName:
|
|
5892
|
+
storageName: z8.string().min(1, "Storage name is required"),
|
|
5769
5893
|
storageType: storageTypeSchema,
|
|
5770
|
-
files:
|
|
5771
|
-
force:
|
|
5772
|
-
baseVersion:
|
|
5894
|
+
files: z8.array(fileEntryWithHashSchema),
|
|
5895
|
+
force: z8.boolean().optional(),
|
|
5896
|
+
baseVersion: z8.string().optional(),
|
|
5773
5897
|
changes: storageChangesSchema.optional()
|
|
5774
5898
|
}),
|
|
5775
5899
|
responses: {
|
|
5776
|
-
200:
|
|
5777
|
-
versionId:
|
|
5778
|
-
existing:
|
|
5779
|
-
uploads:
|
|
5900
|
+
200: z8.object({
|
|
5901
|
+
versionId: z8.string(),
|
|
5902
|
+
existing: z8.boolean(),
|
|
5903
|
+
uploads: z8.object({
|
|
5780
5904
|
archive: presignedUploadSchema,
|
|
5781
5905
|
manifest: presignedUploadSchema
|
|
5782
5906
|
}).optional()
|
|
@@ -5789,27 +5913,27 @@ var webhookStoragesPrepareContract = c4.router({
|
|
|
5789
5913
|
summary: "Prepare for direct S3 upload from sandbox"
|
|
5790
5914
|
}
|
|
5791
5915
|
});
|
|
5792
|
-
var webhookStoragesCommitContract =
|
|
5916
|
+
var webhookStoragesCommitContract = c5.router({
|
|
5793
5917
|
commit: {
|
|
5794
5918
|
method: "POST",
|
|
5795
5919
|
path: "/api/webhooks/agent/storages/commit",
|
|
5796
|
-
body:
|
|
5797
|
-
runId:
|
|
5920
|
+
body: z8.object({
|
|
5921
|
+
runId: z8.string().min(1, "runId is required"),
|
|
5798
5922
|
// Required for webhook auth
|
|
5799
|
-
storageName:
|
|
5923
|
+
storageName: z8.string().min(1, "Storage name is required"),
|
|
5800
5924
|
storageType: storageTypeSchema,
|
|
5801
|
-
versionId:
|
|
5802
|
-
files:
|
|
5803
|
-
message:
|
|
5925
|
+
versionId: z8.string().min(1, "Version ID is required"),
|
|
5926
|
+
files: z8.array(fileEntryWithHashSchema),
|
|
5927
|
+
message: z8.string().optional()
|
|
5804
5928
|
}),
|
|
5805
5929
|
responses: {
|
|
5806
|
-
200:
|
|
5807
|
-
success:
|
|
5808
|
-
versionId:
|
|
5809
|
-
storageName:
|
|
5810
|
-
size:
|
|
5811
|
-
fileCount:
|
|
5812
|
-
deduplicated:
|
|
5930
|
+
200: z8.object({
|
|
5931
|
+
success: z8.literal(true),
|
|
5932
|
+
versionId: z8.string(),
|
|
5933
|
+
storageName: z8.string(),
|
|
5934
|
+
size: z8.number(),
|
|
5935
|
+
fileCount: z8.number(),
|
|
5936
|
+
deduplicated: z8.boolean().optional()
|
|
5813
5937
|
}),
|
|
5814
5938
|
400: apiErrorSchema,
|
|
5815
5939
|
401: apiErrorSchema,
|
|
@@ -5823,13 +5947,13 @@ var webhookStoragesCommitContract = c4.router({
|
|
|
5823
5947
|
});
|
|
5824
5948
|
|
|
5825
5949
|
// ../../packages/core/src/contracts/cli-auth.ts
|
|
5826
|
-
import { z as
|
|
5827
|
-
var
|
|
5828
|
-
var oauthErrorSchema =
|
|
5829
|
-
error:
|
|
5830
|
-
error_description:
|
|
5950
|
+
import { z as z9 } from "zod";
|
|
5951
|
+
var c6 = initContract();
|
|
5952
|
+
var oauthErrorSchema = z9.object({
|
|
5953
|
+
error: z9.string(),
|
|
5954
|
+
error_description: z9.string()
|
|
5831
5955
|
});
|
|
5832
|
-
var cliAuthDeviceContract =
|
|
5956
|
+
var cliAuthDeviceContract = c6.router({
|
|
5833
5957
|
/**
|
|
5834
5958
|
* POST /api/cli/auth/device
|
|
5835
5959
|
* Initiate device authorization flow
|
|
@@ -5837,21 +5961,21 @@ var cliAuthDeviceContract = c5.router({
|
|
|
5837
5961
|
create: {
|
|
5838
5962
|
method: "POST",
|
|
5839
5963
|
path: "/api/cli/auth/device",
|
|
5840
|
-
body:
|
|
5964
|
+
body: z9.object({}).optional(),
|
|
5841
5965
|
responses: {
|
|
5842
|
-
200:
|
|
5843
|
-
device_code:
|
|
5844
|
-
user_code:
|
|
5845
|
-
verification_url:
|
|
5846
|
-
expires_in:
|
|
5847
|
-
interval:
|
|
5966
|
+
200: z9.object({
|
|
5967
|
+
device_code: z9.string(),
|
|
5968
|
+
user_code: z9.string(),
|
|
5969
|
+
verification_url: z9.string(),
|
|
5970
|
+
expires_in: z9.number(),
|
|
5971
|
+
interval: z9.number()
|
|
5848
5972
|
}),
|
|
5849
5973
|
500: oauthErrorSchema
|
|
5850
5974
|
},
|
|
5851
5975
|
summary: "Initiate device authorization flow"
|
|
5852
5976
|
}
|
|
5853
5977
|
});
|
|
5854
|
-
var cliAuthTokenContract =
|
|
5978
|
+
var cliAuthTokenContract = c6.router({
|
|
5855
5979
|
/**
|
|
5856
5980
|
* POST /api/cli/auth/token
|
|
5857
5981
|
* Exchange device code for access token
|
|
@@ -5859,16 +5983,16 @@ var cliAuthTokenContract = c5.router({
|
|
|
5859
5983
|
exchange: {
|
|
5860
5984
|
method: "POST",
|
|
5861
5985
|
path: "/api/cli/auth/token",
|
|
5862
|
-
body:
|
|
5863
|
-
device_code:
|
|
5986
|
+
body: z9.object({
|
|
5987
|
+
device_code: z9.string().min(1, "device_code is required")
|
|
5864
5988
|
}),
|
|
5865
5989
|
responses: {
|
|
5866
5990
|
// Success - token issued
|
|
5867
|
-
200:
|
|
5868
|
-
access_token:
|
|
5869
|
-
refresh_token:
|
|
5870
|
-
token_type:
|
|
5871
|
-
expires_in:
|
|
5991
|
+
200: z9.object({
|
|
5992
|
+
access_token: z9.string(),
|
|
5993
|
+
refresh_token: z9.string(),
|
|
5994
|
+
token_type: z9.literal("Bearer"),
|
|
5995
|
+
expires_in: z9.number()
|
|
5872
5996
|
}),
|
|
5873
5997
|
// Authorization pending
|
|
5874
5998
|
202: oauthErrorSchema,
|
|
@@ -5881,9 +6005,9 @@ var cliAuthTokenContract = c5.router({
|
|
|
5881
6005
|
});
|
|
5882
6006
|
|
|
5883
6007
|
// ../../packages/core/src/contracts/auth.ts
|
|
5884
|
-
import { z as
|
|
5885
|
-
var
|
|
5886
|
-
var authContract =
|
|
6008
|
+
import { z as z10 } from "zod";
|
|
6009
|
+
var c7 = initContract();
|
|
6010
|
+
var authContract = c7.router({
|
|
5887
6011
|
/**
|
|
5888
6012
|
* GET /api/auth/me
|
|
5889
6013
|
* Get current user information
|
|
@@ -5892,9 +6016,9 @@ var authContract = c6.router({
|
|
|
5892
6016
|
method: "GET",
|
|
5893
6017
|
path: "/api/auth/me",
|
|
5894
6018
|
responses: {
|
|
5895
|
-
200:
|
|
5896
|
-
userId:
|
|
5897
|
-
email:
|
|
6019
|
+
200: z10.object({
|
|
6020
|
+
userId: z10.string(),
|
|
6021
|
+
email: z10.string()
|
|
5898
6022
|
}),
|
|
5899
6023
|
401: apiErrorSchema,
|
|
5900
6024
|
404: apiErrorSchema,
|
|
@@ -5905,20 +6029,20 @@ var authContract = c6.router({
|
|
|
5905
6029
|
});
|
|
5906
6030
|
|
|
5907
6031
|
// ../../packages/core/src/contracts/cron.ts
|
|
5908
|
-
import { z as
|
|
5909
|
-
var
|
|
5910
|
-
var cleanupResultSchema =
|
|
5911
|
-
runId:
|
|
5912
|
-
sandboxId:
|
|
5913
|
-
status:
|
|
5914
|
-
error:
|
|
5915
|
-
});
|
|
5916
|
-
var cleanupResponseSchema =
|
|
5917
|
-
cleaned:
|
|
5918
|
-
errors:
|
|
5919
|
-
results:
|
|
5920
|
-
});
|
|
5921
|
-
var cronCleanupSandboxesContract =
|
|
6032
|
+
import { z as z11 } from "zod";
|
|
6033
|
+
var c8 = initContract();
|
|
6034
|
+
var cleanupResultSchema = z11.object({
|
|
6035
|
+
runId: z11.string(),
|
|
6036
|
+
sandboxId: z11.string().nullable(),
|
|
6037
|
+
status: z11.enum(["cleaned", "error"]),
|
|
6038
|
+
error: z11.string().optional()
|
|
6039
|
+
});
|
|
6040
|
+
var cleanupResponseSchema = z11.object({
|
|
6041
|
+
cleaned: z11.number(),
|
|
6042
|
+
errors: z11.number(),
|
|
6043
|
+
results: z11.array(cleanupResultSchema)
|
|
6044
|
+
});
|
|
6045
|
+
var cronCleanupSandboxesContract = c8.router({
|
|
5922
6046
|
/**
|
|
5923
6047
|
* GET /api/cron/cleanup-sandboxes
|
|
5924
6048
|
* Cron job to cleanup sandboxes that have stopped sending heartbeats
|
|
@@ -5936,48 +6060,48 @@ var cronCleanupSandboxesContract = c7.router({
|
|
|
5936
6060
|
});
|
|
5937
6061
|
|
|
5938
6062
|
// ../../packages/core/src/contracts/proxy.ts
|
|
5939
|
-
import { z as
|
|
5940
|
-
var proxyErrorSchema =
|
|
5941
|
-
error:
|
|
5942
|
-
message:
|
|
5943
|
-
code:
|
|
6063
|
+
import { z as z12 } from "zod";
|
|
6064
|
+
var proxyErrorSchema = z12.object({
|
|
6065
|
+
error: z12.object({
|
|
6066
|
+
message: z12.string(),
|
|
6067
|
+
code: z12.enum([
|
|
5944
6068
|
"UNAUTHORIZED",
|
|
5945
6069
|
"BAD_REQUEST",
|
|
5946
6070
|
"BAD_GATEWAY",
|
|
5947
6071
|
"INTERNAL_ERROR"
|
|
5948
6072
|
]),
|
|
5949
|
-
targetUrl:
|
|
6073
|
+
targetUrl: z12.string().optional()
|
|
5950
6074
|
})
|
|
5951
6075
|
});
|
|
5952
6076
|
|
|
5953
6077
|
// ../../packages/core/src/contracts/scopes.ts
|
|
5954
|
-
import { z as
|
|
5955
|
-
var
|
|
5956
|
-
var scopeTypeSchema =
|
|
5957
|
-
var scopeSlugSchema =
|
|
6078
|
+
import { z as z13 } from "zod";
|
|
6079
|
+
var c9 = initContract();
|
|
6080
|
+
var scopeTypeSchema = z13.enum(["personal", "organization", "system"]);
|
|
6081
|
+
var scopeSlugSchema = z13.string().min(3, "Scope slug must be at least 3 characters").max(64, "Scope slug must be at most 64 characters").regex(
|
|
5958
6082
|
/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]{1,2}$/,
|
|
5959
6083
|
"Scope slug must contain only lowercase letters, numbers, and hyphens, and must start and end with an alphanumeric character"
|
|
5960
6084
|
).refine(
|
|
5961
6085
|
(slug) => !slug.startsWith("vm0"),
|
|
5962
6086
|
"Scope slug cannot start with 'vm0' (reserved)"
|
|
5963
6087
|
).transform((s) => s.toLowerCase());
|
|
5964
|
-
var scopeResponseSchema =
|
|
5965
|
-
id:
|
|
5966
|
-
slug:
|
|
6088
|
+
var scopeResponseSchema = z13.object({
|
|
6089
|
+
id: z13.string().uuid(),
|
|
6090
|
+
slug: z13.string(),
|
|
5967
6091
|
type: scopeTypeSchema,
|
|
5968
|
-
displayName:
|
|
5969
|
-
createdAt:
|
|
5970
|
-
updatedAt:
|
|
6092
|
+
displayName: z13.string().nullable(),
|
|
6093
|
+
createdAt: z13.string(),
|
|
6094
|
+
updatedAt: z13.string()
|
|
5971
6095
|
});
|
|
5972
|
-
var createScopeRequestSchema =
|
|
6096
|
+
var createScopeRequestSchema = z13.object({
|
|
5973
6097
|
slug: scopeSlugSchema,
|
|
5974
|
-
displayName:
|
|
6098
|
+
displayName: z13.string().max(128).optional()
|
|
5975
6099
|
});
|
|
5976
|
-
var updateScopeRequestSchema =
|
|
6100
|
+
var updateScopeRequestSchema = z13.object({
|
|
5977
6101
|
slug: scopeSlugSchema,
|
|
5978
|
-
force:
|
|
6102
|
+
force: z13.boolean().optional().default(false)
|
|
5979
6103
|
});
|
|
5980
|
-
var scopeContract =
|
|
6104
|
+
var scopeContract = c9.router({
|
|
5981
6105
|
/**
|
|
5982
6106
|
* GET /api/scope
|
|
5983
6107
|
* Get current user's scope
|
|
@@ -6032,42 +6156,42 @@ var scopeContract = c8.router({
|
|
|
6032
6156
|
});
|
|
6033
6157
|
|
|
6034
6158
|
// ../../packages/core/src/contracts/sessions.ts
|
|
6035
|
-
import { z as
|
|
6036
|
-
var
|
|
6037
|
-
var sessionResponseSchema =
|
|
6038
|
-
id:
|
|
6039
|
-
agentComposeId:
|
|
6040
|
-
agentComposeVersionId:
|
|
6041
|
-
conversationId:
|
|
6042
|
-
artifactName:
|
|
6043
|
-
vars:
|
|
6044
|
-
secretNames:
|
|
6045
|
-
volumeVersions:
|
|
6046
|
-
createdAt:
|
|
6047
|
-
updatedAt:
|
|
6159
|
+
import { z as z14 } from "zod";
|
|
6160
|
+
var c10 = initContract();
|
|
6161
|
+
var sessionResponseSchema = z14.object({
|
|
6162
|
+
id: z14.string(),
|
|
6163
|
+
agentComposeId: z14.string(),
|
|
6164
|
+
agentComposeVersionId: z14.string().nullable(),
|
|
6165
|
+
conversationId: z14.string().nullable(),
|
|
6166
|
+
artifactName: z14.string().nullable(),
|
|
6167
|
+
vars: z14.record(z14.string(), z14.string()).nullable(),
|
|
6168
|
+
secretNames: z14.array(z14.string()).nullable(),
|
|
6169
|
+
volumeVersions: z14.record(z14.string(), z14.string()).nullable(),
|
|
6170
|
+
createdAt: z14.string(),
|
|
6171
|
+
updatedAt: z14.string()
|
|
6048
6172
|
});
|
|
6049
|
-
var agentComposeSnapshotSchema =
|
|
6050
|
-
agentComposeVersionId:
|
|
6051
|
-
vars:
|
|
6052
|
-
secretNames:
|
|
6173
|
+
var agentComposeSnapshotSchema = z14.object({
|
|
6174
|
+
agentComposeVersionId: z14.string(),
|
|
6175
|
+
vars: z14.record(z14.string(), z14.string()).optional(),
|
|
6176
|
+
secretNames: z14.array(z14.string()).optional()
|
|
6053
6177
|
});
|
|
6054
|
-
var artifactSnapshotSchema2 =
|
|
6055
|
-
artifactName:
|
|
6056
|
-
artifactVersion:
|
|
6178
|
+
var artifactSnapshotSchema2 = z14.object({
|
|
6179
|
+
artifactName: z14.string(),
|
|
6180
|
+
artifactVersion: z14.string()
|
|
6057
6181
|
});
|
|
6058
|
-
var volumeVersionsSnapshotSchema2 =
|
|
6059
|
-
versions:
|
|
6182
|
+
var volumeVersionsSnapshotSchema2 = z14.object({
|
|
6183
|
+
versions: z14.record(z14.string(), z14.string())
|
|
6060
6184
|
});
|
|
6061
|
-
var checkpointResponseSchema =
|
|
6062
|
-
id:
|
|
6063
|
-
runId:
|
|
6064
|
-
conversationId:
|
|
6185
|
+
var checkpointResponseSchema = z14.object({
|
|
6186
|
+
id: z14.string(),
|
|
6187
|
+
runId: z14.string(),
|
|
6188
|
+
conversationId: z14.string(),
|
|
6065
6189
|
agentComposeSnapshot: agentComposeSnapshotSchema,
|
|
6066
6190
|
artifactSnapshot: artifactSnapshotSchema2.nullable(),
|
|
6067
6191
|
volumeVersionsSnapshot: volumeVersionsSnapshotSchema2.nullable(),
|
|
6068
|
-
createdAt:
|
|
6192
|
+
createdAt: z14.string()
|
|
6069
6193
|
});
|
|
6070
|
-
var sessionsByIdContract =
|
|
6194
|
+
var sessionsByIdContract = c10.router({
|
|
6071
6195
|
/**
|
|
6072
6196
|
* GET /api/agent/sessions/:id
|
|
6073
6197
|
* Get session by ID
|
|
@@ -6075,8 +6199,8 @@ var sessionsByIdContract = c9.router({
|
|
|
6075
6199
|
getById: {
|
|
6076
6200
|
method: "GET",
|
|
6077
6201
|
path: "/api/agent/sessions/:id",
|
|
6078
|
-
pathParams:
|
|
6079
|
-
id:
|
|
6202
|
+
pathParams: z14.object({
|
|
6203
|
+
id: z14.string().min(1, "Session ID is required")
|
|
6080
6204
|
}),
|
|
6081
6205
|
responses: {
|
|
6082
6206
|
200: sessionResponseSchema,
|
|
@@ -6087,7 +6211,7 @@ var sessionsByIdContract = c9.router({
|
|
|
6087
6211
|
summary: "Get session by ID"
|
|
6088
6212
|
}
|
|
6089
6213
|
});
|
|
6090
|
-
var checkpointsByIdContract =
|
|
6214
|
+
var checkpointsByIdContract = c10.router({
|
|
6091
6215
|
/**
|
|
6092
6216
|
* GET /api/agent/checkpoints/:id
|
|
6093
6217
|
* Get checkpoint by ID
|
|
@@ -6095,8 +6219,8 @@ var checkpointsByIdContract = c9.router({
|
|
|
6095
6219
|
getById: {
|
|
6096
6220
|
method: "GET",
|
|
6097
6221
|
path: "/api/agent/checkpoints/:id",
|
|
6098
|
-
pathParams:
|
|
6099
|
-
id:
|
|
6222
|
+
pathParams: z14.object({
|
|
6223
|
+
id: z14.string().min(1, "Checkpoint ID is required")
|
|
6100
6224
|
}),
|
|
6101
6225
|
responses: {
|
|
6102
6226
|
200: checkpointResponseSchema,
|
|
@@ -6108,108 +6232,6 @@ var checkpointsByIdContract = c9.router({
|
|
|
6108
6232
|
}
|
|
6109
6233
|
});
|
|
6110
6234
|
|
|
6111
|
-
// ../../packages/core/src/contracts/runners.ts
|
|
6112
|
-
import { z as z14 } from "zod";
|
|
6113
|
-
var c10 = initContract();
|
|
6114
|
-
var runnerGroupSchema = z14.string().regex(
|
|
6115
|
-
/^[a-z0-9-]+\/[a-z0-9-]+$/,
|
|
6116
|
-
"Runner group must be in scope/name format (e.g., acme/production)"
|
|
6117
|
-
);
|
|
6118
|
-
var jobSchema = z14.object({
|
|
6119
|
-
runId: z14.string().uuid(),
|
|
6120
|
-
prompt: z14.string(),
|
|
6121
|
-
agentComposeVersionId: z14.string(),
|
|
6122
|
-
vars: z14.record(z14.string(), z14.string()).nullable(),
|
|
6123
|
-
secretNames: z14.array(z14.string()).nullable(),
|
|
6124
|
-
checkpointId: z14.string().uuid().nullable()
|
|
6125
|
-
});
|
|
6126
|
-
var runnersPollContract = c10.router({
|
|
6127
|
-
poll: {
|
|
6128
|
-
method: "POST",
|
|
6129
|
-
path: "/api/runners/poll",
|
|
6130
|
-
body: z14.object({
|
|
6131
|
-
group: runnerGroupSchema
|
|
6132
|
-
}),
|
|
6133
|
-
responses: {
|
|
6134
|
-
200: z14.object({
|
|
6135
|
-
job: jobSchema.nullable()
|
|
6136
|
-
}),
|
|
6137
|
-
400: apiErrorSchema,
|
|
6138
|
-
401: apiErrorSchema,
|
|
6139
|
-
500: apiErrorSchema
|
|
6140
|
-
},
|
|
6141
|
-
summary: "Poll for pending jobs (long-polling with 30s timeout)"
|
|
6142
|
-
}
|
|
6143
|
-
});
|
|
6144
|
-
var storageEntrySchema = z14.object({
|
|
6145
|
-
mountPath: z14.string(),
|
|
6146
|
-
archiveUrl: z14.string().nullable()
|
|
6147
|
-
});
|
|
6148
|
-
var artifactEntrySchema = z14.object({
|
|
6149
|
-
mountPath: z14.string(),
|
|
6150
|
-
archiveUrl: z14.string().nullable(),
|
|
6151
|
-
vasStorageName: z14.string(),
|
|
6152
|
-
vasVersionId: z14.string()
|
|
6153
|
-
});
|
|
6154
|
-
var storageManifestSchema = z14.object({
|
|
6155
|
-
storages: z14.array(storageEntrySchema),
|
|
6156
|
-
artifact: artifactEntrySchema.nullable()
|
|
6157
|
-
});
|
|
6158
|
-
var resumeSessionSchema = z14.object({
|
|
6159
|
-
sessionId: z14.string(),
|
|
6160
|
-
sessionHistory: z14.string()
|
|
6161
|
-
});
|
|
6162
|
-
var storedExecutionContextSchema = z14.object({
|
|
6163
|
-
workingDir: z14.string(),
|
|
6164
|
-
storageManifest: storageManifestSchema.nullable(),
|
|
6165
|
-
environment: z14.record(z14.string(), z14.string()).nullable(),
|
|
6166
|
-
resumeSession: resumeSessionSchema.nullable(),
|
|
6167
|
-
encryptedSecrets: z14.string().nullable(),
|
|
6168
|
-
// AES-256-GCM encrypted secrets
|
|
6169
|
-
cliAgentType: z14.string(),
|
|
6170
|
-
experimentalNetworkSecurity: z14.boolean().optional()
|
|
6171
|
-
});
|
|
6172
|
-
var executionContextSchema = z14.object({
|
|
6173
|
-
runId: z14.string().uuid(),
|
|
6174
|
-
prompt: z14.string(),
|
|
6175
|
-
agentComposeVersionId: z14.string(),
|
|
6176
|
-
vars: z14.record(z14.string(), z14.string()).nullable(),
|
|
6177
|
-
secretNames: z14.array(z14.string()).nullable(),
|
|
6178
|
-
checkpointId: z14.string().uuid().nullable(),
|
|
6179
|
-
sandboxToken: z14.string(),
|
|
6180
|
-
// New fields for E2B parity:
|
|
6181
|
-
workingDir: z14.string(),
|
|
6182
|
-
storageManifest: storageManifestSchema.nullable(),
|
|
6183
|
-
environment: z14.record(z14.string(), z14.string()).nullable(),
|
|
6184
|
-
resumeSession: resumeSessionSchema.nullable(),
|
|
6185
|
-
secretValues: z14.array(z14.string()).nullable(),
|
|
6186
|
-
cliAgentType: z14.string(),
|
|
6187
|
-
// Network security mode flag
|
|
6188
|
-
experimentalNetworkSecurity: z14.boolean().optional()
|
|
6189
|
-
});
|
|
6190
|
-
var runnersJobClaimContract = c10.router({
|
|
6191
|
-
claim: {
|
|
6192
|
-
method: "POST",
|
|
6193
|
-
path: "/api/runners/jobs/:id/claim",
|
|
6194
|
-
pathParams: z14.object({
|
|
6195
|
-
id: z14.string().uuid()
|
|
6196
|
-
}),
|
|
6197
|
-
body: z14.object({}),
|
|
6198
|
-
responses: {
|
|
6199
|
-
200: executionContextSchema,
|
|
6200
|
-
400: apiErrorSchema,
|
|
6201
|
-
401: apiErrorSchema,
|
|
6202
|
-
403: apiErrorSchema,
|
|
6203
|
-
// Job does not belong to user
|
|
6204
|
-
404: apiErrorSchema,
|
|
6205
|
-
409: apiErrorSchema,
|
|
6206
|
-
// Already claimed
|
|
6207
|
-
500: apiErrorSchema
|
|
6208
|
-
},
|
|
6209
|
-
summary: "Claim a pending job for execution"
|
|
6210
|
-
}
|
|
6211
|
-
});
|
|
6212
|
-
|
|
6213
6235
|
// ../../packages/core/src/contracts/public/common.ts
|
|
6214
6236
|
import { z as z15 } from "zod";
|
|
6215
6237
|
var publicApiErrorTypeSchema = z15.enum([
|
|
@@ -6285,18 +6307,21 @@ var updateAgentRequestSchema = z16.object({
|
|
|
6285
6307
|
config: z16.unknown()
|
|
6286
6308
|
// New agent configuration (creates new version)
|
|
6287
6309
|
});
|
|
6310
|
+
var agentListQuerySchema = listQuerySchema.extend({
|
|
6311
|
+
name: z16.string().optional()
|
|
6312
|
+
});
|
|
6288
6313
|
var publicAgentsListContract = c11.router({
|
|
6289
6314
|
list: {
|
|
6290
6315
|
method: "GET",
|
|
6291
6316
|
path: "/v1/agents",
|
|
6292
|
-
query:
|
|
6317
|
+
query: agentListQuerySchema,
|
|
6293
6318
|
responses: {
|
|
6294
6319
|
200: paginatedAgentsSchema,
|
|
6295
6320
|
401: publicApiErrorSchema,
|
|
6296
6321
|
500: publicApiErrorSchema
|
|
6297
6322
|
},
|
|
6298
6323
|
summary: "List agents",
|
|
6299
|
-
description: "List all agents in the current scope with pagination"
|
|
6324
|
+
description: "List all agents in the current scope with pagination. Use the `name` query parameter to filter by agent name."
|
|
6300
6325
|
},
|
|
6301
6326
|
create: {
|
|
6302
6327
|
method: "POST",
|
|
@@ -9551,14 +9576,21 @@ var VMRegistry = class {
|
|
|
9551
9576
|
/**
|
|
9552
9577
|
* Register a VM with its IP address
|
|
9553
9578
|
*/
|
|
9554
|
-
register(vmIp, runId, sandboxToken) {
|
|
9579
|
+
register(vmIp, runId, sandboxToken, options) {
|
|
9555
9580
|
this.data.vms[vmIp] = {
|
|
9556
9581
|
runId,
|
|
9557
9582
|
sandboxToken,
|
|
9558
|
-
registeredAt: Date.now()
|
|
9583
|
+
registeredAt: Date.now(),
|
|
9584
|
+
firewallRules: options?.firewallRules,
|
|
9585
|
+
mitmEnabled: options?.mitmEnabled,
|
|
9586
|
+
sealSecretsEnabled: options?.sealSecretsEnabled
|
|
9559
9587
|
};
|
|
9560
9588
|
this.save();
|
|
9561
|
-
|
|
9589
|
+
const firewallInfo = options?.firewallRules ? ` with ${options.firewallRules.length} firewall rules` : "";
|
|
9590
|
+
const mitmInfo = options?.mitmEnabled ? ", MITM enabled" : "";
|
|
9591
|
+
console.log(
|
|
9592
|
+
`[VMRegistry] Registered VM ${vmIp} for run ${runId}${firewallInfo}${mitmInfo}`
|
|
9593
|
+
);
|
|
9562
9594
|
}
|
|
9563
9595
|
/**
|
|
9564
9596
|
* Unregister a VM by IP address
|
|
@@ -9624,16 +9656,19 @@ mitmproxy addon for VM0 runner-level network security mode.
|
|
|
9624
9656
|
|
|
9625
9657
|
This addon runs on the runner HOST (not inside VMs) and:
|
|
9626
9658
|
1. Intercepts all HTTPS requests from VMs
|
|
9627
|
-
2. Looks up the source VM's runId from the VM registry
|
|
9628
|
-
3.
|
|
9629
|
-
4.
|
|
9630
|
-
5.
|
|
9659
|
+
2. Looks up the source VM's runId and firewall rules from the VM registry
|
|
9660
|
+
3. Evaluates firewall rules (first-match-wins) to ALLOW or DENY
|
|
9661
|
+
4. For MITM mode: Rewrites requests to go through VM0 Proxy endpoint
|
|
9662
|
+
5. For SNI-only mode: Passes through or blocks without decryption
|
|
9663
|
+
6. Logs network activity per-run to JSONL files
|
|
9631
9664
|
"""
|
|
9632
9665
|
import os
|
|
9633
9666
|
import json
|
|
9634
9667
|
import time
|
|
9635
9668
|
import urllib.parse
|
|
9636
|
-
|
|
9669
|
+
import ipaddress
|
|
9670
|
+
import socket
|
|
9671
|
+
from mitmproxy import http, ctx, tls
|
|
9637
9672
|
|
|
9638
9673
|
|
|
9639
9674
|
# VM0 Proxy configuration from environment
|
|
@@ -9716,12 +9751,189 @@ def get_original_url(flow: http.HTTPFlow) -> str:
|
|
|
9716
9751
|
return f"{scheme}://{host_with_port}{path}"
|
|
9717
9752
|
|
|
9718
9753
|
|
|
9719
|
-
|
|
9754
|
+
# ============================================================================
|
|
9755
|
+
# Firewall Rule Matching
|
|
9756
|
+
# ============================================================================
|
|
9757
|
+
|
|
9758
|
+
def match_domain(pattern: str, hostname: str) -> bool:
|
|
9759
|
+
"""
|
|
9760
|
+
Match hostname against domain pattern.
|
|
9761
|
+
Supports exact match and wildcard prefix (*.example.com).
|
|
9762
|
+
"""
|
|
9763
|
+
if not pattern or not hostname:
|
|
9764
|
+
return False
|
|
9765
|
+
|
|
9766
|
+
pattern = pattern.lower()
|
|
9767
|
+
hostname = hostname.lower()
|
|
9768
|
+
|
|
9769
|
+
if pattern.startswith("*."):
|
|
9770
|
+
# Wildcard: *.example.com matches sub.example.com, www.example.com
|
|
9771
|
+
# Also matches example.com itself (without subdomain)
|
|
9772
|
+
suffix = pattern[1:] # .example.com
|
|
9773
|
+
base = pattern[2:] # example.com
|
|
9774
|
+
return hostname.endswith(suffix) or hostname == base
|
|
9775
|
+
|
|
9776
|
+
return hostname == pattern
|
|
9777
|
+
|
|
9778
|
+
|
|
9779
|
+
def match_ip(cidr: str, ip_str: str) -> bool:
|
|
9720
9780
|
"""
|
|
9721
|
-
|
|
9781
|
+
Match IP address against CIDR range.
|
|
9782
|
+
Supports single IPs (1.2.3.4) and ranges (10.0.0.0/8).
|
|
9783
|
+
"""
|
|
9784
|
+
if not cidr or not ip_str:
|
|
9785
|
+
return False
|
|
9786
|
+
|
|
9787
|
+
try:
|
|
9788
|
+
# Parse CIDR (automatically handles single IPs as /32)
|
|
9789
|
+
if "/" not in cidr:
|
|
9790
|
+
cidr = f"{cidr}/32"
|
|
9791
|
+
network = ipaddress.ip_network(cidr, strict=False)
|
|
9792
|
+
ip = ipaddress.ip_address(ip_str)
|
|
9793
|
+
return ip in network
|
|
9794
|
+
except ValueError:
|
|
9795
|
+
return False
|
|
9796
|
+
|
|
9722
9797
|
|
|
9723
|
-
|
|
9724
|
-
|
|
9798
|
+
def resolve_hostname_to_ip(hostname: str) -> str | None:
|
|
9799
|
+
"""Resolve hostname to IP address for IP-based rule matching."""
|
|
9800
|
+
try:
|
|
9801
|
+
return socket.gethostbyname(hostname)
|
|
9802
|
+
except socket.gaierror:
|
|
9803
|
+
return None
|
|
9804
|
+
|
|
9805
|
+
|
|
9806
|
+
def evaluate_rules(rules: list, hostname: str, ip_str: str = None) -> tuple[str, str | None]:
|
|
9807
|
+
"""
|
|
9808
|
+
Evaluate firewall rules against hostname/IP.
|
|
9809
|
+
Returns (action, matched_rule_description).
|
|
9810
|
+
|
|
9811
|
+
Rule evaluation is first-match-wins (top to bottom).
|
|
9812
|
+
|
|
9813
|
+
Rule formats:
|
|
9814
|
+
- Domain/IP rule: { domain: "*.example.com", action: "ALLOW" }
|
|
9815
|
+
- Terminal rule: { final: "DENY" }
|
|
9816
|
+
"""
|
|
9817
|
+
if not rules:
|
|
9818
|
+
return ("ALLOW", None) # No rules = allow all
|
|
9819
|
+
|
|
9820
|
+
for rule in rules:
|
|
9821
|
+
# Final/terminal rule - value is the action
|
|
9822
|
+
final_action = rule.get("final")
|
|
9823
|
+
if final_action:
|
|
9824
|
+
return (final_action, "final")
|
|
9825
|
+
|
|
9826
|
+
# Domain rule
|
|
9827
|
+
domain = rule.get("domain")
|
|
9828
|
+
if domain and match_domain(domain, hostname):
|
|
9829
|
+
return (rule.get("action", "DENY"), f"domain:{domain}")
|
|
9830
|
+
|
|
9831
|
+
# IP rule
|
|
9832
|
+
ip_pattern = rule.get("ip")
|
|
9833
|
+
if ip_pattern:
|
|
9834
|
+
target_ip = ip_str
|
|
9835
|
+
if not target_ip:
|
|
9836
|
+
target_ip = resolve_hostname_to_ip(hostname)
|
|
9837
|
+
if target_ip and match_ip(ip_pattern, target_ip):
|
|
9838
|
+
return (rule.get("action", "DENY"), f"ip:{ip_pattern}")
|
|
9839
|
+
|
|
9840
|
+
# No rule matched - default deny (zero-trust)
|
|
9841
|
+
return ("DENY", "default")
|
|
9842
|
+
|
|
9843
|
+
|
|
9844
|
+
# ============================================================================
|
|
9845
|
+
# TLS ClientHello Handler (SNI-only mode)
|
|
9846
|
+
# ============================================================================
|
|
9847
|
+
|
|
9848
|
+
def tls_clienthello(data: tls.ClientHelloData) -> None:
|
|
9849
|
+
"""
|
|
9850
|
+
Handle TLS ClientHello for SNI-based filtering.
|
|
9851
|
+
This is called BEFORE TLS decryption, allowing SNI-only filtering.
|
|
9852
|
+
"""
|
|
9853
|
+
client_ip = data.context.client.peername[0] if data.context.client.peername else None
|
|
9854
|
+
if not client_ip:
|
|
9855
|
+
return
|
|
9856
|
+
|
|
9857
|
+
vm_info = get_vm_info(client_ip)
|
|
9858
|
+
if not vm_info:
|
|
9859
|
+
return # Not a registered VM, let it through
|
|
9860
|
+
|
|
9861
|
+
# If MITM is enabled, let the normal flow handle it
|
|
9862
|
+
if vm_info.get("mitmEnabled", False):
|
|
9863
|
+
return
|
|
9864
|
+
|
|
9865
|
+
# SNI-only mode: check rules based on SNI
|
|
9866
|
+
sni = data.context.client.sni
|
|
9867
|
+
run_id = vm_info.get("runId", "")
|
|
9868
|
+
rules = vm_info.get("firewallRules", [])
|
|
9869
|
+
|
|
9870
|
+
# Auto-allow VM0 API requests - the agent MUST be able to communicate with VM0
|
|
9871
|
+
if API_URL and sni:
|
|
9872
|
+
parsed_api = urllib.parse.urlparse(API_URL)
|
|
9873
|
+
api_hostname = parsed_api.hostname.lower() if parsed_api.hostname else ""
|
|
9874
|
+
sni_lower = sni.lower()
|
|
9875
|
+
if api_hostname and (sni_lower == api_hostname or sni_lower.endswith(f".{api_hostname}")):
|
|
9876
|
+
ctx.log.info(f"[{run_id}] SNI-only auto-allow VM0 API: {sni}")
|
|
9877
|
+
log_network_entry(run_id, {
|
|
9878
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
|
|
9879
|
+
"mode": "sni",
|
|
9880
|
+
"action": "ALLOW",
|
|
9881
|
+
"host": sni,
|
|
9882
|
+
"port": 443,
|
|
9883
|
+
"rule_matched": "vm0-api",
|
|
9884
|
+
})
|
|
9885
|
+
data.ignore_connection = True # Pass through without MITM
|
|
9886
|
+
return
|
|
9887
|
+
|
|
9888
|
+
if not sni:
|
|
9889
|
+
# No SNI, can't determine target - block for security
|
|
9890
|
+
ctx.log.warn(f"[{run_id}] SNI-only: No SNI in ClientHello, blocking")
|
|
9891
|
+
log_network_entry(run_id, {
|
|
9892
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
|
|
9893
|
+
"mode": "sni",
|
|
9894
|
+
"action": "DENY",
|
|
9895
|
+
"host": "",
|
|
9896
|
+
"port": 443,
|
|
9897
|
+
"rule_matched": "no-sni",
|
|
9898
|
+
})
|
|
9899
|
+
# Don't set ignore_connection - mitmproxy will attempt MITM handshake
|
|
9900
|
+
# Since VM doesn't have CA cert (SNI-only mode), TLS will fail immediately
|
|
9901
|
+
return
|
|
9902
|
+
|
|
9903
|
+
# Evaluate rules
|
|
9904
|
+
action, matched_rule = evaluate_rules(rules, sni)
|
|
9905
|
+
|
|
9906
|
+
# Log the connection
|
|
9907
|
+
log_network_entry(run_id, {
|
|
9908
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
|
|
9909
|
+
"mode": "sni",
|
|
9910
|
+
"action": action,
|
|
9911
|
+
"host": sni,
|
|
9912
|
+
"port": 443,
|
|
9913
|
+
"rule_matched": matched_rule,
|
|
9914
|
+
})
|
|
9915
|
+
|
|
9916
|
+
if action == "ALLOW":
|
|
9917
|
+
# Pass through without MITM - mitmproxy will relay without decryption
|
|
9918
|
+
ctx.log.info(f"[{run_id}] SNI-only ALLOW: {sni} (rule: {matched_rule})")
|
|
9919
|
+
data.ignore_connection = True
|
|
9920
|
+
else:
|
|
9921
|
+
# Block the connection by NOT setting ignore_connection
|
|
9922
|
+
# mitmproxy will attempt MITM handshake, but since VM doesn't have
|
|
9923
|
+
# our CA certificate installed (SNI-only mode), the TLS handshake
|
|
9924
|
+
# will fail immediately with a certificate error.
|
|
9925
|
+
ctx.log.warn(f"[{run_id}] SNI-only DENY: {sni} (rule: {matched_rule})")
|
|
9926
|
+
# Client will see: SSL certificate problem / certificate verify failed
|
|
9927
|
+
|
|
9928
|
+
|
|
9929
|
+
# ============================================================================
|
|
9930
|
+
# HTTP Request Handler (MITM mode)
|
|
9931
|
+
# ============================================================================
|
|
9932
|
+
|
|
9933
|
+
def request(flow: http.HTTPFlow) -> None:
|
|
9934
|
+
"""
|
|
9935
|
+
Intercept request and apply firewall rules.
|
|
9936
|
+
For MITM mode, rewrites allowed requests to VM0 Proxy.
|
|
9725
9937
|
"""
|
|
9726
9938
|
# Track request start time
|
|
9727
9939
|
request_start_times[flow.id] = time.time()
|
|
@@ -9738,16 +9950,52 @@ def request(flow: http.HTTPFlow) -> None:
|
|
|
9738
9950
|
|
|
9739
9951
|
if not vm_info:
|
|
9740
9952
|
# Not a registered VM, pass through without proxying
|
|
9741
|
-
# This allows non-VM traffic to work normally
|
|
9742
9953
|
ctx.log.info(f"No VM registration for {client_ip}, passing through")
|
|
9743
9954
|
return
|
|
9744
9955
|
|
|
9745
9956
|
run_id = vm_info.get("runId", "")
|
|
9746
9957
|
sandbox_token = vm_info.get("sandboxToken", "")
|
|
9958
|
+
mitm_enabled = vm_info.get("mitmEnabled", False)
|
|
9959
|
+
rules = vm_info.get("firewallRules", [])
|
|
9747
9960
|
|
|
9748
9961
|
# Store info for response handler
|
|
9749
9962
|
flow.metadata["vm_run_id"] = run_id
|
|
9750
9963
|
flow.metadata["vm_client_ip"] = client_ip
|
|
9964
|
+
flow.metadata["vm_mitm_enabled"] = mitm_enabled
|
|
9965
|
+
|
|
9966
|
+
# Get target hostname
|
|
9967
|
+
hostname = flow.request.pretty_host.lower()
|
|
9968
|
+
|
|
9969
|
+
# Auto-allow VM0 API requests - the agent MUST be able to communicate with VM0
|
|
9970
|
+
# This is checked before user firewall rules to ensure agent functionality
|
|
9971
|
+
if API_URL:
|
|
9972
|
+
parsed_api = urllib.parse.urlparse(API_URL)
|
|
9973
|
+
api_hostname = parsed_api.hostname.lower() if parsed_api.hostname else ""
|
|
9974
|
+
if api_hostname and (hostname == api_hostname or hostname.endswith(f".{api_hostname}")):
|
|
9975
|
+
ctx.log.info(f"[{run_id}] Auto-allow VM0 API: {hostname}")
|
|
9976
|
+
flow.metadata["firewall_action"] = "ALLOW"
|
|
9977
|
+
flow.metadata["firewall_rule"] = "vm0-api"
|
|
9978
|
+
# Continue to skip rewrite check below
|
|
9979
|
+
flow.metadata["original_url"] = get_original_url(flow)
|
|
9980
|
+
flow.metadata["skip_rewrite"] = True
|
|
9981
|
+
return
|
|
9982
|
+
|
|
9983
|
+
# Evaluate firewall rules
|
|
9984
|
+
action, matched_rule = evaluate_rules(rules, hostname)
|
|
9985
|
+
flow.metadata["firewall_action"] = action
|
|
9986
|
+
flow.metadata["firewall_rule"] = matched_rule
|
|
9987
|
+
|
|
9988
|
+
if action == "DENY":
|
|
9989
|
+
ctx.log.warn(f"[{run_id}] Firewall DENY: {hostname} (rule: {matched_rule})")
|
|
9990
|
+
# Kill the flow and return error response
|
|
9991
|
+
flow.response = http.Response.make(
|
|
9992
|
+
403,
|
|
9993
|
+
b"Blocked by firewall",
|
|
9994
|
+
{"Content-Type": "text/plain"}
|
|
9995
|
+
)
|
|
9996
|
+
return
|
|
9997
|
+
|
|
9998
|
+
# Request is ALLOWED - proceed with processing
|
|
9751
9999
|
|
|
9752
10000
|
# Skip if no API URL configured
|
|
9753
10001
|
if not API_URL:
|
|
@@ -9760,9 +10008,8 @@ def request(flow: http.HTTPFlow) -> None:
|
|
|
9760
10008
|
flow.metadata["skip_rewrite"] = True
|
|
9761
10009
|
return
|
|
9762
10010
|
|
|
9763
|
-
# Skip rewriting requests to trusted domains (S3, etc.)
|
|
10011
|
+
# Skip rewriting requests to trusted storage domains (S3, etc.)
|
|
9764
10012
|
# S3 presigned URLs have signatures that break when proxied
|
|
9765
|
-
host = flow.request.pretty_host.lower()
|
|
9766
10013
|
TRUSTED_DOMAINS = [
|
|
9767
10014
|
".s3.amazonaws.com",
|
|
9768
10015
|
".s3-", # Regional S3 endpoints like s3-us-west-2.amazonaws.com
|
|
@@ -9771,8 +10018,8 @@ def request(flow: http.HTTPFlow) -> None:
|
|
|
9771
10018
|
".storage.googleapis.com",
|
|
9772
10019
|
]
|
|
9773
10020
|
for domain in TRUSTED_DOMAINS:
|
|
9774
|
-
if domain in
|
|
9775
|
-
ctx.log.info(f"[{run_id}] Skipping trusted domain: {
|
|
10021
|
+
if domain in hostname or hostname.endswith(domain.lstrip(".")):
|
|
10022
|
+
ctx.log.info(f"[{run_id}] Skipping trusted storage domain: {hostname}")
|
|
9776
10023
|
flow.metadata["original_url"] = get_original_url(flow)
|
|
9777
10024
|
flow.metadata["skip_rewrite"] = True
|
|
9778
10025
|
return
|
|
@@ -9781,7 +10028,13 @@ def request(flow: http.HTTPFlow) -> None:
|
|
|
9781
10028
|
original_url = get_original_url(flow)
|
|
9782
10029
|
flow.metadata["original_url"] = original_url
|
|
9783
10030
|
|
|
9784
|
-
|
|
10031
|
+
# If MITM is not enabled, just allow the request through without rewriting
|
|
10032
|
+
if not mitm_enabled:
|
|
10033
|
+
ctx.log.info(f"[{run_id}] Firewall ALLOW (no MITM): {hostname}")
|
|
10034
|
+
return
|
|
10035
|
+
|
|
10036
|
+
# MITM mode: rewrite to VM0 Proxy
|
|
10037
|
+
ctx.log.info(f"[{run_id}] Proxying via MITM: {original_url}")
|
|
9785
10038
|
|
|
9786
10039
|
# Parse proxy URL
|
|
9787
10040
|
parsed = urllib.parse.urlparse(PROXY_URL)
|
|
@@ -9822,34 +10075,58 @@ def response(flow: http.HTTPFlow) -> None:
|
|
|
9822
10075
|
# Get stored info
|
|
9823
10076
|
run_id = flow.metadata.get("vm_run_id", "")
|
|
9824
10077
|
original_url = flow.metadata.get("original_url", flow.request.pretty_url)
|
|
10078
|
+
mitm_enabled = flow.metadata.get("vm_mitm_enabled", False)
|
|
10079
|
+
firewall_action = flow.metadata.get("firewall_action", "ALLOW")
|
|
10080
|
+
firewall_rule = flow.metadata.get("firewall_rule")
|
|
9825
10081
|
|
|
9826
10082
|
# Calculate sizes
|
|
9827
10083
|
request_size = len(flow.request.content) if flow.request.content else 0
|
|
9828
10084
|
response_size = len(flow.response.content) if flow.response and flow.response.content else 0
|
|
9829
10085
|
status_code = flow.response.status_code if flow.response else 0
|
|
9830
10086
|
|
|
10087
|
+
# Parse URL for host
|
|
10088
|
+
try:
|
|
10089
|
+
parsed_url = urllib.parse.urlparse(original_url)
|
|
10090
|
+
host = parsed_url.hostname or flow.request.pretty_host
|
|
10091
|
+
port = parsed_url.port or (443 if parsed_url.scheme == "https" else 80)
|
|
10092
|
+
except:
|
|
10093
|
+
host = flow.request.pretty_host
|
|
10094
|
+
port = flow.request.port
|
|
10095
|
+
|
|
9831
10096
|
# Log network entry for this run
|
|
9832
10097
|
if run_id:
|
|
9833
10098
|
log_entry = {
|
|
9834
10099
|
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
|
|
9835
|
-
"
|
|
9836
|
-
"
|
|
9837
|
-
"
|
|
9838
|
-
"
|
|
9839
|
-
"
|
|
9840
|
-
"response_size": response_size,
|
|
10100
|
+
"mode": "mitm" if mitm_enabled else "filter",
|
|
10101
|
+
"action": firewall_action,
|
|
10102
|
+
"host": host,
|
|
10103
|
+
"port": port,
|
|
10104
|
+
"rule_matched": firewall_rule,
|
|
9841
10105
|
}
|
|
10106
|
+
|
|
10107
|
+
# Add HTTP details only in MITM mode
|
|
10108
|
+
if mitm_enabled:
|
|
10109
|
+
log_entry.update({
|
|
10110
|
+
"method": flow.request.method,
|
|
10111
|
+
"path": flow.request.path.split("?")[0], # Path without query
|
|
10112
|
+
"url": original_url,
|
|
10113
|
+
"status": status_code,
|
|
10114
|
+
"latency_ms": latency_ms,
|
|
10115
|
+
"request_size": request_size,
|
|
10116
|
+
"response_size": response_size,
|
|
10117
|
+
})
|
|
10118
|
+
|
|
9842
10119
|
log_network_entry(run_id, log_entry)
|
|
9843
10120
|
|
|
9844
10121
|
# Log errors to mitmproxy console
|
|
9845
10122
|
if flow.response and flow.response.status_code >= 400:
|
|
9846
10123
|
ctx.log.warn(
|
|
9847
|
-
f"[{run_id}]
|
|
10124
|
+
f"[{run_id}] Response {flow.response.status_code}: {original_url}"
|
|
9848
10125
|
)
|
|
9849
10126
|
|
|
9850
10127
|
|
|
9851
10128
|
# mitmproxy addon registration
|
|
9852
|
-
addons = [request, response]
|
|
10129
|
+
addons = [tls_clienthello, request, response]
|
|
9853
10130
|
`;
|
|
9854
10131
|
|
|
9855
10132
|
// src/lib/proxy/proxy-manager.ts
|
|
@@ -10087,7 +10364,7 @@ function buildEnvironmentVariables(context, apiUrl) {
|
|
|
10087
10364
|
envVars[key] = value;
|
|
10088
10365
|
}
|
|
10089
10366
|
}
|
|
10090
|
-
if (context.
|
|
10367
|
+
if (context.experimentalFirewall?.experimental_mitm) {
|
|
10091
10368
|
envVars.NODE_EXTRA_CA_CERTS = "/usr/local/share/ca-certificates/vm0-proxy-ca.crt";
|
|
10092
10369
|
}
|
|
10093
10370
|
return envVars;
|
|
@@ -10261,13 +10538,22 @@ async function executeJob(context, config) {
|
|
|
10261
10538
|
console.log(`[Executor] Waiting for SSH on ${guestIp}...`);
|
|
10262
10539
|
await ssh.waitUntilReachable(12e4, 2e3);
|
|
10263
10540
|
console.log(`[Executor] SSH ready on ${guestIp}`);
|
|
10264
|
-
|
|
10541
|
+
const firewallConfig = context.experimentalFirewall;
|
|
10542
|
+
if (firewallConfig?.enabled) {
|
|
10543
|
+
const mitmEnabled = firewallConfig.experimental_mitm ?? false;
|
|
10544
|
+
const sealSecretsEnabled = firewallConfig.experimental_seal_secrets ?? false;
|
|
10265
10545
|
console.log(
|
|
10266
|
-
`[Executor] Setting up network security
|
|
10546
|
+
`[Executor] Setting up network security for VM ${guestIp} (mitm=${mitmEnabled}, sealSecrets=${sealSecretsEnabled})`
|
|
10267
10547
|
);
|
|
10268
10548
|
await setupVMProxyRules(guestIp, config.proxy.port);
|
|
10269
|
-
getVMRegistry().register(guestIp, context.runId, context.sandboxToken
|
|
10270
|
-
|
|
10549
|
+
getVMRegistry().register(guestIp, context.runId, context.sandboxToken, {
|
|
10550
|
+
firewallRules: firewallConfig?.rules,
|
|
10551
|
+
mitmEnabled,
|
|
10552
|
+
sealSecretsEnabled
|
|
10553
|
+
});
|
|
10554
|
+
if (mitmEnabled) {
|
|
10555
|
+
await installProxyCA(ssh);
|
|
10556
|
+
}
|
|
10271
10557
|
}
|
|
10272
10558
|
console.log(`[Executor] Configuring DNS...`);
|
|
10273
10559
|
await configureDNS(ssh);
|
|
@@ -10341,7 +10627,7 @@ async function executeJob(context, config) {
|
|
|
10341
10627
|
error: errorMsg
|
|
10342
10628
|
};
|
|
10343
10629
|
} finally {
|
|
10344
|
-
if (context.
|
|
10630
|
+
if (context.experimentalFirewall?.enabled && guestIp) {
|
|
10345
10631
|
console.log(`[Executor] Cleaning up network security for VM ${guestIp}`);
|
|
10346
10632
|
try {
|
|
10347
10633
|
await removeVMProxyRules(guestIp, config.proxy.port);
|
|
@@ -10438,7 +10724,7 @@ var startCommand = new Command("start").description("Start the runner").option("
|
|
|
10438
10724
|
`Network proxy not available: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
10439
10725
|
);
|
|
10440
10726
|
console.warn(
|
|
10441
|
-
"Jobs with
|
|
10727
|
+
"Jobs with experimentalFirewall enabled will run without network interception"
|
|
10442
10728
|
);
|
|
10443
10729
|
}
|
|
10444
10730
|
const statusFilePath = join(dirname(options.config), "status.json");
|
|
@@ -10587,7 +10873,7 @@ var statusCommand = new Command2("status").description("Check runner connectivit
|
|
|
10587
10873
|
});
|
|
10588
10874
|
|
|
10589
10875
|
// src/index.ts
|
|
10590
|
-
var version = true ? "2.
|
|
10876
|
+
var version = true ? "2.4.0" : "0.1.0";
|
|
10591
10877
|
program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
|
|
10592
10878
|
program.addCommand(startCommand);
|
|
10593
10879
|
program.addCommand(statusCommand);
|