balena-io / balena-cli

The official balena CLI tool.
Apache License 2.0
452 stars 138 forks source link

balena build bails on dockerfiles containing what it thinks are query parameters #2279

Open nbertram opened 3 years ago

nbertram commented 3 years ago

Expected Behavior

Can build dockerfiles including URLs that have query parameters

Actual Behavior

See input below, but anything that appears query-param-like is parsed into some sort of command that it isn't. It doesn't matter if it's in a comment or in a build step. In my case I want to curl a file that requires a query param to fetch, but the reproduction example below is just a comment. It doesn't even have to be a URL, any question mark with text immediately after it causes this, eg. # hello?foo will crash the build.

[debug] new argv=[/home/neil/bin/balena-cli/balena,/snapshot/versioned-source/bin/balena,build,--deviceType,raspberrypi3,--arch,armv7hf,--emulated,.] length=9
[Debug]   Parsing input...
[Debug]   Loading project...
[Debug]   Resolving project...
[Info]    No "docker-compose.yml" file found at "/tmp/balena-test"
[Info]    Creating default composition with source: "/tmp/balena-test"
[Debug]   Creating project...
[Info]    Building for armv7hf/raspberrypi3
[Build]   Building services...
[Build]   main Preparing...
[Info]    Emulation is enabled
[Debug]   Found build tasks:
[Debug]       main: build [.]
[Debug]   Resolving services with [raspberrypi3|armv7hf]
[Debug]   Found project types:
[Debug]       main: Standard Dockerfile
[Debug]   Prepared tasks; building...
[Build]   Built 1 service in 0:01
[Error]   Build failed.
(HTTP code 400) unexpected - Dockerfile parse error line 3: unknown instruction: FOO=BAR

Error: (HTTP code 400) unexpected - Dockerfile parse error line 3: unknown instruction: FOO=BAR
    at /snapshot/versioned-source/node_modules/docker-modem/lib/modem.js:315:17
    at IncomingMessage.<anonymous> (/snapshot/versioned-source/node_modules/docker-modem/lib/modem.js:342:9)
    at IncomingMessage.emit (events.js:327:22)
    at IncomingMessage.EventEmitter.emit (domain.js:482:12)
    at endReadableNT (_stream_readable.js:1221:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)
From previous event:
    at Builder.createBuildStream (/snapshot/versioned-source/node_modules/resin-docker-build/build/builder.js:72:42)
    at /snapshot/versioned-source/node_modules/resin-multibuild/build/build.js:88:21

For further help or support, visit:
https://www.balena.io/docs/reference/balena-cli/#support-faq-and-troubleshooting

Steps to Reproduce the Problem

Put this in a Dockerfile:

FROM balenalib/raspberrypi3-debian-node:14-buster-run AS run

# http://example.com?foo=bar
RUN echo hello

then in the same directory, run:

balena build --debug --deviceType raspberrypi3 --arch armv7hf --emulated .

Specifications

nbertram commented 3 years ago

OK it's even worse than I thought. This is also broken:

FROM balenalib/raspberrypi3-debian-node:14-buster-run AS run

# Is this a question? Yes it is!
RUN echo hello

Any text after a ? triggers the problem, not just query-param-like text.

Seems using escape sequences like \x3f is also not a solution, as these seem to be interpolated before whatever is misreading the dockerfile and also trigger the crash.

This cuts off several hacks around the issue, like trying to put '?' into an env var and using that instead. I've had to base64 encode the URL I want to download for now, but this is really not ideal!

pdcastro commented 3 years ago

Thank you for reporting this issue and sharing the base64 workaround @nbertram 👍

In a brief investigation, it seems to only happen on Linux (not Docker Desktop) when the --emulated flag is used. Adding console.log just after the following line:

https://github.com/balena-io-modules/docker-qemu-transpose/blob/v1.1.1/src/index.ts#L190

const newDockerfile = transpose(buffer.toString(), opts);`
console.log(`newDockerfile:\n${newDockerfile}`);

... shows that your sample Dockerfile becomes the following "transposed" version that gets sent to the Docker engine:

FROM balenalib/raspberrypi3-debian-node:14-buster-run AS run
COPY [".balena/qemu-execve","/tmp/qemu-execve"]
FOO=BAR 
RUN ["/tmp/qemu-execve","-execve","/bin/sh","-c","echo hello"]

I assume that the bug is in the docker-qemu-transpose repo. I am not working on it at the moment, but anyone else interested is invited to!

nbertram commented 3 years ago

On that basis, another workaround might be to drop using the --emulated flag and falling back on the building host's binfmt qemu-static (which we have already due to some other ARM builds). Linux-specific though.

When I next have time I'll do a little experimenting.

pipex commented 2 years ago

docker-qemu-transpose seens to have problems with multi-line RUN instructions as well. For an instruction of the type

RUN first-command \
    && second-command \
    && third-command

I got the following error using the --emulated flag

Dockerfile parse error line 23: unknown instruction: && 

Another workaround (which is what I used) is to replace the flag with cross-build-* sections https://www.balena.io/docs/reference/base-images/base-images/#building-arm-containers-on-x86-machines