@evident-ai/runner-cdk 0.1.1-dev.da70cd4 → 3.4.1-dev.0ef5061
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -20
- package/dist/controller-lambda/handler.js +50529 -0
- package/dist/evident-scale-to-zero-construct.d.ts +16 -4
- package/dist/evident-scale-to-zero-construct.js +19 -14
- package/dist/image-version-reporter-lambda/handler.js +129 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +14 -1
- package/dist/microvm/constants.d.ts +7 -0
- package/dist/microvm/constants.js +34 -0
- package/dist/microvm/construct.d.ts +105 -0
- package/dist/microvm/construct.js +283 -0
- package/dist/microvm/controller/doorbell.d.ts +73 -0
- package/dist/microvm/controller/doorbell.js +107 -0
- package/dist/microvm/controller/handle-doorbell.d.ts +27 -0
- package/dist/microvm/controller/handle-doorbell.js +483 -0
- package/dist/microvm/controller/microvm-client.d.ts +81 -0
- package/dist/microvm/controller/microvm-client.js +7 -0
- package/dist/microvm/controller/shape-catalogue.d.ts +64 -0
- package/dist/microvm/controller/shape-catalogue.js +108 -0
- package/dist/microvm/controller/throttle-retry.d.ts +11 -0
- package/dist/microvm/controller/throttle-retry.js +27 -0
- package/dist/microvm/image/stage-context.d.ts +33 -0
- package/dist/microvm/image/stage-context.js +148 -0
- package/dist/microvm/image-version-reporter/construct.d.ts +35 -0
- package/dist/microvm/image-version-reporter/construct.js +91 -0
- package/dist/microvm/image-version-reporter/handler.d.ts +26 -0
- package/dist/microvm/image-version-reporter/handler.js +104 -0
- package/dist/microvm/shapes.d.ts +72 -0
- package/dist/microvm/shapes.js +93 -0
- package/dist/microvm-image-context/Dockerfile +227 -0
- package/dist/microvm-image-context/hook-server.js +286 -0
- package/dist/microvm-image-context/hooks/common.sh +957 -0
- package/dist/microvm-image-context/hooks/resume +78 -0
- package/dist/microvm-image-context/hooks/run +94 -0
- package/dist/microvm-image-context/hooks/suspend +22 -0
- package/dist/microvm-image-context/hooks/terminate +37 -0
- package/dist/waker/construct.js +1 -1
- package/package.json +15 -7
|
@@ -61,13 +61,25 @@ export type EvidentScaleToZeroConstructProps = {
|
|
|
61
61
|
replicaBucket: s3.IBucket;
|
|
62
62
|
image: ecs.ContainerImage;
|
|
63
63
|
/**
|
|
64
|
-
* Container secrets.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
64
|
+
* Container secrets. `availableSecretKeys` are injected by name; EVIDENT_AGENT_KEY
|
|
65
|
+
* and GH_TOKEN remain available to external adopters that do not enumerate keys.
|
|
66
|
+
*
|
|
67
|
+
* `agentSecret` always supplies EVIDENT_AGENT_KEY. When `capabilitySecret` is
|
|
68
|
+
* ALSO given (#1868 WI-2), every capability key (GH_TOKEN included) is injected
|
|
69
|
+
* from THAT secret instead, and `availableSecretKeys` is ignored — the two
|
|
70
|
+
* deploy targets (this one and the MicroVM stack) then read the same
|
|
71
|
+
* capability keys from the same shared secret rather than each carrying its
|
|
72
|
+
* own copy. When `capabilitySecret` is absent, behavior is unchanged: GH_TOKEN
|
|
73
|
+
* plus every `availableSecretKeys` entry, all from `agentSecret` — an external
|
|
74
|
+
* adopter passing only `agentSecret`/`availableSecretKeys` is unaffected.
|
|
67
75
|
*/
|
|
68
76
|
agentSecret: secretsmanager.ISecret;
|
|
69
|
-
/** Key names present in the agent secret
|
|
77
|
+
/** Key names present in the agent secret. Every listed key is injected into the container. */
|
|
70
78
|
availableSecretKeys: Set<string>;
|
|
79
|
+
/** The shared capability secret (#1868 WI-2). See `agentSecret`'s doc above. */
|
|
80
|
+
capabilitySecret?: secretsmanager.ISecret;
|
|
81
|
+
/** Key names present in `capabilitySecret`. Ignored when `capabilitySecret` is absent. */
|
|
82
|
+
capabilityKeys?: Set<string>;
|
|
71
83
|
/** Waker secret (EVIDENT_WAKE_SECRET), consumed by the waker at runtime. */
|
|
72
84
|
wakerSecret: secretsmanager.ISecret;
|
|
73
85
|
};
|
|
@@ -61,7 +61,7 @@ class EvidentScaleToZeroConstruct extends constructs_1.Construct {
|
|
|
61
61
|
service;
|
|
62
62
|
constructor(scope, id, props) {
|
|
63
63
|
super(scope, id);
|
|
64
|
-
const { agentName, evidentAgentId, gitRepo, gitBranch, idleTimeoutSeconds, cpu, memoryLimitMiB, resourcePrefix = DEFAULT_RESOURCE_PREFIX, envName, evidentApiUrl, evidentTunnelUrl, extraEnvironment, cluster, securityGroup, taskRole, logGroup, replicaBucket, image, agentSecret, availableSecretKeys, wakerSecret, } = props;
|
|
64
|
+
const { agentName, evidentAgentId, gitRepo, gitBranch, idleTimeoutSeconds, cpu, memoryLimitMiB, resourcePrefix = DEFAULT_RESOURCE_PREFIX, envName, evidentApiUrl, evidentTunnelUrl, extraEnvironment, cluster, securityGroup, taskRole, logGroup, replicaBucket, image, agentSecret, availableSecretKeys, capabilitySecret, capabilityKeys, wakerSecret, } = props;
|
|
65
65
|
this.replicaPrefix = `agents/${evidentAgentId}`;
|
|
66
66
|
// A plain STRING (not service.serviceName) so the container env is static and
|
|
67
67
|
// has no construct-ordering dependency on the service.
|
|
@@ -101,7 +101,7 @@ class EvidentScaleToZeroConstruct extends constructs_1.Construct {
|
|
|
101
101
|
// --endpoint / --tunnel). The agent is resolved from EVIDENT_AGENT_KEY.
|
|
102
102
|
EVIDENT_API_URL: evidentApiUrl,
|
|
103
103
|
EVIDENT_TUNNEL_URL: evidentTunnelUrl,
|
|
104
|
-
// Litestream replica target (read by
|
|
104
|
+
// Litestream replica target (read by runner/synchroniser, which
|
|
105
105
|
// generates /etc/evident/litestream.yml at boot).
|
|
106
106
|
LITESTREAM_BUCKET: replicaBucket.bucketName,
|
|
107
107
|
LITESTREAM_PREFIX: this.replicaPrefix,
|
|
@@ -115,10 +115,9 @@ class EvidentScaleToZeroConstruct extends constructs_1.Construct {
|
|
|
115
115
|
// window (protected/active sessions are never touched). Tightened from 7d
|
|
116
116
|
// to 24h per #537: at 7d, opencode.db was observed growing ~11x (77 MB ->
|
|
117
117
|
// 849 MB) in ~24h, so 7d was far too permissive at the observed growth
|
|
118
|
-
// rate. 24h is
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
// interval and never touches a protected/active session.
|
|
118
|
+
// rate. 24h is the tighter mitigation that came out of that (see also the
|
|
119
|
+
// OPENCODE_VERSION pin above). Sweep runs on the default 1h interval and
|
|
120
|
+
// never touches a protected/active session.
|
|
122
121
|
EVIDENT_SESSION_CLEANUP_MAX_AGE: '24h',
|
|
123
122
|
CLUSTER: cluster.clusterName,
|
|
124
123
|
SERVICE: serviceName,
|
|
@@ -128,16 +127,22 @@ class EvidentScaleToZeroConstruct extends constructs_1.Construct {
|
|
|
128
127
|
...extraEnvironment,
|
|
129
128
|
};
|
|
130
129
|
const secrets = {
|
|
130
|
+
// Identifies the runner to Evident. Always agentSecret — capabilitySecret
|
|
131
|
+
// never carries this key (#1868 WI-2: the two are a deliberate split, not
|
|
132
|
+
// a duplication of the same data).
|
|
131
133
|
EVIDENT_AGENT_KEY: ecs.Secret.fromSecretsManager(agentSecret, 'EVIDENT_AGENT_KEY'),
|
|
132
|
-
GH_TOKEN: ecs.Secret.fromSecretsManager(agentSecret, 'GH_TOKEN'),
|
|
133
134
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
if (capabilitySecret !== undefined) {
|
|
136
|
+
for (const key of capabilityKeys ?? new Set()) {
|
|
137
|
+
secrets[key] = ecs.Secret.fromSecretsManager(capabilitySecret, key);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Legacy shape, unchanged: GH_TOKEN (required to clone this construct's
|
|
142
|
+
// workspace at boot) plus every availableSecretKeys entry, all from
|
|
143
|
+
// agentSecret — what every external adopter still gets.
|
|
144
|
+
secrets.GH_TOKEN = ecs.Secret.fromSecretsManager(agentSecret, 'GH_TOKEN');
|
|
145
|
+
for (const key of availableSecretKeys) {
|
|
141
146
|
secrets[key] = ecs.Secret.fromSecretsManager(agentSecret, key);
|
|
142
147
|
}
|
|
143
148
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/microvm/image-version-reporter/handler.ts
|
|
21
|
+
var handler_exports = {};
|
|
22
|
+
__export(handler_exports, {
|
|
23
|
+
handleImageVersionReport: () => handleImageVersionReport,
|
|
24
|
+
handler: () => handler
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(handler_exports);
|
|
27
|
+
var import_node_crypto = require("node:crypto");
|
|
28
|
+
var import_client_secrets_manager = require("@aws-sdk/client-secrets-manager");
|
|
29
|
+
var PHYSICAL_RESOURCE_ID = "evident-image-version-report";
|
|
30
|
+
var REPORT_TIMEOUT_MS = 5e3;
|
|
31
|
+
var secrets = new import_client_secrets_manager.SecretsManagerClient({});
|
|
32
|
+
async function fetchDoorbellSecret(secretArn, secretKey) {
|
|
33
|
+
const { SecretString } = await secrets.send(new import_client_secrets_manager.GetSecretValueCommand({ SecretId: secretArn }));
|
|
34
|
+
if (!SecretString) {
|
|
35
|
+
throw new Error(`doorbell secret ${secretArn} has no SecretString`);
|
|
36
|
+
}
|
|
37
|
+
const parsed = JSON.parse(SecretString);
|
|
38
|
+
const value = parsed !== null && typeof parsed === "object" ? parsed[secretKey] : void 0;
|
|
39
|
+
if (typeof value !== "string" || value === "") {
|
|
40
|
+
throw new Error(`doorbell secret ${secretArn} is missing a non-empty '${secretKey}' field`);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function requireEnv(name) {
|
|
45
|
+
const value = process.env[name];
|
|
46
|
+
if (!value) {
|
|
47
|
+
throw new Error(`missing required env var ${name}`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function readImageVersions(value) {
|
|
52
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
53
|
+
throw new Error("imageVersions must be an object");
|
|
54
|
+
}
|
|
55
|
+
return Object.entries(value).map(([shape, imageVersion]) => {
|
|
56
|
+
if (typeof imageVersion !== "string") {
|
|
57
|
+
throw new Error(`imageVersions.${shape} must be a string`);
|
|
58
|
+
}
|
|
59
|
+
return { shape, image_version: imageVersion };
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function response() {
|
|
63
|
+
return { PhysicalResourceId: PHYSICAL_RESOURCE_ID };
|
|
64
|
+
}
|
|
65
|
+
var runtimeDependencies = {
|
|
66
|
+
getSecret: fetchDoorbellSecret,
|
|
67
|
+
fetch: globalThis.fetch
|
|
68
|
+
};
|
|
69
|
+
async function handleImageVersionReport(event, getConfig, dependencies = runtimeDependencies) {
|
|
70
|
+
if (event.RequestType === "Delete") {
|
|
71
|
+
return response();
|
|
72
|
+
}
|
|
73
|
+
let runnerId = "unknown";
|
|
74
|
+
let versions = [];
|
|
75
|
+
let responseStatus;
|
|
76
|
+
try {
|
|
77
|
+
versions = readImageVersions(event.ResourceProperties?.imageVersions);
|
|
78
|
+
const config = getConfig();
|
|
79
|
+
runnerId = config.evidentRunnerId;
|
|
80
|
+
const secret = await dependencies.getSecret(config.doorbellSecretArn, config.doorbellSecretKey);
|
|
81
|
+
const body = JSON.stringify({
|
|
82
|
+
type: "runner.microvm_image_versions_reported",
|
|
83
|
+
versions
|
|
84
|
+
});
|
|
85
|
+
const signature = (0, import_node_crypto.createHmac)("sha256", secret).update(body).digest("hex");
|
|
86
|
+
const url = `${config.evidentApiUrl.replace(/\/+$/, "")}/v1/runners/${encodeURIComponent(
|
|
87
|
+
runnerId
|
|
88
|
+
)}/microvm-image-versions`;
|
|
89
|
+
const result = await dependencies.fetch(url, {
|
|
90
|
+
method: "POST",
|
|
91
|
+
headers: {
|
|
92
|
+
"content-type": "application/json",
|
|
93
|
+
"x-evident-signature": signature
|
|
94
|
+
},
|
|
95
|
+
body,
|
|
96
|
+
signal: AbortSignal.timeout(REPORT_TIMEOUT_MS)
|
|
97
|
+
});
|
|
98
|
+
responseStatus = result.status;
|
|
99
|
+
console.log("runner.microvm_image_versions_reported", {
|
|
100
|
+
runnerId,
|
|
101
|
+
versions,
|
|
102
|
+
status: result.status
|
|
103
|
+
});
|
|
104
|
+
if (!result.ok) {
|
|
105
|
+
throw new Error(`Evident returned HTTP ${result.status}`);
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
109
|
+
console.warn("MicroVM image version report failed", {
|
|
110
|
+
operation: event.RequestType,
|
|
111
|
+
runnerId,
|
|
112
|
+
versions,
|
|
113
|
+
...responseStatus === void 0 ? {} : { status: responseStatus },
|
|
114
|
+
error: message
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return response();
|
|
118
|
+
}
|
|
119
|
+
var handler = (event) => handleImageVersionReport(event, () => ({
|
|
120
|
+
doorbellSecretArn: requireEnv("DOORBELL_SECRET_ARN"),
|
|
121
|
+
doorbellSecretKey: requireEnv("DOORBELL_SECRET_KEY"),
|
|
122
|
+
evidentApiUrl: requireEnv("EVIDENT_API_URL"),
|
|
123
|
+
evidentRunnerId: requireEnv("EVIDENT_RUNNER_ID")
|
|
124
|
+
}));
|
|
125
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
126
|
+
0 && (module.exports = {
|
|
127
|
+
handleImageVersionReport,
|
|
128
|
+
handler
|
|
129
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
export { EvidentScaleToZeroConstruct, type EvidentScaleToZeroConstructProps, } from './evident-scale-to-zero-construct';
|
|
2
2
|
export { EvidentWaker, type EvidentWakerProps } from './waker/construct';
|
|
3
|
+
export { EvidentMicrovmConstruct, type EvidentMicrovmConstructProps } from './microvm/construct';
|
|
4
|
+
export { MICROVM_SHAPES, validateShapes, type MicrovmShape } from './microvm/shapes';
|
|
5
|
+
export { MICROVM_MAX_RUN_SECONDS, HOOKS_PORT, HOOK_TIMEOUT_SECONDS, } from './microvm/constants';
|
|
6
|
+
export { stageMicrovmImageContext, type StageMicrovmImageContextOptions, } from './microvm/image/stage-context';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EvidentWaker = exports.EvidentScaleToZeroConstruct = void 0;
|
|
3
|
+
exports.stageMicrovmImageContext = exports.HOOK_TIMEOUT_SECONDS = exports.HOOKS_PORT = exports.MICROVM_MAX_RUN_SECONDS = exports.validateShapes = exports.MICROVM_SHAPES = exports.EvidentMicrovmConstruct = exports.EvidentWaker = exports.EvidentScaleToZeroConstruct = void 0;
|
|
4
4
|
var evident_scale_to_zero_construct_1 = require("./evident-scale-to-zero-construct");
|
|
5
5
|
Object.defineProperty(exports, "EvidentScaleToZeroConstruct", { enumerable: true, get: function () { return evident_scale_to_zero_construct_1.EvidentScaleToZeroConstruct; } });
|
|
6
6
|
var construct_1 = require("./waker/construct");
|
|
7
7
|
Object.defineProperty(exports, "EvidentWaker", { enumerable: true, get: function () { return construct_1.EvidentWaker; } });
|
|
8
|
+
var construct_2 = require("./microvm/construct");
|
|
9
|
+
Object.defineProperty(exports, "EvidentMicrovmConstruct", { enumerable: true, get: function () { return construct_2.EvidentMicrovmConstruct; } });
|
|
10
|
+
var shapes_1 = require("./microvm/shapes");
|
|
11
|
+
Object.defineProperty(exports, "MICROVM_SHAPES", { enumerable: true, get: function () { return shapes_1.MICROVM_SHAPES; } });
|
|
12
|
+
Object.defineProperty(exports, "validateShapes", { enumerable: true, get: function () { return shapes_1.validateShapes; } });
|
|
13
|
+
var constants_1 = require("./microvm/constants");
|
|
14
|
+
Object.defineProperty(exports, "MICROVM_MAX_RUN_SECONDS", { enumerable: true, get: function () { return constants_1.MICROVM_MAX_RUN_SECONDS; } });
|
|
15
|
+
// The two values a consumer MUST pass to `EvidentMicrovmConstruct` for them
|
|
16
|
+
// to match the published image they were baked into (#1528).
|
|
17
|
+
Object.defineProperty(exports, "HOOKS_PORT", { enumerable: true, get: function () { return constants_1.HOOKS_PORT; } });
|
|
18
|
+
Object.defineProperty(exports, "HOOK_TIMEOUT_SECONDS", { enumerable: true, get: function () { return constants_1.HOOK_TIMEOUT_SECONDS; } });
|
|
19
|
+
var stage_context_1 = require("./microvm/image/stage-context");
|
|
20
|
+
Object.defineProperty(exports, "stageMicrovmImageContext", { enumerable: true, get: function () { return stage_context_1.stageMicrovmImageContext; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const HOOKS_PORT = 8080;
|
|
2
|
+
export declare const HOOKS_DIR = "/etc/evident/hooks";
|
|
3
|
+
export declare const HOOK_TIMEOUT_SECONDS = 60;
|
|
4
|
+
export declare const RUN_HOOK_PAYLOAD_MAX_BYTES = 16384;
|
|
5
|
+
export declare const SUSPENDING_POLL_ATTEMPTS = 4;
|
|
6
|
+
export declare const SUSPENDING_POLL_INTERVAL_MS = 500;
|
|
7
|
+
export declare const MICROVM_MAX_RUN_SECONDS = 28800;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared literals for the MicroVM controller and for the image it launches.
|
|
3
|
+
// Every module imports from here rather than restating a value that must match
|
|
4
|
+
// across them. The image template pins matching copies, guarded by
|
|
5
|
+
// `microvm/image/dockerfile.test.ts`.
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.MICROVM_MAX_RUN_SECONDS = exports.SUSPENDING_POLL_INTERVAL_MS = exports.SUSPENDING_POLL_ATTEMPTS = exports.RUN_HOOK_PAYLOAD_MAX_BYTES = exports.HOOK_TIMEOUT_SECONDS = exports.HOOKS_DIR = exports.HOOKS_PORT = void 0;
|
|
8
|
+
// The port the image's hook server binds, baked into the published Dockerfile
|
|
9
|
+
// (`ENV HOOKS_PORT`) and passed to the construct as `hooksPort`. Exported from
|
|
10
|
+
// the package index because a consumer building the published image context
|
|
11
|
+
// MUST pass the value it was baked with — the construct's own docstring warns
|
|
12
|
+
// that a mismatch means AWS probes a port nothing binds.
|
|
13
|
+
exports.HOOKS_PORT = 8080;
|
|
14
|
+
// One executable per lifecycle phase. A phase with no script is a no-op, which
|
|
15
|
+
// is why the image ships none for `ready` or `validate`: nothing Evident-specific
|
|
16
|
+
// may run before the snapshot, so there is nothing for them to do.
|
|
17
|
+
exports.HOOKS_DIR = '/etc/evident/hooks';
|
|
18
|
+
// Seconds AWS allows a Run/Resume/Suspend/Terminate hook, passed to the
|
|
19
|
+
// construct as `hookTimeoutSeconds`. Exported for the same reason as
|
|
20
|
+
// `HOOKS_PORT`: the hooks are built against it.
|
|
21
|
+
exports.HOOK_TIMEOUT_SECONDS = 60;
|
|
22
|
+
// AWS caps `runHookPayload` at 16 KiB; anything larger is rejected at its API,
|
|
23
|
+
// so the controller checks it before spending a call.
|
|
24
|
+
exports.RUN_HOOK_PAYLOAD_MAX_BYTES = 16384;
|
|
25
|
+
// Worst-case poll (attempts × interval ≈ 2 s) must fit the controller Lambda's 8 s
|
|
26
|
+
// timeout alongside the retry backoff.
|
|
27
|
+
exports.SUSPENDING_POLL_ATTEMPTS = 4;
|
|
28
|
+
exports.SUSPENDING_POLL_INTERVAL_MS = 500;
|
|
29
|
+
// AWS's non-adjustable ceiling on a single MicroVM run, passed as
|
|
30
|
+
// `RunMicrovmCommand`'s `maximumDurationInSeconds`. The version pruner reuses it
|
|
31
|
+
// as its post-deactivation staging delay: once a version has been INACTIVE for
|
|
32
|
+
// longer than any VM can possibly still be running, no VM started before the
|
|
33
|
+
// deactivation can outlive it. The two MUST move together.
|
|
34
|
+
exports.MICROVM_MAX_RUN_SECONDS = 28800;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Construct } from 'constructs';
|
|
2
|
+
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
3
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
4
|
+
import { type MicrovmShape } from './shapes';
|
|
5
|
+
export interface EvidentMicrovmConstructProps {
|
|
6
|
+
/**
|
|
7
|
+
* Build context for the image, already staged on disk. An argument rather
|
|
8
|
+
* than something this construct stages itself, so synthesising the stack
|
|
9
|
+
* stays a pure function of its inputs instead of depending on how the
|
|
10
|
+
* ambient checkout was cloned.
|
|
11
|
+
*/
|
|
12
|
+
readonly imageSource: string;
|
|
13
|
+
/**
|
|
14
|
+
* ARN of the Lambda-managed base MicroVM image, from
|
|
15
|
+
* `aws lambda-microvms list-managed-microvm-images`. A string, not a `CfnParameter`
|
|
16
|
+
* built here: the caller creates the parameter at ITS OWN stack scope
|
|
17
|
+
* (preserving its logical id) and passes its resolved value down — a
|
|
18
|
+
* construct must not mint parameters into a consumer's stack.
|
|
19
|
+
*/
|
|
20
|
+
readonly baseImageArn: string;
|
|
21
|
+
/**
|
|
22
|
+
* Version of the Lambda-managed base MicroVM image, from
|
|
23
|
+
* `aws lambda-microvms list-managed-microvm-images`. See `baseImageArn` for why this
|
|
24
|
+
* is a plain string.
|
|
25
|
+
*/
|
|
26
|
+
readonly baseImageVersion: string;
|
|
27
|
+
/**
|
|
28
|
+
* The shape catalogue to build one image per shape from (#723). Defaults to
|
|
29
|
+
* `MICROVM_SHAPES`, the committed catalogue. Overridable so a caller can
|
|
30
|
+
* synth a local multi-shape template without mutating that module
|
|
31
|
+
* constant.
|
|
32
|
+
*/
|
|
33
|
+
readonly shapes?: readonly MicrovmShape[];
|
|
34
|
+
/**
|
|
35
|
+
* The secret holding the shared HMAC key the controller verifies every
|
|
36
|
+
* doorbell against, under the field `DOORBELL_SECRET`. Any Secrets Manager
|
|
37
|
+
* secret, however the caller manages it — this construct has no opinion on
|
|
38
|
+
* SOPS, KMS, or any other production mechanism. Required (not defaulted
|
|
39
|
+
* here): a default would need a scope of its own, and a caller-owned
|
|
40
|
+
* default keeps its own logical id — the caller builds one exactly once,
|
|
41
|
+
* in its own scope, and passes the result in either case.
|
|
42
|
+
*/
|
|
43
|
+
readonly doorbellSecret: secretsmanager.ISecret;
|
|
44
|
+
/**
|
|
45
|
+
* Optional runner secret whose JSON values are exported by `/run`. Omitting it
|
|
46
|
+
* leaves GitHub and MCP credentials unavailable to a generic consumer.
|
|
47
|
+
*/
|
|
48
|
+
readonly runnerSecret?: secretsmanager.ISecret;
|
|
49
|
+
/**
|
|
50
|
+
* Optional runner OpenCode overlay. Absolute paths are image paths; relative
|
|
51
|
+
* paths are resolved from the baked workspace by the `/run` hook.
|
|
52
|
+
*/
|
|
53
|
+
readonly runnerOpencodeConfigPath?: string;
|
|
54
|
+
/** Optional git identity the `/run` hook configures for agent commits. */
|
|
55
|
+
readonly gitUserName?: string;
|
|
56
|
+
/** Optional git email the `/run` hook configures for agent commits. */
|
|
57
|
+
readonly gitUserEmail?: string;
|
|
58
|
+
/**
|
|
59
|
+
* TCP port the image's hook server listens on, baked into both the image
|
|
60
|
+
* (`HOOKS_PORT` env var) and the `MicrovmImage`'s `hooks.port` — a mismatch
|
|
61
|
+
* means AWS probes a port nothing binds. Caller-supplied because the hook
|
|
62
|
+
* server is part of `imageSource`, which this construct does not build.
|
|
63
|
+
*/
|
|
64
|
+
readonly hooksPort: number;
|
|
65
|
+
/**
|
|
66
|
+
* Seconds AWS waits for a Run/Resume/Suspend/Terminate hook to answer,
|
|
67
|
+
* before the image build itself times out (`IMAGE_HOOK_TIMEOUT_SECONDS`,
|
|
68
|
+
* fixed at 600 s — building the snapshot is a different budget from
|
|
69
|
+
* running a hook).
|
|
70
|
+
*/
|
|
71
|
+
readonly hookTimeoutSeconds: number;
|
|
72
|
+
/**
|
|
73
|
+
* Base URL of Evident's own API. Together with `evidentRunnerId`, opts this
|
|
74
|
+
* deploy into reporting each shape's published image version to Evident
|
|
75
|
+
* (#1903) — a CDK custom resource, triggered only when a deploy actually
|
|
76
|
+
* changes a version. Omitting BOTH leaves the template byte-for-byte
|
|
77
|
+
* identical to not having this prop at all: an adopter with no Evident
|
|
78
|
+
* runner id configured has nothing to report against. Supplying only one
|
|
79
|
+
* throws at synth — see `evidentRunnerId`.
|
|
80
|
+
*/
|
|
81
|
+
readonly evidentApiUrl?: string;
|
|
82
|
+
/**
|
|
83
|
+
* The pool runner id (public, non-secret UUID) to report against — see
|
|
84
|
+
* `evidentApiUrl`. Mirrors `EvidentScaleToZeroConstructProps.evidentAgentId`'s
|
|
85
|
+
* "public (non-secret) Evident agent UUID" precedent. Must be supplied
|
|
86
|
+
* together with `evidentApiUrl`, or neither at all — supplying exactly one
|
|
87
|
+
* throws at construction rather than silently disabling the reporter.
|
|
88
|
+
*/
|
|
89
|
+
readonly evidentRunnerId?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The customer-account half of the per-session runner (#558): the MicroVM
|
|
93
|
+
* image and the roles it builds and runs as, plus the stateless controller
|
|
94
|
+
* Lambda that turns a signed doorbell into RunMicrovm / ResumeMicrovm /
|
|
95
|
+
* SuspendMicrovm.
|
|
96
|
+
*/
|
|
97
|
+
export declare class EvidentMicrovmConstruct extends Construct {
|
|
98
|
+
/** POST target for Evident's signed doorbell (HMAC-verified in the handler). */
|
|
99
|
+
readonly functionUrl: string;
|
|
100
|
+
/** The shapes the controller can launch, with the image ARN each RunMicrovm uses. */
|
|
101
|
+
readonly shapeCatalogueJson: string;
|
|
102
|
+
/** Bucket a runner restores model credentials from: seed `<state_prefix>/claude/credentials.json` here. */
|
|
103
|
+
readonly durableStateBucket: s3.Bucket;
|
|
104
|
+
constructor(scope: Construct, id: string, props: EvidentMicrovmConstructProps);
|
|
105
|
+
}
|