@evident-ai/runner-cdk 3.5.2-dev.e67eb8b → 3.5.2-dev.f258bd6

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.
@@ -1,42 +1,17 @@
1
- export interface StageMicrovmImageContextOptions {
2
- /**
3
- * The repository baked into the image as the agent's workspace. This is the
4
- * CONSUMER's repository, not Evident's — the image is a dev box for whatever
5
- * codebase the agent works on. Must be a full (non-shallow) clone.
6
- */
7
- readonly repositoryPath: string;
8
- /**
9
- * `origin` of the baked repository, as the VM will see it. Must be a
10
- * credential-free URL (typically `https://github.com/<owner>/<repo>.git`):
11
- * this string ships inside the shared snapshot, so a token in it would be
12
- * baked into every VM. The credential arrives per-VM instead.
13
- */
14
- readonly originUrl: string;
15
- /** Directory to write the build context to. Removed and recreated. */
16
- readonly destination: string;
17
- /**
18
- * Overlay scripts the image build runs as root and as `runner`. The overlay
19
- * ships inside the shared snapshot, so it may install software but must carry
20
- * no credential. When omitted, deterministic no-op scripts are written.
21
- */
22
- readonly overlayDir?: string;
23
- /**
24
- * The published template to copy from. Defaults to the one inside this
25
- * package; named directly by the tests, which assert against a template they
26
- * built themselves rather than whichever `dist/` happens to be present.
27
- */
28
- readonly templateDir?: string;
1
+ /** The fixed directory that contains the workspace in a staged build context. */
2
+ export declare const MICROVM_WORKSPACE_DIRECTORY = "workspace";
3
+ export interface StageMicrovmBuildContextOptions {
4
+ /** The customer's directory containing their Dockerfile and COPY sources. */
5
+ readonly buildContextPath: string;
6
+ /** A full local checkout to bake into the image's `workspace/` directory. */
7
+ readonly workspaceRepositoryPath: string;
8
+ /** Credential-free origin URL carried by the baked checkout. */
9
+ readonly workspaceOriginUrl: string;
29
10
  }
30
11
  /**
31
- * Writes the build context AWS unpacks — the Dockerfile, the hook server, the
32
- * per-phase hook scripts, the deployment overlay and the repository — and
33
- * returns its path. The result is what `EvidentMicrovmConstruct`'s `imageSource`
34
- * takes.
12
+ * Stages customer-owned image inputs in a fresh temporary directory.
35
13
  *
36
- * The Dockerfile, hook server and phase hooks come from this package's
37
- * published `dist/`, so a consumer needs no checkout of the source repository and no
38
- * copy of those files. A caller may supply an overlay; the default is
39
- * deterministic no-op scripts. `repositoryPath` is the only required caller
40
- * input.
14
+ * Staging keeps the image asset hash a pure function of the workspace commit while
15
+ * leaving the customer in control of the Dockerfile and its build context.
41
16
  */
42
- export declare function stageMicrovmImageContext(options: StageMicrovmImageContextOptions): string;
17
+ export declare function stageMicrovmBuildContext(options: StageMicrovmBuildContextOptions): string;
@@ -33,143 +33,53 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.stageMicrovmImageContext = stageMicrovmImageContext;
36
+ exports.MICROVM_WORKSPACE_DIRECTORY = void 0;
37
+ exports.stageMicrovmBuildContext = stageMicrovmBuildContext;
37
38
  const node_child_process_1 = require("node:child_process");
38
39
  const node_fs_1 = require("node:fs");
40
+ const node_os_1 = require("node:os");
39
41
  const path = __importStar(require("node:path"));
40
- /**
41
- * The image build context template published inside this package.
42
- *
43
- * Resolved from the PACKAGE ROOT, THREE directories above `__dirname` — either
44
- * compiled (`dist/microvm/image`) or via ts-node (`src/microvm/image`) — the
45
- * same way `microvm/construct.ts` resolves the controller Lambda asset, but one
46
- * `..` deeper because this file sits a directory below it. It is
47
- * written by `scripts/build.ts` at PACKAGE build time, not at stage time, so a
48
- * consumer needs no esbuild and no checkout of this repo (#1528).
49
- */
50
- const TEMPLATE_DIR = path.resolve(__dirname, '..', '..', '..', 'dist', 'microvm-image-context');
42
+ /** The fixed directory that contains the workspace in a staged build context. */
43
+ exports.MICROVM_WORKSPACE_DIRECTORY = 'workspace';
51
44
  function git(args, cwd) {
52
45
  return (0, node_child_process_1.execFileSync)('git', args, { cwd, encoding: 'utf8' }).trim();
53
46
  }
54
- /**
55
- * `git rev-parse --is-shallow-repository` throws an opaque `execFileSync`
56
- * error (e.g. "not a git repository") when `repositoryPath` isn't usable at
57
- * all, so that failure is rethrown naming the path.
58
- */
59
- function isShallowRepository(repositoryPath) {
47
+ /** Names the path when git cannot determine whether the repository is shallow. */
48
+ function isShallowRepository(sourcePath) {
60
49
  try {
61
- return git(['rev-parse', '--is-shallow-repository'], repositoryPath) === 'true';
50
+ return git(['rev-parse', '--is-shallow-repository'], sourcePath) === 'true';
62
51
  }
63
52
  catch (err) {
64
- throw new Error(`${repositoryPath} is not a usable git repository: ` +
53
+ throw new Error(`${sourcePath} is not a usable git repository: ` +
65
54
  `${err instanceof Error ? err.message : String(err)}`);
66
55
  }
67
56
  }
68
- /**
69
- * Clones the caller's repository into the build context for the Dockerfile to
70
- * bake as a checked-out but uninstalled workspace.
71
- *
72
- * `file://` rather than a plain path: a path triggers git's local-clone
73
- * optimisation, which copies the whole object store — every branch and worktree
74
- * ref on the staging machine (50 MB here). The file transport negotiates like a
75
- * network fetch and packs only what the checked-out branch reaches (9 MB), with
76
- * one branch and one remote-tracking ref. Ignored files, `node_modules` first
77
- * among them, are not part of a clone at all.
78
- */
79
- function stageRepository(repositoryPath, destination, originUrl) {
80
- if (isShallowRepository(repositoryPath)) {
81
- throw new Error(`refusing to stage a shallow checkout (${repositoryPath}): the agent branches, ` +
57
+ /** Clones a full repository while normalising the bytes that affect the image asset hash. */
58
+ function stageRepository(sourcePath, stagedWorkspacePath, workspaceOriginUrl) {
59
+ if (isShallowRepository(sourcePath)) {
60
+ throw new Error(`refusing to stage a shallow checkout (${sourcePath}): the agent branches, ` +
82
61
  'commits and opens PRs, so the image needs real history. Run `git fetch --unshallow`.');
83
62
  }
84
- // Absolute on both sides: `file://` needs an absolute path to mean anything,
85
- // and the clone's cwd is the destination's parent (the only directory both
86
- // are guaranteed to resolve against).
87
- git(['clone', '--quiet', '--single-branch', `file://${repositoryPath}`, destination], path.dirname(destination));
88
- // The clone points `origin` at this machine's filesystem; the VM's origin is
89
- // the caller's own remote over HTTPS, with no credential in it.
90
- git(['remote', 'set-url', 'origin', originUrl], destination);
91
- // The asset hash of the resulting image must be a pure function of the commit,
92
- // or every deploy publishes a new `AWS::Lambda::MicrovmImage` version and wedges
93
- // the stack at its per-image version ceiling. Two things break that purity:
94
- // - `pack-objects`' delta search is multithreaded (`pack.threads` defaults to
95
- // the CPU count) and its output varies run to run; `-f`/`-F`
96
- // (`--no-reuse-delta`/`--no-reuse-object`) additionally stop it from reusing
97
- // whatever packing the source checkout happened to have. All three together
98
- // make the pack a pure function of the object set, independent of the source.
99
- // - `.git/index` carries stat data (inode/mtime/size) and `.git/logs/**` carries
100
- // wall-clock reflog timestamps; neither is byte-stable for a fixed commit.
101
- git(['-c', 'pack.threads=1', 'repack', '-adfqF'], destination);
102
- (0, node_fs_1.rmSync)(path.join(destination, '.git', 'index'), { force: true });
103
- (0, node_fs_1.rmSync)(path.join(destination, '.git', 'logs'), { recursive: true, force: true });
104
- console.log(`[stage] repo ${git(['rev-parse', 'HEAD'], destination)}`);
105
- }
106
- function stageScriptDirectory(source, destination) {
107
- (0, node_fs_1.mkdirSync)(destination);
108
- for (const entry of (0, node_fs_1.readdirSync)(source, { withFileTypes: true })) {
109
- const sourcePath = path.join(source, entry.name);
110
- const staged = path.join(destination, entry.name);
111
- if (entry.isDirectory()) {
112
- stageScriptDirectory(sourcePath, staged);
113
- continue;
114
- }
115
- (0, node_fs_1.copyFileSync)(sourcePath, staged);
116
- // Set modes here rather than inheriting them from the template, so they stay
117
- // correct after an npm pack, zip, CI-cache or hand-copy round trip. The image
118
- // executes extensionless scripts and sources `.sh` files.
119
- (0, node_fs_1.chmodSync)(staged, entry.name.endsWith('.sh') ? 0o644 : 0o755);
120
- }
63
+ git(['clone', '--quiet', '--single-branch', `file://${sourcePath}`, stagedWorkspacePath], path.dirname(stagedWorkspacePath));
64
+ git(['remote', 'set-url', 'origin', workspaceOriginUrl], stagedWorkspacePath);
65
+ git(['-c', 'pack.threads=1', 'repack', '-adfqF'], stagedWorkspacePath);
66
+ (0, node_fs_1.rmSync)(path.join(stagedWorkspacePath, '.git', 'index'), { force: true });
67
+ (0, node_fs_1.rmSync)(path.join(stagedWorkspacePath, '.git', 'logs'), { recursive: true, force: true });
68
+ console.log(`[stage] repo ${git(['rev-parse', 'HEAD'], stagedWorkspacePath)}`);
121
69
  }
122
70
  /**
123
- * Writes the build context AWS unpacks — the Dockerfile, the hook server, the
124
- * per-phase hook scripts, the deployment overlay and the repository — and
125
- * returns its path. The result is what `EvidentMicrovmConstruct`'s `imageSource`
126
- * takes.
71
+ * Stages customer-owned image inputs in a fresh temporary directory.
127
72
  *
128
- * The Dockerfile, hook server and phase hooks come from this package's
129
- * published `dist/`, so a consumer needs no checkout of the source repository and no
130
- * copy of those files. A caller may supply an overlay; the default is
131
- * deterministic no-op scripts. `repositoryPath` is the only required caller
132
- * input.
73
+ * Staging keeps the image asset hash a pure function of the workspace commit while
74
+ * leaving the customer in control of the Dockerfile and its build context.
133
75
  */
134
- function stageMicrovmImageContext(options) {
135
- const { originUrl, overlayDir, templateDir = TEMPLATE_DIR } = options;
136
- // `file://` and the clone below only mean anything against absolute paths,
137
- // and a caller may reasonably pass either.
138
- const repositoryPath = path.resolve(options.repositoryPath);
139
- const destination = path.resolve(options.destination);
140
- if (!(0, node_fs_1.existsSync)(templateDir)) {
141
- throw new Error(`the MicroVM image context template is missing from ${templateDir}. It is written by ` +
142
- "this package's build (`pnpm --filter @evident-ai/runner-cdk build`) and ships in the " +
143
- 'published tarball, so an installed copy should always have it.');
144
- }
145
- (0, node_fs_1.rmSync)(destination, { recursive: true, force: true });
146
- (0, node_fs_1.mkdirSync)(destination, { recursive: true });
147
- (0, node_fs_1.copyFileSync)(path.join(templateDir, 'Dockerfile'), path.join(destination, 'Dockerfile'));
148
- (0, node_fs_1.copyFileSync)(path.join(templateDir, 'hook-server.js'), path.join(destination, 'hook-server.js'));
149
- const hooksSource = path.join(templateDir, 'hooks');
150
- const hooksStage = path.join(destination, 'hooks');
151
- stageScriptDirectory(hooksSource, hooksStage);
152
- const overlayStage = path.join(destination, 'overlay');
153
- if (overlayDir === undefined) {
154
- (0, node_fs_1.mkdirSync)(overlayStage);
155
- for (const name of ['setup-root', 'setup-workspace']) {
156
- const staged = path.join(overlayStage, name);
157
- (0, node_fs_1.writeFileSync)(staged, '#!/usr/bin/env bash\n# No overlay supplied.\n', { mode: 0o755 });
158
- (0, node_fs_1.chmodSync)(staged, 0o755);
159
- }
160
- }
161
- else {
162
- const resolvedOverlayDir = path.resolve(overlayDir);
163
- if (!(0, node_fs_1.existsSync)(resolvedOverlayDir)) {
164
- throw new Error(`overlay directory does not exist: ${resolvedOverlayDir}`);
165
- }
166
- for (const required of ['setup-root', 'setup-workspace']) {
167
- if (!(0, node_fs_1.existsSync)(path.join(resolvedOverlayDir, required))) {
168
- throw new Error(`overlay directory ${resolvedOverlayDir} is missing required script ${required}`);
169
- }
170
- }
171
- stageScriptDirectory(resolvedOverlayDir, overlayStage);
76
+ function stageMicrovmBuildContext(options) {
77
+ const buildContextPath = path.resolve(options.buildContextPath);
78
+ if (!(0, node_fs_1.existsSync)(buildContextPath) || !(0, node_fs_1.existsSync)(path.join(buildContextPath, 'Dockerfile'))) {
79
+ throw new Error(`MicroVM build context ${buildContextPath} does not exist or has no Dockerfile`);
172
80
  }
173
- stageRepository(repositoryPath, path.join(destination, 'repo'), originUrl);
174
- return destination;
81
+ const stagedPath = (0, node_fs_1.mkdtempSync)(path.join((0, node_os_1.tmpdir)(), 'evident-microvm-'));
82
+ (0, node_fs_1.cpSync)(buildContextPath, stagedPath, { recursive: true });
83
+ stageRepository(path.resolve(options.workspaceRepositoryPath), path.join(stagedPath, exports.MICROVM_WORKSPACE_DIRECTORY), options.workspaceOriginUrl);
84
+ return stagedPath;
175
85
  }
@@ -3,7 +3,7 @@ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
3
3
  import type { MicrovmImageBuildInputs } from '@evident-ai/lambda-microvm-cdk';
4
4
  export type ImageVersionReporterProps = {
5
5
  /** The secret whose value is the same HMAC key the controller verifies every doorbell against. */
6
- doorbellSecret: secretsmanager.ISecret;
6
+ controllerSigningSecret: secretsmanager.ISecret;
7
7
  /** Base URL of Evident's own API — non-secret. */
8
8
  evidentApiUrl: string;
9
9
  /** The pool runner id the report is filed against — non-secret, public UUID. */
@@ -64,13 +64,13 @@ class ImageVersionReporter extends constructs_1.Construct {
64
64
  timeout: cdk.Duration.seconds(30),
65
65
  environment: {
66
66
  // ARN + field name only, never the value (mirrors the controller and waker).
67
- DOORBELL_SECRET_ARN: props.doorbellSecret.secretArn,
68
- DOORBELL_SECRET_KEY: constants_1.DOORBELL_SECRET_KEY,
67
+ CONTROLLER_SIGNING_SECRET_ARN: props.controllerSigningSecret.secretArn,
68
+ CONTROLLER_SIGNING_SECRET_KEY: constants_1.CONTROLLER_SIGNING_SECRET_KEY,
69
69
  EVIDENT_API_URL: props.evidentApiUrl,
70
70
  EVIDENT_RUNNER_ID: props.evidentRunnerId,
71
71
  },
72
72
  });
73
- props.doorbellSecret.grantRead(handler);
73
+ props.controllerSigningSecret.grantRead(handler);
74
74
  const provider = new cr.Provider(this, 'Provider', {
75
75
  onEventHandler: handler,
76
76
  });
@@ -9,8 +9,8 @@ export type ReporterEvent = {
9
9
  };
10
10
  };
11
11
  export type ReporterConfig = {
12
- doorbellSecretArn: string;
13
- doorbellSecretKey: string;
12
+ controllerSigningSecretArn: string;
13
+ controllerSigningSecretKey: string;
14
14
  evidentApiUrl: string;
15
15
  evidentRunnerId: string;
16
16
  };
@@ -7,17 +7,17 @@ const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
7
7
  const PHYSICAL_RESOURCE_ID = 'evident-image-version-report';
8
8
  const REPORT_TIMEOUT_MS = 5_000;
9
9
  const secrets = new client_secrets_manager_1.SecretsManagerClient({});
10
- async function fetchDoorbellSecret(secretArn, secretKey) {
10
+ async function fetchControllerSigningSecret(secretArn, secretKey) {
11
11
  const { SecretString } = await secrets.send(new client_secrets_manager_1.GetSecretValueCommand({ SecretId: secretArn }));
12
12
  if (!SecretString) {
13
- throw new Error(`doorbell secret ${secretArn} has no SecretString`);
13
+ throw new Error(`controller signing secret ${secretArn} has no SecretString`);
14
14
  }
15
15
  const parsed = JSON.parse(SecretString);
16
16
  const value = parsed !== null && typeof parsed === 'object'
17
17
  ? parsed[secretKey]
18
18
  : undefined;
19
19
  if (typeof value !== 'string' || value === '') {
20
- throw new Error(`doorbell secret ${secretArn} is missing a non-empty '${secretKey}' field`);
20
+ throw new Error(`controller signing secret ${secretArn} is missing a non-empty '${secretKey}' field`);
21
21
  }
22
22
  return value;
23
23
  }
@@ -43,7 +43,7 @@ function response() {
43
43
  return { PhysicalResourceId: PHYSICAL_RESOURCE_ID };
44
44
  }
45
45
  const runtimeDependencies = {
46
- getSecret: fetchDoorbellSecret,
46
+ getSecret: fetchControllerSigningSecret,
47
47
  fetch: globalThis.fetch,
48
48
  };
49
49
  async function handleImageVersionReport(event, getConfig, dependencies = runtimeDependencies) {
@@ -57,10 +57,12 @@ async function handleImageVersionReport(event, getConfig, dependencies = runtime
57
57
  versions = readImageVersions(event.ResourceProperties?.imageVersions);
58
58
  const config = getConfig();
59
59
  runnerId = config.evidentRunnerId;
60
- const secret = await dependencies.getSecret(config.doorbellSecretArn, config.doorbellSecretKey);
60
+ const secret = await dependencies.getSecret(config.controllerSigningSecretArn, config.controllerSigningSecretKey);
61
61
  const body = JSON.stringify({
62
62
  type: 'runner.microvm_image_versions_reported',
63
63
  versions,
64
+ // The API orders reports by this value because replacing an image restarts its version counter.
65
+ reporter_clock_ms: Date.now(),
64
66
  });
65
67
  const signature = (0, node_crypto_1.createHmac)('sha256', secret).update(body).digest('hex');
66
68
  const url = `${config.evidentApiUrl.replace(/\/+$/, '')}/v1/runners/${encodeURIComponent(runnerId)}/microvm-image-versions`;
@@ -96,8 +98,8 @@ async function handleImageVersionReport(event, getConfig, dependencies = runtime
96
98
  return response();
97
99
  }
98
100
  const handler = (event) => handleImageVersionReport(event, () => ({
99
- doorbellSecretArn: requireEnv('DOORBELL_SECRET_ARN'),
100
- doorbellSecretKey: requireEnv('DOORBELL_SECRET_KEY'),
101
+ controllerSigningSecretArn: requireEnv('CONTROLLER_SIGNING_SECRET_ARN'),
102
+ controllerSigningSecretKey: requireEnv('CONTROLLER_SIGNING_SECRET_KEY'),
101
103
  evidentApiUrl: requireEnv('EVIDENT_API_URL'),
102
104
  evidentRunnerId: requireEnv('EVIDENT_RUNNER_ID'),
103
105
  }));
@@ -5,11 +5,8 @@ import { type MicrovmMemoryMiB } from '@evident-ai/lambda-microvm-cdk';
5
5
  * there is no launch-time resource dial — so "a bigger machine" means "a
6
6
  * different shape", each backed by its own `MicrovmImage`.
7
7
  *
8
- * `constructId` and `imageName` are carried **explicitly** rather than
9
- * derived from `name`, because for the default shape they are frozen
10
- * deployment identity (see the comment on `MICROVM_SHAPES` below): deriving
11
- * them would let an innocent rename of `name` silently rebuild the live
12
- * image. Every other shape is free to name these however is convenient.
8
+ * `name` is also the `MicrovmImage` child id, so it identifies both the
9
+ * controller-facing shape and the image resource built for it.
13
10
  */
14
11
  export interface MicrovmShape {
15
12
  /** The stable id a doorbell asks for; crosses the wire to Evident. */
@@ -27,8 +24,6 @@ export interface MicrovmShape {
27
24
  * it must be the first entry in `MICROVM_SHAPES`.
28
25
  */
29
26
  readonly isDefault: boolean;
30
- /** The `MicrovmImage` construct id within the stack. */
31
- readonly constructId: string;
32
27
  /** The account-unique `imageName` passed to `MicrovmImage`. */
33
28
  readonly imageName: string;
34
29
  }
@@ -45,28 +40,22 @@ export interface MicrovmShape {
45
40
  * making the construction-order contract enforceable rather than a
46
41
  * convention.
47
42
  *
48
- * The default entry's `constructId` ("Image") and `imageName`
49
- * ("evident-microvm") are FROZEN: they are today's live, hand-deployed
50
- * image's identity. Changing either destroys and rebuilds it (~4m45s,
51
- * measured) plus a window with no image. Its `description` is copied
52
- * verbatim from the image that is live today so the deploy changes nothing
53
- * about it.
43
+ * The default entry's `name` ("standard") and `imageName`
44
+ * ("evident-microvm-standard") are FROZEN: `name` crosses the wire and
45
+ * identifies the image child, while `imageName` is account-unique. Changing
46
+ * either replaces the image, so both values remain stable after deployment.
54
47
  *
55
48
  * "Frozen" means unchanged under OUR OWN synth (no `microvm:*` context set —
56
49
  * `main.ts` passes none). `imageName` MAY carry a customer's
57
50
  * `microvm:namePrefix` (`deployment.ts`'s `resolveShapeCatalogue`) — that is
58
- * account-scoped naming, not a change to this module. `constructId` stays
59
- * frozen unconditionally, with no override anywhere: it is the
60
- * CloudFormation logical-id path, and prefixing it is the resource
61
- * replacement this whole file's FROZEN warning exists to prevent.
51
+ * account-scoped naming, not a change to this module.
62
52
  */
63
53
  export declare const MICROVM_SHAPES: readonly MicrovmShape[];
64
54
  /**
65
55
  * Validates a shape list at synth time. Deliberately lean
66
56
  * (`code-simplicity.mdc`): this is a hand-edited constant list in a typed
67
- * file, so it only checks what `tsc` cannot already catch — CDK itself
68
- * rejects a duplicate `constructId`, so that one needs no check here, and no
69
- * byte-budget cap is applied (the image ARNs are unresolved tokens at synth,
70
- * so a rendered size is not measurable anyway).
57
+ * file, so it only checks what `tsc` cannot already catch. No byte-budget cap
58
+ * is applied because the image ARNs are unresolved tokens at synth, so a
59
+ * rendered size is not measurable anyway.
71
60
  */
72
61
  export declare function validateShapes(shapes: readonly MicrovmShape[]): readonly MicrovmShape[];
@@ -16,20 +16,15 @@ const lambda_microvm_cdk_1 = require("@evident-ai/lambda-microvm-cdk");
16
16
  * making the construction-order contract enforceable rather than a
17
17
  * convention.
18
18
  *
19
- * The default entry's `constructId` ("Image") and `imageName`
20
- * ("evident-microvm") are FROZEN: they are today's live, hand-deployed
21
- * image's identity. Changing either destroys and rebuilds it (~4m45s,
22
- * measured) plus a window with no image. Its `description` is copied
23
- * verbatim from the image that is live today so the deploy changes nothing
24
- * about it.
19
+ * The default entry's `name` ("standard") and `imageName`
20
+ * ("evident-microvm-standard") are FROZEN: `name` crosses the wire and
21
+ * identifies the image child, while `imageName` is account-unique. Changing
22
+ * either replaces the image, so both values remain stable after deployment.
25
23
  *
26
24
  * "Frozen" means unchanged under OUR OWN synth (no `microvm:*` context set —
27
25
  * `main.ts` passes none). `imageName` MAY carry a customer's
28
26
  * `microvm:namePrefix` (`deployment.ts`'s `resolveShapeCatalogue`) — that is
29
- * account-scoped naming, not a change to this module. `constructId` stays
30
- * frozen unconditionally, with no override anywhere: it is the
31
- * CloudFormation logical-id path, and prefixing it is the resource
32
- * replacement this whole file's FROZEN warning exists to prevent.
27
+ * account-scoped naming, not a change to this module.
33
28
  */
34
29
  exports.MICROVM_SHAPES = [
35
30
  {
@@ -38,18 +33,16 @@ exports.MICROVM_SHAPES = [
38
33
  description: 'Evident per-session runner: an arm64 image that boots with no identity and acquires one at /run.',
39
34
  memoryMiB: 4096,
40
35
  isDefault: true,
41
- // FROZEN — see the file-level comment. Do not rename either string.
42
- constructId: 'Image',
43
- imageName: 'evident-microvm',
36
+ // FROZEN — name crosses the wire and imageName is account-unique.
37
+ imageName: 'evident-microvm-standard',
44
38
  },
45
39
  ];
46
40
  /**
47
41
  * Validates a shape list at synth time. Deliberately lean
48
42
  * (`code-simplicity.mdc`): this is a hand-edited constant list in a typed
49
- * file, so it only checks what `tsc` cannot already catch — CDK itself
50
- * rejects a duplicate `constructId`, so that one needs no check here, and no
51
- * byte-budget cap is applied (the image ARNs are unresolved tokens at synth,
52
- * so a rendered size is not measurable anyway).
43
+ * file, so it only checks what `tsc` cannot already catch. No byte-budget cap
44
+ * is applied because the image ARNs are unresolved tokens at synth, so a
45
+ * rendered size is not measurable anyway.
53
46
  */
54
47
  function validateShapes(shapes) {
55
48
  if (shapes.length === 0) {
@@ -27,9 +27,9 @@ module.exports = __toCommonJS(handler_exports);
27
27
  var import_client_ecs = require("@aws-sdk/client-ecs");
28
28
  var import_client_secrets_manager = require("@aws-sdk/client-secrets-manager");
29
29
 
30
- // ../webhook-signature/src/verify-wake-signature.ts
30
+ // ../../sdk/src/signature.ts
31
31
  var import_node_crypto = require("node:crypto");
32
- function verifyWakeSignature(rawBody, signatureHeader, secret) {
32
+ function verifyEvidentSignature(rawBody, signatureHeader, secret) {
33
33
  if (!signatureHeader || !secret) {
34
34
  return false;
35
35
  }
@@ -64,7 +64,7 @@ async function handleWake({
64
64
  service,
65
65
  ecs
66
66
  }) {
67
- if (!verifyWakeSignature(rawBody, signatureHeader, wakeSecret)) {
67
+ if (!verifyEvidentSignature(rawBody, signatureHeader, wakeSecret)) {
68
68
  const { statusCode: statusCode2, body: body2 } = jsonResponse(401, "invalid signature");
69
69
  return { statusCode: statusCode2, body: body2, calledUpdateService: false };
70
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evident-ai/runner-cdk",
3
- "version": "3.5.2-dev.e67eb8b",
3
+ "version": "3.5.2-dev.f258bd6",
4
4
  "description": "Reusable CDK constructs for an Evident agent runner: a single scale-to-zero Fargate runner (task + service + per-agent self-stop role + waker Lambda), or a per-session AWS Lambda MicroVM that boots on demand and suspends between messages. Instantiate once per agent from your own stack.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -15,8 +15,8 @@
15
15
  ],
16
16
  "scripts": {
17
17
  "build": "pnpm run build-bundled-deps && ts-node scripts/build.ts && node -e 'const m=require(\"./package.json\").main; if (!require(\"node:fs\").existsSync(m)) { console.error(`build produced no ${m}`); process.exit(1); }'",
18
- "//build-bundled-deps": "scripts/build.ts esbuild-bundles runner/docker-images/microvm/hook-server.ts, which imports @evident-ai/lambda-microvm-runtime by its built `main`. @evident-ai/lambda-microvm-cdk is a workspace:* devDependency whose types resolve through its own dist/, so tsc --project tsconfig.build.json cannot compile src/microvm/{shapes,construct}.ts without it. Chained into `build` rather than left to turbo's `^build` because callers outside turbo invoke `pnpm --filter @evident-ai/runner-cdk build` directly, which bypasses turbo entirely.",
19
- "build-bundled-deps": "pnpm --filter @evident-ai/lambda-microvm-cdk build && pnpm --filter @evident-ai/lambda-microvm-runtime build",
18
+ "//build-bundled-deps": "Builds the workspace dependencies whose dist/ output the direct runner-cdk build chain consumes: lambda-microvm-cdk for the public construct types, lambda-microvm-runtime for runner-microvm-image's hook-server bundle, and runner-microvm-image for that bundle itself. Chained into `build` rather than left to turbo's `^build` because callers outside turbo invoke `pnpm --filter @evident-ai/runner-cdk build` directly, which bypasses turbo entirely.",
19
+ "build-bundled-deps": "pnpm --filter @evident-ai/lambda-microvm-cdk build && pnpm --filter @evident-ai/lambda-microvm-runtime build && pnpm --filter runner-microvm-image build",
20
20
  "typecheck": "tsc --noEmit",
21
21
  "test": "node --test --require ts-node/register 'src/**/*.test.ts'",
22
22
  "format": "prettier --write 'src/**/*.ts'",