Skip to content

Template expressions inside YAML comments are rendered and can fail the whole deployment #151

Description

@Hermsi1337

Summary

The action renders the stack/services/volumes YAML input as a Go text/template before parsing it as YAML (cmd/action/main.go, loadYamlOptional(): template.Parse at line 201, renderConfigTemplate at line 207, yaml.Unmarshal only afterwards at line 214). Since text/template has no notion of YAML, # comments are treated like any other text — template expressions inside comments are executed.

Failing scenarios (empirically confirmed)

  1. Commented-out line referencing an unset variable — the most common case, e.g. commenting out a service option:

    services:
      app:
        image: nginx
        # db_url: {{ .Env.DATABASE_URL }}

    With DATABASE_URL unset, the deploy hard-fails because of missingkey=error:

    failure while rendering template: template: :1:13: executing "" at <.Env.DATABASE_URL>: map has no entry for key "DATABASE_URL"
    

    Trailing comments (image: nginx # {{ .Env.UNSET }}) fail the same way.

  2. Comment containing invalid/partial template syntax, e.g. # see {{ or # see {{ foo }}:

    failure while creating template from input: template: :2: function "services" not defined
    

    The error is actively misleading — the parser runs past the line end, consumes the next YAML line as template code, and reports a wrong line number and an invented function name.

  3. Plain comments without {{ are harmless (confirmed), which is why this only bites once someone comments out a templated line — the most common YAML edit there is.

Both input paths are affected equally (stack_yaml/stack_file and the services/volumes variants).

Proposed fix

Strip YAML comments from the raw input before template.Parse. Comments are semantically void in YAML, so this is loss-free — but the stripper must be quote- and block-scalar-aware, because # is literal content:

  • inside single- and double-quoted scalars ("a # b", 'a # b', incl. multi-line double-quoted scalars),
  • when not preceded by whitespace (image: nginx#latest is not a comment),
  • inside block scalars (command: | followed by #!/bin/sh).

Replacing the comment text in place (keeping the newline) keeps template/YAML error line numbers accurate.

Rejected alternatives:

  • Drop missingkey=error — doesn't fix scenario 2 (parse-time failure) and removes a valuable safety net against typo'd variable names.
  • Parse YAML first, strip comments via yaml.Node — impossible; un-rendered templated input is not valid YAML (yaml: invalid map key).
  • Naive regex # strip — corrupts nginx#latest, "a # b", and shebangs in block scalars.
  • Change template delimiters — breaking change, and the new delimiters would still execute inside comments.

A note in the README ("comments are stripped before templating, {{ }} inside comments is inert") should accompany the fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions