Summary
On osls 4.0.0 there is no way to resolve ${ssm:} during local development without live AWS credentials, the community workaround that used to provide one has silently stopped working.
serverless-offline-ssm made credential-free local development work by monkeypatching the AWS provider's generic request() method, which the built-in ssm variable source called.
The v4 upgrade guide documents the removal of provider.request() and points at the osls-aws-provider-request-shim community project for plugins broken by it, but unfortunately that shim does not help here.
The ask is to introduce a small first-party way to resolve ${ssm:} from a local map so existing serverless projects that rely on offline dev can continue to function. I am happy to contribute it.
Reproduction
https://github.com/farmersdog/ssm-repro — ./run.sh from a clean clone installs pinned versions, runs four independent cases, and prints a summary table:
- osls 3.76.1 — the mock map applies,
${ssm:} resolves, exit 0.
- osls 4.0.0 — byte-identical config and plugin list, exit 1 with the error above, banner still printing.
osls-aws-provider-request-shim@1.0.1 — byte-identical to case 2 in both plugin orderings. A probe subclass shows why: the shim's constructor runs, but its initialize hook never fires, because resolution has already failed. A control config with no ${ssm:} reference logs both.
- Cross-stage
params: — a ${ssm:} reference reachable only via params.prod fails at --stage dev. Not a v4 regression; see below.
Every case runs with the credential chain fully neutralized (all AWS_* credential and profile variables unset, HOME pointed at an empty directory, IMDS disabled) and asserts the failure is AWS provider credentials not found, not a misconfigured-profile error, so an incomplete strip can't be mistaken for a result.
Not specific to print — resolution is a hard gate ahead of every command, so invoke local, package and serverless-offline fail identically.
Root cause
serverless-offline-ssm@6.2.0/dist/resolver.js:23-39 patches provider.request, filtering for ('SSM', 'getParameter').
osls@3.76.1 called exactly that: lib/configuration/variables/sources/instance-dependent/get-ssm.js:30-38.
osls@4.0.0 does not. The same get-ssm.js builds the client itself (:4, :10-12, :39 — SSMClient / GetParameterCommand) and sends via create-cached-aws-variable-source-command-sender.js:80. The provider is consulted only for getRegion() and getAwsSdkV3Config().
lib/plugins/aws/provider.js:1713-1715 makes provider.request a throwing stub.
The plugin patches a method the SSM source no longer calls, the patch is never exercised, and nothing warns. Timing rules out any userland fix: resolution runs at scripts/serverless.js:649, await serverless.run() — the earliest a lifecycle hook can fire — only at :687.
What I'd like
Preferred: an offline mock map consulted before the SDK call in get-ssm.js. A custom block or an env var pointing at a JSON file of parameter path → value; on a hit, return it and never construct the client.
custom:
ssmOffline:
'/dev/demo/api-token': mock-value
or SLS_SSM_OFFLINE_FILE=./ssm.local.json.
There some decisions needed on whether misses fall through to real SSM or fail closed, whether the env-var form should be the only one to keep it out of the config schema, and whether an explicit opt-in flag should be required so a stray map file can't affect a deploy.
Environment
osls@4.0.0 vs osls@3.76.1; serverless-offline-ssm@6.2.0; osls-aws-provider-request-shim@1.0.1 (tested, does not apply); node 22.22.2; Linux; no AWS credentials of any kind.
Thanks for maintaining this fork and considering this change.
Summary
On osls 4.0.0 there is no way to resolve
${ssm:}during local development without live AWS credentials, the community workaround that used to provide one has silently stopped working.serverless-offline-ssmmade credential-free local development work by monkeypatching the AWS provider's genericrequest()method, which the built-inssmvariable source called.The v4 upgrade guide documents the removal of
provider.request()and points at theosls-aws-provider-request-shimcommunity project for plugins broken by it, but unfortunately that shim does not help here.The ask is to introduce a small first-party way to resolve
${ssm:}from a local map so existing serverless projects that rely on offline dev can continue to function. I am happy to contribute it.Reproduction
https://github.com/farmersdog/ssm-repro —
./run.shfrom a clean clone installs pinned versions, runs four independent cases, and prints a summary table:${ssm:}resolves, exit 0.osls-aws-provider-request-shim@1.0.1— byte-identical to case 2 in both plugin orderings. A probe subclass shows why: the shim's constructor runs, but itsinitializehook never fires, because resolution has already failed. A control config with no${ssm:}reference logs both.params:— a${ssm:}reference reachable only viaparams.prodfails at--stage dev. Not a v4 regression; see below.Every case runs with the credential chain fully neutralized (all
AWS_*credential and profile variables unset,HOMEpointed at an empty directory, IMDS disabled) and asserts the failure isAWS provider credentials not found, not a misconfigured-profile error, so an incomplete strip can't be mistaken for a result.Not specific to
print— resolution is a hard gate ahead of every command, soinvoke local,packageandserverless-offlinefail identically.Root cause
serverless-offline-ssm@6.2.0/dist/resolver.js:23-39patchesprovider.request, filtering for('SSM', 'getParameter').osls@3.76.1called exactly that:lib/configuration/variables/sources/instance-dependent/get-ssm.js:30-38.osls@4.0.0does not. The sameget-ssm.jsbuilds the client itself (:4,:10-12,:39—SSMClient/GetParameterCommand) and sends viacreate-cached-aws-variable-source-command-sender.js:80. The provider is consulted only forgetRegion()andgetAwsSdkV3Config().lib/plugins/aws/provider.js:1713-1715makesprovider.requesta throwing stub.The plugin patches a method the SSM source no longer calls, the patch is never exercised, and nothing warns. Timing rules out any userland fix: resolution runs at
scripts/serverless.js:649,await serverless.run()— the earliest a lifecycle hook can fire — only at:687.What I'd like
Preferred: an offline mock map consulted before the SDK call in
get-ssm.js. Acustomblock or an env var pointing at a JSON file of parameter path → value; on a hit, return it and never construct the client.or
SLS_SSM_OFFLINE_FILE=./ssm.local.json.There some decisions needed on whether misses fall through to real SSM or fail closed, whether the env-var form should be the only one to keep it out of the config schema, and whether an explicit opt-in flag should be required so a stray map file can't affect a deploy.
Environment
osls@4.0.0vsosls@3.76.1;serverless-offline-ssm@6.2.0;osls-aws-provider-request-shim@1.0.1(tested, does not apply); node 22.22.2; Linux; no AWS credentials of any kind.Thanks for maintaining this fork and considering this change.