Skip to content

fix: generate the try-it encryption key without a backslash escape - #2851

Merged
timbastin merged 1 commit into
l3montree-dev:mainfrom
sujeito-operator:fix-try-it-key-generation-escape
Aug 14, 2026
Merged

fix: generate the try-it encryption key without a backslash escape#2851
timbastin merged 1 commit into
l3montree-dev:mainfrom
sujeito-operator:fix-try-it-key-generation-escape

Conversation

@sujeito-operator

Copy link
Copy Markdown
Contributor

Fixes #2841.

docker-compose-try-it.yaml line 21 writes the app-side encryption key with

od -vN 32 -An -tx1 /dev/urandom | tr -d ' \n'

On Docker Compose before v5.2.0 the \n never reaches tr as a newline. A
command: given as a string is split by shellwords.Parse (compose-go,
types/command.go), and go-shellwords v1.0.12 — the version in every Compose go.mod
I read from v2.20.0 through v5.1.0 (10 tags) —
drops the backslash and keeps the letter. The container runs tr -d ' n', which deletes
spaces and the letter n and leaves od's two line breaks in the file. go-shellwords
v1.0.13 turns the same escape into a real newline instead, and Compose picked that up in
v5.2.0; that is why the result depends on which binary you run, and why the same
command typed into docker run alpine is fine.

Measured by feeding this file's own command: scalar through shellwords.Parse at each
version and executing the argv it produces under busybox sh:

shellwords   file          key size   line breaks
v1.0.12      as-is         66 bytes   2
v1.0.13      as-is         64 bytes   0
v1.0.12      this patch    64 bytes   0
v1.0.13      this patch    64 bytes   0

The 66-byte key is what takes the API down. buildGCM
(services/db_encryption_service.go) calls bytes.TrimSpace, which removes the trailing
newline only; the one at offset 32 stays, and hex.Decode then returns
encoding/hex: invalid byte: U+000A after 16 of 32 bytes, so LoadDBEncryptionKey panics on startup.

The patch replaces the escape rather than repairing it. tr -dc '0-9a-f' keeps only hex
digits and contains no backslash, so no YAML, Compose or shell layer can change its
meaning — the table above shows it is correct under both parser generations. It is also
strictly tighter than the original: nothing but a hex digit can enter the key whatever
od emits.

One line, one token. Nothing else in the file is touched, and the pattern does not occur
anywhere else in the repository.

Written by an automated agent. Every figure above is a command re-run by the script that
opened this pull request, not a recollection; it refuses to open if any of them drifts.

`docker-compose-try-it.yaml` generated the key with `tr -d ' \n'`. A string `command:` is
split by go-shellwords before any shell sees it, and the version pinned by every Compose
release through v5.1.0 drops the backslash and keeps the letter, so the
container ran `tr -d ' n'` and od's two line breaks stayed in the key. TrimSpace in
buildGCM removes only the trailing one, so hex.Decode fails on the newline at offset 32
and the API panics on startup.

`tr -dc '0-9a-f'` keeps only hex digits and carries no escape for any layer to consume.

Fixes l3montree-dev#2841

Signed-off-by: Sujeito Operator <[email protected]>
@timbastin

Copy link
Copy Markdown
Member

Wow that was great! Thanks a lot. Spot on!

@timbastin
timbastin merged commit a0b5c59 into l3montree-dev:main Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docker compose setup script creates line wrapped encryption key causing API to fail

2 participants