feat(dev): lambda-invoke shim — HTTP stand-in for the prod Lambda transport#129
Merged
Conversation
Mount POST /__mirrorstack/lambda-invoke on the module's dev HTTP server (never in Lambda mode): dispatch's localHTTPInvoker POSTs LambdaRequest envelopes there via MS_MODULE_LAMBDA_DEV_URL, and the shim feeds them through the same runtime.NewLambdaHandler closure production uses. Because NewLambdaHandler injects the envelope's typed identity into ctx before any router middleware runs — and on the dev HTTP path PlatformAuth passes preset identity with no secret check — the shim gates itself on the envelope's X-MS-Internal-Secret against a dedicated module-side MS_LAMBDA_INTERNAL_SECRET (the MS_PLATFORM_TOKEN chain carries the per-session tunnel token, which lambda envelopes never hold): enforce with constant-time compare when set, 503 fail-closed when a platform secret is configured without it, bypass only when nothing is configured (plain `mirrorstack dev`, matching every other guard). Gate rejections use outer 4xx/5xx (dispatch treats >=300 as a transport fault); a delivered invoke is always outer 200 with the module's status inside the envelope. Self-targeting envelopes are rejected outright. NewLambdaHandler now marks its synthetic request payload-trusted (auth.WithPayloadTrust, context-only — never settable from inbound data), and RequireProxy honors the mark with the Lambda-mode pass-through, so Public/Platform routes stop 403ing not_proxied through the shim under the standard MS_PLATFORM_TOKEN_FILE dev-runner config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019grh7whQS1xhPfQpaZ4bNG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
POST /__mirrorstack/lambda-invoke(dev/HTTP mode only, never mounted in real Lambda mode): dispatch'slocalHTTPInvoker(MS_MODULE_LAMBDA_DEV_URL) POSTs theLambdaRequestenvelope here, and the shim feeds it through the sameruntime.NewLambdaHandler(m.router)closure production uses — so a locally "deployed" module is served through the real envelope path with zero module-code changes. This is the dev shimapi-platform lambda_transport.goalready anticipated.Trust gate (the important part)
NewLambdaHandlerinjects the envelope's typeduserId/appId/appRole/appSchemainto ctx as trusted identity, and PlatformAuth honors preset identity with no secret check — so an ungated shim would let any local caller forge admin identity. The shim gates itself BEFORE invoking the handler, mirroring internalAuth's matrix:MS_LAMBDA_INTERNAL_SECRETset → constant-time compare against the envelope'sX-MS-Internal-Secret(dispatch injects it on every invoke); 401 on mismatchmirrorstack dev, where this surface is already open by prior design)Dedicated env var because the dev runner points
MS_PLATFORM_TOKEN[_FILE]/MS_INTERNAL_SECRETat the per-session tunnel token / log-shipper secret — neither is what dispatch puts in envelopes. Self-targeting envelopes are rejected outright; rejections use outer HTTP statuses (dispatch treats ≥300 as a generic transport fault, so nothing leaks).Also adds
auth.WithPayloadTrust(context-only, set solely byNewLambdaHandler):RequireProxygives payload-trusted requests the same pass-through as Lambda mode — without it every Public/Platform route 403snot_proxiedthrough the envelope path wheneverMS_PLATFORM_TOKEN_FILEis set.Verification
not_proxied,x-ms-*identity-header stripping preserved.module_deploysrow for oauth-core): dispatch/v1/apps/twkpa-edu/oauth-core/public/me→ shim (POST /__mirrorstack/lambda-invoke 200+ envelope identity in module logs) → correct response; flipping the deploy row todisabledfalls back to the WSS tunnel; oauth-google (no deploy row) stayed on the tunnel throughout.🤖 Generated with Claude Code