feat(compute): add AWS Lambda MicroVMs ComputeStrategy backend — P1 (#645) - #689
Conversation
…ws-samples#645) Implement Phase P1 of ADR-021: the lambda-microvm compute backend (start/poll/stop), its CDK infrastructure, bootstrap policy, CLI support, and regional-availability enforcement. Suspend/resume (P3) and agent-side hook serving / smoke parity (P2) follow separately; a P1-built image is documented as not yet runnable end to end. Handlers (cdk/src/handlers): - ComputeType widens to 'agentcore' | 'ecs' | 'lambda-microvm'; SessionHandle gains {microvmId, endpoint}; SessionStatus gains 'suspended'; resolveComputeStrategy keeps the exhaustive-never gate - LambdaMicrovmComputeStrategy: RunMicrovm with idlePolicy omitted (auto-suspend disabled by construction) and maximumDurationInSeconds=28800 (AgentCore 8h parity); payload inline in runHookPayload up to exactly 16384 bytes, S3 pointer above; GetMicrovm poll maps the six-state MicrovmState enum mechanically (no task-state interpretation in the strategy); TerminateMicrovm best-effort with differentiated error handling; errors wrapped with a MicroVM marker so classifier entries cannot leak retry semantics onto other backends (regression-pinned) - Orchestrator: persists {microvmId, endpoint} to compute_metadata; cross-references substrate state vs DynamoDB (terminal + non- terminal -> failed with confirm re-read; suspended + non- AWAITING_APPROVAL -> anomaly event, no fail-fast); finalization and cancellation terminate the MicroVM (cancel branch ordered before the AgentCore RUNTIME_ARN fallback to avoid stopping an unrelated runtime in mixed deployments) Infra (cdk/src/constructs, stacks, bootstrap): - LambdaMicrovmCompute construct: CfnMicrovmImage + CfnNetworkConnector L1s (platform-VPC egress, 443-only SG), build/ execution roles trusted by lambda.amazonaws.com with sts:TagSession + aws:SourceAccount, execution role admitted via AgentSessionRole.admitComputeRole, payload bucket (1-day expiry, execution-role read-only, orchestrator put-only), three documented image-config states with mutually exclusive synth warnings - IAM scoped to the exact image ARN (+ ':*' version hedge; image names cannot contain ':') — no microvm-image:* wildcard anywhere; orchestrator gets only RunMicrovm/GetMicrovm/TerminateMicrovm/ PassNetworkConnector + scoped iam:PassRole; cancel Lambda gets TerminateMicrovm only; no Suspend/Resume/auth-token grants (P3) - Synth-time region gate (5 launch regions) with microvm_region_override escape hatch; token regions skipped - Bootstrap: conditional IaCRole-ABCA-Compute-LambdaMicrovms policy behind ComputeTypes (1.2.0 -> 1.3.0), deploy-time actions only; DEPLOYMENT_ROLES.md golden block [5] + golden-baseline parity test - abca:compute-backend=lambda-microvm cost tags; scripts/package-microvm-artifact.sh for the zip+Dockerfile flow CLI (cli/src): - Onboarding probes availability (ListManagedMicrovmImages) on the EFFECTIVE compute type (flag ?? stored ?? default) before any write, rejecting with launch-region list + agentcore/ecs remedy - platform doctor check when an active blueprint uses the backend (access-denied -> warn per checkBedrockModel precedent); runtime status groups the substrate like ECS ADR-021 refined in place (proposed): six-state poll mapping table, GetMicrovm NotFound -> completed rationale, microvmId vs microvmIdentifier seam, per-hook phasing table and the explicit "P1 image is not runnable end to end" consequence. Verification: cdk 141 suites / 2744 tests; cli 52 suites / 651 tests; tsc + eslint clean in both; types-sync green; knip at baseline (78); bootstrap generation and docs sync deterministic. Refs aws-samples#645 Co-authored-by: Claude <noreply@anthropic.com>
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #689 +/- ##
=======================================
Coverage ? 91.69%
=======================================
Files ? 292
Lines ? 80689
Branches ? 7681
=======================================
Hits ? 73984
Misses ? 6705
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
I'll address the CI comments tomorrow |
…utions The lock regenerated while adding @aws-sdk/client-lambda-microvms did not honor the root resolutions field, reintroducing vulnerable brace-expansion pins (GHSA-mh99-v99m-4gvg, cleared on main in aws-samples#658) and drifting from the resolution shape CI's install produces (yaml dedupe to 2.9.0, strnum/xml-naming entries), which tripped the fail-on-mutation gate. Regenerated with Node 22.23.2 + Yarn 1.22.22 (CI-equivalent) via yarn install --check-files: brace-expansion collapses to patched 5.0.9 everywhere, osv-scanner 2.4.0 reports no issues, second install is byte-identical, and both workspaces stay green (cdk 2744, cli 651; tsc clean). Refs aws-samples#645 Co-authored-by: Claude <noreply@anthropic.com>
Close the 14 uncovered patch lines on PR aws-samples#689: platform-doctor repo lookup failure shapes (non-Error throw, missing table output, lookup error, empty active-repo list) and non-Error MicroVM probe formatting; orchestrate-task reconciliation task-failure path; and the agent stack's defensive missing-image-ARN invariant. Tests only, no production changes; no unreachable lines found. cli 655, cdk 2746, tsc + eslint clean in both. Refs aws-samples#645 Co-authored-by: Claude <noreply@anthropic.com>
The create-microvm-image call must match the Lambda MicroVMs API model (the AWS CLI is generated from it): architecture is ARM_64 and hooks are enable flags (run: ENABLED) with service-defined paths - not the CFN L1's string shapes the script had copied. The construct is intentionally unchanged: CFN fields are unconstrained strings with their own spec conventions, validated at deploy time. Caught while drafting the P1 verification runbook; offline tests cannot exercise API payload shapes. bash -n clean; cdk suite green. Refs aws-samples#645 Co-authored-by: Claude <noreply@anthropic.com>
krokoko
left a comment
There was a problem hiding this comment.
Thanks for this — Phase P1 of ADR-021 is thoughtfully scoped, and the write-up makes the intentional non-goals (P2 hooks / P3 suspend) easy to review against. Strategy-vs-orchestrator split, image-ARN IAM scoping, cancel ordering before the RUNTIME_ARN fallback, and the layered regional gates all look solid. CI green + strong test coverage help a lot.
Request changes
Onboard should gate on ComputeSubstrate for lambda-microvm (parity with ECS)
In cli/src/commands/repo.ts, ECS already refuses onboard when the stack wasn’t deployed with the ECS substrate. MicroVM currently only probes regional availability (ListManagedMicrovmImages), so an operator can still write compute_type=lambda-microvm against an agentcore-only stack and only fail later at RunMicrovm.
Suggest mirroring the ECS check (and the onboard note) for lambda-microvm when ComputeSubstrate is present and not lambda-microvm. The agent stack already emits that output value.
Suggestions (non-blocking / nice-to-have in this PR)
-
microvm_suspend_anomalyspam —reconcileMicrovmSubstrateStateemits on every poll (~30s) while suspended outsideAWAITING_APPROVAL. Rare in P1 (no Suspend grants), but once it hits it can flood events for a long window. Emitting once per task (e.g. aPollStateflag) would keep “no fail-fast” without the noise — especially useful before P3. -
Orphan MicroVM if persist fails after
RunMicrovm—start-sessionstarts the VM, then writescompute_metadata; the catch pathfailTasks withoutTerminateMicrovm. Same race as AgentCore/ECS, but MicroVM cost/quota makes the leak more expensive. Best-effort terminate from the in-memory handle in the catch would close it. Fine as a follow-up issue if you’d rather not expand this PR. -
Shared payload-bucket read —
payloadBucket.grantRead(executionRole)is bucket-wide (incl. list), same shape as ECS #502. Scoping to the task key / droppingList*would improve isolation when this backend is enabled; also fine as follow-up. -
Incomplete
RunMicrovmresponse — the missingmicrovmId/endpointthrow isn’t wrapped withwrapMicrovmError, so it may miss the MicroVM classifier marker. Small consistency fix.
What looks great
- Exact 16 384 inline/S3 payload split,
idlePolicyomitted, 28800s max duration - Terminal substrate + DDB re-read before fail; suspend + approval treated as healthy
- No Suspend/Resume/auth-token grants; bootstrap deploy-time only with golden policy block
- Packaging script API shapes aligned with the service model
- Knip unexports are fine hygiene
Happy to re-review quickly once the onboard gate lands — and open to deferring 2–3 to tracked follow-ups if you prefer to keep this PR tight.
…aws-samples#645) A live verification run (us-east-1) proved five constants/assumptions wrong against the real Lambda MicroVMs service; a provenance review traced each to its source; PR aws-samples#689 review requested an onboard gate. This lands all corrections: Live-service fixes: - RunMicrovm requires an image ARN: construct injects the derived ARN as MICROVM_IMAGE_IDENTIFIER; strategy validates via assertImageArn before the payload upload - runHookPayload cap is 4096 bytes (docs/SDK prose say 16384 - AWS docs tickets filed): boundary tests at 4096/4097; S3 pointer is now the dominant path - VPC_EGRESS connectors require an operator role (live 400 refuted the service-linked-role comment): shared operator role on both connectors, probe-validated policy shape - Ingress defaults to a PUBLIC HTTP_INGRESS connector: NO_INGRESS is now an explicit, all-or-nothing control (required construct prop, unconditionally injected env, region-derived strategy fallback); tests assert the outcome, not field omission - minimumMemoryInMiB is a BASELINE capped at 8192 MiB with automatic 4x vertical scaling to a 32 GiB peak - validated prop + reframed ADR/docs (the 32 GB launch figure is the peak, not the input) - Agent now serves /aws/lambda-microvms/runtime/v1/ready and /run (the service refuses lifecycle hooks without /ready; a hook-less image cannot accept runHookPayload): /run reuses the /invocations background-spawn path; hooks re-phased ready+run into P1 - Image builds need port 80 (apt): separate build-time egress connector + SG; runtime stays 443-only - Script: ARM_64/ENABLED shapes, banner before+after create, ERR trap Review items (PR aws-samples#689): - Onboard gates on the stack's ComputeSubstrate output for lambda-microvm (ECS parity) via a shared comma-membership helper, ordered before the availability probe - microvm_suspend_anomaly emits once per episode (PollState flag, re-arms on recovery, carries through poll failures) - Orphan MicroVM reaped best-effort when startSession succeeds but persistence fails (both windows: orchestrator catch and strategy missing-endpoint), never masking the original error - Incomplete RunMicrovm response wrapped with the MicroVM classifier marker ADR-021 amended in place (proposed): 4 KB payload, baseline/peak memory, explicit-ingress security row, hook re-phasing, TERMINATED as the load-bearing terminal signal (NotFound is late), source-hierarchy note for externally-sourced service facts. Mirror regenerated. Verification: cdk 2796, cli 683, agent pytest 1322; tsc/eslint/ruff clean; docs sync idempotent. Refs aws-samples#645 Co-authored-by: Claude <noreply@anthropic.com>
|
Thanks @krokoko — all four items addressed in 250ca12, plus important context: a live verification run against the real service (us-east-1) landed between your review and this push, and it invalidated several things both of us believed. Point-by-point first, then the delta. Blocking — ComputeSubstrate onboard gate: done, with ECS parity via a shared Suggestion 1 (anomaly spam): implemented — Suggestion 2 (orphan MicroVM): implemented in-PR — best-effort Suggestion 3 (bucket-wide read): follow-up issue as you offered — filing it against BOTH backends (it's the #502 shape) with a concrete proposal: drop Suggestion 4 (unwrapped throw): wrapped with The live-run delta (things your "looks great" list can no longer say): the 16 384 payload split is now 4 096 — the service enforces it; the 16 KB figure in AWS's own docs/SDK prose is wrong and we've filed documentation tickets. Ingress: omitting the field attaches a public HTTP_INGRESS connector, so NO_INGRESS is now an explicit all-or-nothing control with outcome-asserting tests. Memory: Ready for re-review. |
…feat/645-lambda-microvm-p1 Brings the carved orchestration arc (reconciler, release/rollup, DAG core, iteration heartbeat/reply, Linear issue-context surface, ECS rightsized planning, the agent runtime refresh) onto the Lambda MicroVMs P1 branch. Both change sets survive semantically; every aws-samples#645 behaviour is intact. Textual conflicts (5) 1. cli/src/platform-doctor.ts — three hunks, all UNION. The import block (microvm availability vs Linear auth health), RunPlatformDoctorOptions (lambdaMicrovmClientFactory vs linearProbe/linearVerifyRefresh), and the check list. Ordering: the conditional MicroVM check first, then the Linear auth check, because the MicroVM check is gated on the active-repo scan that already ran and neither test asserts an index — both suites look checks up by `id`. The auto-merged `listRepoConfigs`/`loadActiveRepos` refactor from this branch is what feeds that gate; upstream's `countActiveRepos` call site is gone, which is why the removal of that helper stays valid. 2. cdk/src/handlers/shared/error-classifier.test.ts — one hunk, an accidental collision: this branch appended the MicroVM describes immediately above the `// --- Environmental blockers (aws-samples#251) ---` banner that aws-samples#695 was de-referencing. Kept both blocks and took upstream's banner wording. 3. cdk/src/stacks/agent.ts — this branch hoists `const computeType` to the top of the constructor (TaskApi needs it for the conditional MicroVM cancel grant); aws-samples#695 reworded the comment around its original declaration. Kept the hoist (a second declaration would not compile) with upstream's wording, and said in the comment where the local now lives. 4. agent/tests/test_server.py — both sides appended a class at end of file. UNION: the MicroVM `/ready` + `/run` hook suites, then upstream's `TestInvocationParamContract`. 5. yarn.lock — the brace-expansion resolution key (`^5.0.8` here vs `^5.0.9` upstream). Took upstream's, matching the root package.json the merge resolved to `^5.0.9`. Regenerated with the CI toolchain (Node 22.23.2 + Yarn 1.22.22): `yarn install --check-files` leaves the merged lock byte-identical, and a second `--frozen-lockfile` install is a no-op, so the lock is exactly what CI produces. Semantic adaptations (no textual conflict) - cdk/src/handlers/shared/validation.ts — RESTORED `MIME_TO_EXTENSION`'s export plus `EXTENSION_TO_MIME` and `SUPPORTED_ATTACHMENT_EXTENSIONS_LABEL`. This branch removed them as dead code (knip); aws-samples#695's S4 `linear-attachments.ts` is their consumer, so the removal became a compile error the textual merge could not see. Restored verbatim from the merge base, including the docstrings that explain the derivation. - cdk/src/handlers/shared/compute-strategy.ts — widened the `readOnly` docstring: it said only AgentCore ignores the flag, and the merged tree has two fixed-size substrates. Comment only; `lambda-microvm` correctly ignores it (one microVM shape, no second tier to route to). Checked and confirmed unaffected - Poll loop / PollState: aws-samples#695 did not touch TaskStatus or restructure the poll step, so the MicroVM substrate cross-check and the `microvmSuspendAnomalyReported` threading re-seated as-is alongside the ECS block; the new `readOnly` field lands on the same `startInput`. - ECS task sizing (S2): `ecsConfig.planningTaskDefinitionArn` became required. It auto-merged into the same TaskOrchestrator call as `microvmConfig`; both props coexist and all three synth configurations pass. - Agent server spawn seam: `_extract_invocation_params` → `_validate_required_params` → `_spawn_background` all survive aws-samples#695, so the `/run` hook needed no rework and inherits the new `base_branch` / `merge_branches` / `build_command` / `lint_command` fields for free. - `ComputeSubstrate` stack output and `cli/src/compute-substrate.ts` untouched by aws-samples#695 — the three-value gate assumption still holds. - Error-classifier ordering intact: the five marker-anchored MicroVM entries stay above `Session start failed`; aws-samples#695's three new entries stay above `Task did not succeed.*agent_status=`. - The other un-exports on this branch (`API_KEY_SECRET_BYTES`, `COMMENT_TRIGGER_MENTION`, `MAX_MARKDOWN_HEADING_LEVEL`, `DEFAULT_MAX_COMMENTS`, `ErrorClassType`, `countActiveRepos`) have no consumer in aws-samples#695. Verification (Node 22.23.2 / Yarn 1.22.22 / uv 0.12.1) - cdk jest: 178 suites, 3736 tests pass (1 snapshot). - cli jest: 55 suites, 722 tests pass. - agent pytest: 1460 pass, coverage 82.15% (floor 72%). - tsc: cdk + cli clean. eslint --fix: cdk + cli, no mutation. - ruff check / ruff format --check / ty / vulture: clean. - cdk synth: default (agentcore), `-c compute_type=ecs`, and `-c compute_type=lambda-microvm` all exit 0. - bootstrap artifacts: regeneration is a no-op (deterministic). - docs: starlight sync is a no-op, astro check 0/0/0, astro build 74 pages, link-check clean. - drift prevention: constants-sync, types-sync (62 CLI / 76 CDK exports), coverage-thresholds-sync, abca-commands sync all clean. - jira-forge-app: 9/9 pass. - knip ratchet (advisory, `continue-on-error` in CI): 98 vs baseline 78. Measured the attribution rather than assuming it: this branch's tip is at exactly 78, upstream/main alone is at 108, and the merge result is 98. All 20 findings over baseline sit in files aws-samples#695 introduced (13 unused exported types in the orchestration modules, 6 unused exports, `RefreshVerifyResult`); none are in MicroVM code. The merge therefore inherits main's overage and lands 10 below it, because this branch's un-exports still apply. Baseline left at 78 — its contract is to be lowered when dead code is removed, and raising it here would launder a pre-existing main regression. Refs aws-samples#645
Ecosystem advisories against pre-existing pins (main's weekly security scan fails identically), gating this PR: - agent/uv.lock: cryptography 49.0.0 -> 50.0.0 (GHSA-g6cj-pr64-35w5, High; transitive via mcp[crypto] -> pyjwt), minimal uv lock --upgrade-package - integrations/jira-forge-app: fast-uri 3.1.5, undici 7.29.0 (transitive via @forge/manifest) - yarn.lock: 9 further advisories cleared via existing-style root resolutions for fast-uri, ip-address, undici; lock regenerated with the CI toolchain (Node 22.23.2 + Yarn 1.22.22) and verified byte-stable across repeated installs osv-scanner: no issues found. Suites re-verified after resolution changes: cdk 3736, cli 722, agent 1460, jira-forge 9; tsc clean. Refs aws-samples#645 Co-authored-by: Claude <noreply@anthropic.com>
|
Housekeeping since the last comment, for re-review context:
|
|
LGTM ! @dreamorosi thank you for this, could you please just rebase onto current main since there are conflicts and I'll pprove after ! |
Resolve the four dependency files with upstream's aws-samples#711, aws-samples#717, and aws-samples#718 remediation as canonical. Take upstream agent/uv.lock, Jira package-lock.json, and root package.json verbatim, then regenerate yarn.lock with Node 22.23.2 and Yarn 1.22.22 to retain the Lambda MicroVM SDK entries. Refs aws-samples#645
|
@krokoko conflicts resolved in Resolution was clean: the conflicts were confined to the four dependency files where your team's canonical osv remediation (#711) + resolution pruning (#717) + drift guard (#718) collided with this branch's stopgap fix for the same advisories. Took main verbatim for all four, then regenerated |
Reconcile solution attribution and immutable agent image pins with the Lambda MicroVM backend. Preserve the MicroVM routing, grants, cancellation ordering, CLI checks, and hook routes while extending attributed SDK factories to the MicroVM clients. Refs aws-samples#645
|
@krokoko conflicts with current main resolved again in |
Implements Phase P1 of ADR-021 (#688): the
lambda-microvmcompute backend — strategy (start/poll/stop), CDK infrastructure, bootstrap policy, CLI support, and layered regional-availability enforcement. AgentCore remains the default. Suspend/resume is P3; agent-side hook serving and smoke parity are P2 — the ADR and the construct both warn explicitly that a P1-built image is not runnable end to end.Strategy reports, orchestrator interprets
LambdaMicrovmComputeStrategy.pollSessionmaps the six-stateMicrovmStateenum mechanically (SessionStatusgains'suspended'); the orchestrator cross-references DynamoDB — substrate-terminal + non-terminal status → failed (with a confirm re-read to avoid failing a successful fast teardown),suspended+ non-AWAITING_APPROVAL→ anomaly event, no fail-fast.RunMicrovmalways omitsidlePolicy(auto-suspend disabled by construction, asserted by tests) and pinsmaximumDurationInSecondsat 28 800 s (AgentCore 8 h parity). Strategy errors carry aMicroVM <op> failedmarker so the new classifier entries cannot change agentcore/ECS retry semantics — pinned by regression tests against the pre-changeUNKNOWNshape.No image wildcards in IAM
Every grant is scoped to the exact image ARN (bare names are resolved via
formatArn; a':*'sibling covers version-qualified forms — image names cannot contain:).microvmConfig.imageArnis compiler-required, so the account-wide fallback cannot return silently. Orchestrator gets exactlyRunMicrovm/GetMicrovm/TerminateMicrovm/PassNetworkConnector+ scopediam:PassRole; the cancel Lambda getsTerminateMicrovmonly; no Suspend/Resume/auth-token grants anywhere (P3), asserted by tests including on the generated bootstrap JSON.Regional availability enforced in layers
Synth-time gate on the 5 launch regions with a
microvm_region_overrideescape hatch (token regions skipped, documented); CLI onboarding probesListManagedMicrovmImageson the effective compute type (flag ?? stored ?? default) before any write;platform doctorprobes when an active blueprint uses the backend; orchestration-time classification is non-retryable with a configuration remedy.Cancellation ordering fix worth reviewer attention
The new
lambda-microvmbranch incancel-task.tsis deliberately placed before theagentRuntimeArnfallback:RUNTIME_ARNis set stack-wide whenever AgentCore stop is wired, so a MicroVM task would otherwise have invokedStopRuntimeSessionagainst an unrelated runtime in mixed deployments. Pinned by a regression test.ADR-021 refined in place (
proposed): six-state poll-mapping table,GetMicrovmNotFound →completedrationale,microvmId/microvmIdentifierseam, per-hook phasing table.Verification: cdk 141 suites / 2 744 tests, cli 52 / 651, tsc + eslint clean in both, types-sync green, knip at baseline (78), bootstrap generation and docs sync deterministic.
DEPLOYMENT_ROLES.mdgains golden policy block [5] with test parity.Refs #645