fix: local PropagateTags: false is not overridden by global PropagateTags: true - #3978
fix: local PropagateTags: false is not overridden by global PropagateTags: true#3978Adityaj0 wants to merge 1 commit into
Conversation
…Tags: true
ImplicitApiPlugin._add_tags_to_implicit_api_if_necessary() decided whether to
copy Tags onto the generated implicit API resource with:
resource.properties.get("PropagateTags") or globals_var.get("PropagateTags")
PropagateTags is bool | None, where None means "not set" and False is a
meaningful, explicit opt-out. `or` treats a local False the same as "not
set" and silently falls through to the global value, so an explicit
`PropagateTags: false` on a function is overridden by a global
`PropagateTags: true`, propagating tags the caller explicitly opted out of.
This checks for None instead, matching the "local wins when present"
semantics that GlobalProperties._prefer_local already uses for the
standard Globals merge.
Fixes aws#3977
There was a problem hiding this comment.
Code Review Results
Reviewed: bbc6a9a..2fb8a84
Files: 5
Comments: 1
Comments on lines outside the diff:
[samtranslator/plugins/api/implicit_api_plugin.py:115] [BUG] The PropagateTags precedence fix on the lines above is right, but the Tags line immediately below has the analogous precedence problem and is left unchanged. or makes a resource-level Tags value fully replace the global one, whereas the documented Globals behavior for dictionaries (see GlobalProperties._merge_dict in samtranslator/plugins/globals/globals.py) is a recursive merge.
Concretely:
Globals:
Function:
Tags:
env: prod
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
PropagateTags: true
Tags:
app: foo
Events:
ApiEvent:
Type: Api
Properties: {Path: /, Method: get}The function and its generated resources end up with {env: prod, app: foo} (Globals merges, then propagate_tags runs), but ServerlessRestApi only receives {app: foo} because resource.properties.get("Tags") is truthy and the global Tags are never consulted. The global tag is silently dropped from the implicit API — the same class of "local silently discards global" bug this PR is fixing for PropagateTags.
Since the implicit API plugin runs before the Globals plugin, the merge has to be done explicitly here:
tags_properties = {**(globals_var.get("Tags") or {}), (resource.properties.get("Tags") or {})}Note this assumes both are dicts, which the existing code already assumes (see the setdefault("Tags", {}).update(tags_properties) call below and its accompanying comment), so guarding for intrinsics is no worse than today. If you'd rather keep this PR minimal, that's reasonable — but it's worth splitting out rather than leaving, since the two lines now encode inconsistent global/local rules side by side.
Summary
Fixes #3977.
ImplicitApiPlugin._add_tags_to_implicit_api_if_necessary()decided whether to copy a resource'sTagsonto its generated implicitAWS::Serverless::Api/HttpApiresource with:PropagateTagsisbool | None(see the Pydantic schema insamtranslator/internal/schema_source/aws_serverless_function.py), whereNonemeans "not set" andFalseis a meaningful, explicit opt-out.ortreats a localFalsethe same as "not set," so it silently falls through to the global value — a function with an explicitPropagateTags: falsestill gets tags propagated to its implicit API if a globalPropagateTags: trueis set.This checks
is not Noneinstead, so an explicit local value (includingFalse) always wins over the global, consistent with the "local wins when present" semanticsGlobalProperties._prefer_localalready uses for the standard Globals merge (samtranslator/plugins/globals/globals.py).Test plan
tests/translator/input/function_with_local_propagate_tags_false_overrides_global_true.yaml(localPropagateTags: false+ globalPropagateTags: true+ globalTags) with expected output for all three partitions (aws,aws-cn,aws-us-gov), asserting the implicit API resource has noTags.python -m pytest tests/translator tests/plugins tests/parser— 2581 passed (same 5 pre-existing, unrelated SAR-timing/region failures as ondevelop).ruff check/black --checkclean on the changed file.