AppTheory 2.0 MicroVM Runtime Logging
AppTheory 2.0 makes Lambda MicroVM runtime logging explicit for every RunMicrovm operation. A deployment must choose
exactly one posture:
- send guest runtime output to CloudWatch Logs; or
- disable runtime logging explicitly.
Omission is not a default. It is invalid configuration and fails closed. The controller owns the choice for every run; an HTTP caller cannot provide or override it.
This is a breaking change for deployments that construct an AppTheoryMicrovmImage, pass a structural
IAppTheoryMicrovmImage reference, create a real controller directly in tests, or invoke the constrained provider
surface directly.
Why this changed
A controlled Factory EqualToAI lesser-host A/B held the image version, execution role, network connector, duration, and
log group constant. The AppTheory 1.x-shaped request that omitted the AWS Logging union ran without creating a stream
or delivering events. The otherwise identical request with explicit CloudWatch logging continuously delivered guest
stdout.
That result proves omission is not a deterministic logging fallback. AppTheory therefore does not inherit, guess, or silently default the per-run posture.
Migration checklist
- Choose CloudWatch or explicit disabled logging for every MicroVM image.
- Add the choice to
AppTheoryMicrovmImage.logging. - If CloudWatch is selected, pass a MicroVM
executionRoletoAppTheoryMicrovmController. - Grant that execution role the required CloudWatch Logs actions and Lambda trust described below.
- Add
loggingto every imported or structuralIAppTheoryMicrovmImagereference. - Remove any request field, custom environment override, or raw SDK call that lets an HTTP caller choose logging.
- Re-synthesize and validate through the AppTheory CDK and contract gates.
- Have Factory run the external lesser-host acceptance check after the AppTheory milestone is ready.
Do not replace these steps with a raw AWS SDK call. If the AppTheory surface cannot express a future logging mode, grow the shared contract first.
CloudWatch mode
Set the image logging posture and supply the controller’s MicroVM execution role:
const image = new AppTheoryMicrovmImage(this, "MicrovmImage", {
// Other required image props omitted.
logging: {
cloudWatch: {
logGroup: "/aws/lambda/microvms/my-service",
logStream: "runtime",
},
},
});
new AppTheoryMicrovmController(this, "MicrovmController", {
// Other required controller props omitted.
microvmImage: image,
executionRole: microvmExecutionRole,
});
AppTheoryMicrovmController serializes the normalized choice into the reserved
APPTHEORY_MICROVM_LOGGING environment variable. The real Go, TypeScript, and Python controllers read it and pass the
corresponding logging union to every provider Run request. Do not set this environment variable through
controller.environment; the construct rejects reserved-key overrides.
The MicroVM execution role is separate from the image build role and the controller Lambda’s own role. It must:
- trust
lambda.amazonaws.comforsts:AssumeRole; - allow
sts:TagSessionin the trust policy; and - allow
logs:CreateLogGroup,logs:CreateLogStream, andlogs:PutLogEvents.
See the AWS Lambda MicroVM security and permissions guide
and the runnable role wiring in examples/cdk/microvm-controller.
AppTheory grants the controller permission to pass the supplied role. It does not inspect or mutate arbitrary role policies, so synthesis cannot prove that an imported or later-mutated role contains the Logs permissions. A missing permission remains a deployment/operator error and must be corrected on the role supplied to the AppTheory construct.
Disabled mode
When runtime output must not be delivered, disable it explicitly:
const image = new AppTheoryMicrovmImage(this, "MicrovmImage", {
// Other required image props omitted.
logging: { disabled: true },
});
Disabled mode does not require AppTheoryMicrovmController.executionRole for logging. Do not use {}, disabled:
false, or an omitted property as a disabled shorthand; each is invalid.
Imported image references
IAppTheoryMicrovmImage now includes the normalized logging posture. Structural references must migrate from:
const image: IAppTheoryMicrovmImage = {
microvmImageArn: importedImageArn,
};
to one explicit shape:
const image: IAppTheoryMicrovmImage = {
microvmImageArn: importedImageArn,
logging: {
cloudWatch: {
logGroup: "/aws/lambda/microvms/my-service",
logStream: "runtime",
},
},
};
or:
const image: IAppTheoryMicrovmImage = {
microvmImageArn: importedImageArn,
logging: { disabled: true },
};
CloudWatch structural references have the same execution-role requirement as construct-created images.
Direct runtime construction in tests
Production deployment stays on AppTheoryMicrovmImage plus AppTheoryMicrovmController. Tests that construct the real
controller without CDK must now provide the same union explicitly:
| Runtime | Test/configuration surface |
|---|---|
| Go | microvm.WithControllerLogging(microvm.ProviderLogging{Disabled: true}) or a CloudWatch member paired with WithControllerExecutionRoleArn(...) |
| TypeScript | createRealMicroVMController(provider, registry, { logging: { disabled: true } }) or CloudWatch logging paired with execution_role_arn |
| Python | create_real_microvm_controller(provider, registry, logging={"disabled": True}) or CloudWatch logging paired with execution_role_arn |
Direct constrained-provider tests must also populate the required ProviderRunInput.logging /
MicroVMProviderRunInput.logging field. These are test and runtime contract surfaces, not permission to bypass the
AppTheory controller in a deployment.
Failure modes
| Configuration | Result |
|---|---|
| Logging omitted | CDK synthesis or real-controller construction fails closed. |
| CloudWatch and disabled both set | Validation fails closed. |
disabled set to false |
Validation fails closed. |
| CloudWatch selected without an execution role | CDK synthesis or real-controller construction fails closed. |
| Invalid log group or stream | Validation fails closed before the provider call. |
Caller includes logging in POST /microvms |
The request cannot replace the deployment-owned posture. |
controller.environment overrides APPTHEORY_MICROVM_LOGGING |
CDK synthesis fails closed. |
| Execution role lacks required Logs permissions | Synthesis may pass, but live log delivery fails; fix the supplied role. |
When guest output is dark, do not infer that image-level settings were inherited. Inspect the deployed image logging posture, the reserved controller environment value, the controller execution role, and CloudWatch permissions together.
Acceptance and evidence boundary
Repository gates prove the fixture-backed union, cross-language provider mapping, controller ownership, CDK serialization, and generated bindings. They do not perform a live AWS deployment.
Factory EqualToAI owns the external lesser-host acceptance run. That run should hold the image version, execution role, network connector, duration, and destination constant while verifying that the AppTheory 2.0 CloudWatch path delivers guest output. The existing conformance harness can scan supplied logs for leaks, but it does not provision CloudWatch logging or independently prove delivery.
Release and validation
AppTheory releases are immutable GitHub Releases. Pin the published v2.0.0 release asset when it is available; do not
substitute an npm or PyPI publication path.
Validate a migrated source tree with:
./scripts/verify-contract-tests.sh
./scripts/verify-cdk-constructs.sh
./scripts/verify-cdk-go.sh
./scripts/verify-cdk-synth.sh
make rubric
Related guidance: