feat(lambda): expose a resolvable qualified ARN on AWS::Lambda::Version - #163
Conversation
A published AWS::Lambda::Version had no Resolvable, so nothing in a forma could reference the version's qualified function ARN. CloudFront rejects an unqualified ARN (and $LATEST) on a Lambda@Edge association, which forced callers to hardcode the ARN literal and hand-edit the pin on every publish. Add VersionResolvable with a functionArn property and wire it up as Version.res, mirroring the other Lambda resources. The new cloudfront-lambda-edge example wires a role, function, version and distribution together and resolves the association from the version.
Wires a Lambda Permission to the qualified function ARN published by a Lambda Version, so an apply fails outright if that reference cannot be resolved.
Add a `Verify examples` step to the checks job, right after `Verify schema`, so `make verify-examples` runs on every PR and catches Resolvable shape regressions in the example formae. Also record the new `AWS::Lambda::Version` functionArn resolvable in the changelog.
JeroenSoeters
left a comment
There was a problem hiding this comment.
Approved.
Reviewed the diff against the agreed design, the review ledger, and the CI result.
Head SHA 2cc7b80 is byte-identical to the SHA debug-conformance validated (run 31246285555, both lambda-version and lambda-version-ref green, pre/post-cleanup clean). That matters more than usual here: this repo's PR CI skips conformance-tests, test-integration, discover-tests and pre-cleanup, so the PR run on its own carries no conformance signal. The branch-first dispatch is the only real evidence the accessor resolves against AWS, and it covers exactly what merges.
Ledger floor is clear. Pass 2's single P2 finding (private S3 origin with an OAC but no bucket policy) is correctly rejected, and I verified both load-bearing claims independently rather than taking them on trust:
DistributionResolvable(schema/pkl/cloudfront/distribution.pkl:317-326) exposes onlyidanddomainName, no ARN. A properly scoped OAC policy needsAWS:SourceArn, which embeds the account id, so writing it would hardcode an account-id literal into an example: precisely the hand-managed pin this change exists to remove.examples/cloudfront-edge-minimal/main.pklhas no bucket policy either, so the omission is the existing house pattern, not a regression introduced here. PLA-487 to fix both together is the right call.
Merging with two documented, unfixed limitations, both stated rather than buried:
- Every field on
Versionis create-only, so a code change publishes a replacement version, and a replicated Lambda@Edge version can stay undeletable well after the association is removed. Pre-existing, borne manually today with a hardcoded ARN; PLA-459 tracks the ordering analysis. - Nothing automated deploys a live Lambda@Edge association.
lambda-version-refproves generic resolution of the qualified ARN, not CloudFront's acceptance of it. Confirming end to end remains a manual apply of the new example.
The scope extension wiring Verify examples into the checks job was confirmed on the design turn and is included.
Summary
AWS::Lambda::Versionexposed no Resolvable, so nothing in a forma couldreference a published version's qualified function ARN. That matters most for
Lambda@Edge: CloudFront rejects an unqualified ARN (and
$LATEST) on alambdaFunctionAssociationsentry, so the association had to carry theversioned ARN as a hand-written literal — and every function code change
publishes a new version and requires re-editing that pin, reintroducing exactly
the hand-managed drift IaC exists to remove.
This adds a
VersionResolvablewith a singlefunctionArnaccessor on theCloudControl read-only property
FunctionArn, exposed asVersion.res. Itmirrors the existing pattern in
func.pklandlayerversion.pkl, and names theaccessor after the CloudControl property as those do. A distribution can now
write:
The consumer side already accepted a Resolvable and carries
edgeKind = "runtimeDependency", so dependency ordering works once there issomething to point at.
Also included:
examples/cloudfront-lambda-edge/main.pkl— a worked Lambda@Edge example(role trusted by both
lambdaandedgelambda, function, version,distribution) that resolves the association rather than pinning an ARN.
testdata/lambda-version-ref.pkl— a conformance fixture whosePermission.functionNameconsumes the version'sres.functionArn, so anapply fails outright if the reference cannot resolve. Validated against real
AWS alongside the existing
lambda-versionfixture; both pass.Verify examplesstep in thechecksjob.make verify-examplesexists tocatch precisely this class of Resolvable regression but was not wired into any
workflow, so the examples could rot silently. It is
pkl evalonly — nocredentials, seconds.
Known limitation, unchanged by this PR
Every field on
Versionis create-only, so a function code change publishes areplacement version rather than updating the existing one. The safe order is
publish, re-point the distribution, wait for CloudFront to propagate, and only
then delete the old version — and a replicated Lambda@Edge version can remain
undeletable for a long time after the association is removed, which makes such a
stack slow to tear down. This hazard exists today with a hardcoded ARN; exposing
the resolvable removes the hand-edit but does not change the ordering. It is
stated in the example header and the changelog entry, and the
replacement-ordering analysis is tracked separately.
Note also that no automated test deploys a live Lambda@Edge association — edge
replica teardown blocks deletion far beyond a test's lifetime. The conformance
fixture proves the qualified ARN resolves and round-trips; it does not prove
CloudFront's acceptance of it.
res.versionis deliberately not included: no modelled field can consume ittoday (
Alias.functionVersion,Url.qualifierandEventInvokeConfig.qualifierare all bare
String, andUrl's pattern excludes a purely numeric version), soit would ship dead. Tracked as a follow-up together with widening
Alias.functionVersion.