hadolint / hadolint

Dockerfile linter, validate inline bash, written in Haskell
GNU General Public License v3.0
10.44k stars 425 forks source link

Error when parsing FROM with ARG #339

Open mritzmann opened 5 years ago

mritzmann commented 5 years ago

Expected behavior

hadolint should be able to proceed linting.

Actual behavior

hadolint crashes.

$ docker run --rm -i hadolint/hadolint < Dockerfile   
/dev/stdin:2:26 unexpected ':' expecting '@', a new line followed by the next instruction, at least one space, or the image tag 

Steps to reproduce the behavior

Lint Dockerfile which uses a ARG with default value in FROM.

Output of docker run --rm hadolint/hadolint hadolint --version:

$ docker run --rm hadolint/hadolint hadolint --version
Haskell Dockerfile Linter v1.17.1-3-g4017799

Dockerfile (if relevant)

ARG BASE_IMAGE
FROM ${BASE_IMAGE:-debian:9}

RUN touch test
lorenzo commented 5 years ago

yeah, in general hadolint does not make a great effort at parsing variables, but usually for a good reason. This is more understandable and you will still enjoy the benefits of all checks:

ARG BASE_IMAGE=debian
ARG BASE_IMAGE_VERION=9
FROM $BASE_IMAGE:$BASE_IMAGE_VERSION
thetic commented 4 years ago

This issue causes false positives for DL3006 and DL3026.

Given the following Dockerfile:

ARG TOGETHER=foo.com/image:tag
FROM $TOGETHER

ARG IMAGE=foo.com/image
ARG VERSION=tag
FROM $IMAGE:$VERSION

FROM foo.com/image:tag

I get the following output:

$ hadolint --trusted-registry foo.com Dockerfile
Dockerfile:2 DL3006 Always tag the version of an image explicitly
Dockerfile:2 DL3026 Use only an allowed registry in the FROM image
Dockerfile:6 DL3026 Use only an allowed registry in the FROM image
zemanlx commented 4 years ago

I am sorry that it is causing you trouble. As @lorenzo mentioned hadolint is not parsing variables, therefore in your examples, hadolint does not really know that in FROM you are using foo.com domain and tag in your first example.

thetic commented 4 years ago

Are there plans to improve variable parsing? This looks to be the cause of several of the issues filed.

zemanlx commented 4 years ago

@thetic Not that I know of, but we are open to PR :wink:

thetic commented 4 years ago

Thanks for the response. Unfortunately, I don't know Haskell. I'll keep an eye on this repo and look for alternatives in the meantime. Keep up the good work. Other than this, I have been very satisfied with this project.

mritzmann commented 4 years ago

and look for alternatives in the meantime

You can also simply ignore the rule in question. Example:

ARG BASE_IMAGE
# hadolint ignore=DL3006
FROM ${BASE_IMAGE:-debian:9}

RUN touch test

see also: https://github.com/hadolint/hadolint#inline-ignores

tymonx commented 3 years ago

I'm also have the same issue:

ARG PYTHON_IMAGE=python
ARG PYTHON_VERSION=3.9.7

FROM ${PYTHON_IMAGE:-python}:${PYTHON_VERSION:-latest}

Error:

No configuration was specified. Using default configuration
./Dockerfile:4:29 unexpected ':' expecting '@', '\', a new line followed by the next instruction, or the image tag

Workaround with the # hadolint ignore=DL3006 is not working for me.

This is a valid Dockerfile syntax Environment replacement (FROM supported).

thetic commented 3 years ago

You can also simply ignore the rule in question... Example:

I would prefer to be able to enforce DL3006 and DL3026, not ignore them.

haxorof commented 2 years ago

It is also causing the same issue if you have a Dockerfile which got a FROM that points to some local registry, ex:

FROM localhost:5000/bash:latest
kaotika commented 1 year ago

Here is a potential workaround.

Needs
build.args
#!/bin/bash

export CONTAINERFILE=Dockerfile
export CONTAINER_BUILD_ARG_FILE=build.args

export BUILD_ARGS_ENV_FILE=/tmp/build.args
export DOCKERFILE_ARGS=/tmp/dockerfile.args
export ENVSUBSTED_DOCKERFILE=/tmp/Dockerfile

# extract all ARGS from Dockerfile
cat ${CONTAINERFILE} | grep ARG | cut -d " " -f 2 | xargs -- printf "export %s\n" > ${DOCKERFILE_ARGS}
# source extracted ARGS
source ${DOCKERFILE_ARGS}

# source potential build args or export the needed environment variables
cat ${CONTAINER_BUILD_ARG_FILE} | envsubst | xargs -- printf "export %s\n" > "${BUILD_ARGS_ENV_FILE}"
source "${BUILD_ARGS_ENV_FILE}"

# replace the args in the Dockerfile with envsubst
envsubst < ${CONTAINERFILE} > ${ENVSUBSTED_DOCKERFILE}
echo "### replaced dockerfile:"
cat ${ENVSUBSTED_DOCKERFILE}
echo
echo

echo "### hadolint result:"
# hadolint the envsubsted dockerfile
hadolint \
  --format gitlab_codeclimate \
  --failure-threshold error \
  --trusted-registry docker.io \
  --trusted-registry *.gitlab.com \
  --trusted-registry registry.my-private-registry.com \
  ${ENVSUBSTED_DOCKERFILE}
Results
[
  {
    "categories": [
      "Bug Risk"
    ],
    "check_name": "DL3026",
    "description": "Use only an allowed registry in the FROM image",
    "fingerprint": "7e0fe710b378b9b8e944c5bb7d040795df6f4a9d",
    "location": {
      "lines": {
        "begin": 3,
        "end": 3
      },
      "path": "/tmp/Dockerfile"
    },
    "severity": "blocker",
    "type": "issue"
  }
]
[]