Skip to content

Documented signature header template is invalid in .env, compose, and plain YAML #1023

Description

@alexluong

The webhook destination docs give this as the signature header template:

DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE="t={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}"

Go's template parser rejects a backslash inside an action:

raw: t={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}
PARSE ERROR: template: x:1: unexpected "\\" in operand

raw: t={{.Timestamp.Unix}},v0={{.Signatures | join ","}}
parses OK

So whether the documented value works depends entirely on what parses the line before Go sees it:

how it's set backslashes result
shell, double-quoted stripped by the shell works
Config API JSON body unescaped by the JSON parser works
YAML, double-quoted unescaped by the YAML parser works
.env file (godotenv — Outpost's own config loading — or Compose env_file:) unescaped in double-quoted values works
docker run --env-file passed through literally invalid template
docker-compose environment: passed through literally invalid template
YAML, single-quoted scalar passed through literally invalid template

(Corrected after testing: the original version of this issue claimed .env files pass backslashes through literally. Most .env readers — godotenv, which Outpost itself uses, and Compose env_file: — unescape \" inside double-quoted values, so the documented line works there; only docker run --env-file is fully literal. A plain YAML scalar can't carry these values at all — they start with {{.)

The bottom rows are ordinary ways to configure a self-hosted deployment. Copy the documented line into any of them and the template is invalid — which, before #1020's fix, panicked the delivery worker at the first delivery, and now fails startup.

The Go default is unaffected — config.go:186 is a source literal that resolves to join ",".

Suggested change

Show the template value itself, and treat escaping as a property of the transport rather than of the template:

The header template is:

t={{.Timestamp.Unix}},v0={{.Signatures | join ","}}

This is the literal template value. If the format carrying it requires escaping — the inner quotes in a JSON string or a double-quoted shell string — apply that format's own escaping.

That way the reader is given the real value once, and escaping stays the transport's concern rather than something the docs must enumerate per context.

Also: the two field sets are mutually exclusive

Separate from the escaping, the docs list content-template and header-template fields in two tables. Both are accurate, but nothing indicates that borrowing a field from the other list is an error rather than an empty value.

One table makes the exclusivity structural instead of something the reader has to infer by comparing two lists:

Field Content template Header template
.EventID yes yes
.Topic yes yes
.Timestamp yes yes
.Body yes
.Signatures yes

With a line under it stating that a field marked is not merely empty — it makes the configuration invalid.

Scope

  • docs/content/destinations/webhook.mdoc — the tables and both the Managed and Self-Hosted examples
  • docs/content/self-hosting/changelog/upgrade-v0.12.mdoc — carries the same escaped value

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationsmallLess then a day of work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions