# Haskell Dockerfile Linter
[![Build Status][github-actions-img]][github-actions]
[![GPL-3 licensed][license-img]][license]
[![GitHub release][release-img]][release]
![Github downloads][downloads-img]
A smarter Dockerfile linter that helps you build [best practice][] Docker
images. The linter is parsing the Dockerfile into an AST and performs rules on
top of the AST. It is standing on the shoulders of [ShellCheck][] to lint
the Bash code inside `RUN` instructions.
[:globe_with_meridians: **Check the online version on
hadolint.github.io/hadolint**](https://hadolint.github.io/hadolint)
[![Screenshot](screenshot.png)](https://hadolint.github.io/hadolint)
## How to use
You can run `hadolint` locally to lint your Dockerfile.
```bash
hadolint
hadolint --ignore DL3003 --ignore DL3006 # exclude specific rules
hadolint --trusted-registry my-company.com:500 # Warn when using untrusted FROM images
```
Docker comes to the rescue to provide an easy way how to run `hadolint` on most
platforms.
Just pipe your `Dockerfile` to `docker run`:
```bash
$ docker run --rm -i hadolint/hadolint < Dockerfile
# OR
$ docker run --rm -i ghcr.io/hadolint/hadolint < Dockerfile
```
or if you are using Windows PowerShell:
```powershell
> cat .\Dockerfile | docker run --rm -i hadolint/hadolint
```
## Install
You can download prebuilt binaries for OSX, Windows and Linux from the latest
[release page][]. However, if it doesn't work for you, please fall back to
Docker, `brew` or source installation.
If you are on OSX you can use [brew](https://brew.sh/) to install `hadolint`.
```bash
brew install hadolint
```
On Windows you can use [scoop](https://github.com/lukesampson/scoop) to
install `hadolint`.
```batch
scoop install hadolint
```
As shown before, `hadolint` is available as a Docker container:
```bash
docker pull hadolint/hadolint
# OR
docker pull ghcr.io/hadolint/hadolint
```
If you need a Docker container with shell access, use the Debian or Alpine
variants of the Docker image:
```bash
docker pull hadolint/hadolint:latest-debian
# OR
docker pull hadolint/hadolint:latest-alpine
# OR
docker pull ghcr.io/hadolint/hadolint:latest-debian
# OR
docker pull ghcr.io/hadolint/hadolint:latest-alpine
```
You can also build `hadolint` locally. You need [Haskell][] and the [stack][]
build tool to build the binary.
```bash
git clone https://github.com/hadolint/hadolint \
&& cd hadolint \
&& stack install
```
## CLI
```bash
hadolint --help
```
```text
hadolint - Dockerfile Linter written in Haskell
Usage: hadolint [-v|--version] [--no-fail] [--no-color] [-c|--config FILENAME]
[-V|--verbose] [-f|--format ARG] [DOCKERFILE...]
[--error RULECODE] [--warning RULECODE] [--info RULECODE]
[--style RULECODE] [--ignore RULECODE]
[--trusted-registry REGISTRY (e.g. docker.io)]
[--require-label LABELSCHEMA (e.g. maintainer:text)]
[--strict-labels] [-t|--failure-theshold THRESHOLD]
Lint Dockerfile for errors and best practices
Available options:
-h,--help Show this help text
-v,--version Show version
--no-fail Don't exit with a failure status code when any rule
is violated
--no-color Don't colorize output
-c,--config FILENAME Path to the configuration file
-V,--verbose Enables verbose logging of hadolint's output to
stderr
-f,--format ARG The output format for the results [tty | json |
checkstyle | codeclimate | gitlab_codeclimate |
codacy] (default: tty)
--error RULECODE Make the rule `RULECODE` have the level `error`
--warning RULECODE Make the rule `RULECODE` have the level `warning`
--info RULECODE Make the rule `RULECODE` have the level `info`
--style RULECODE Make the rule `RULECODE` have the level `style`
--ignore RULECODE A rule to ignore. If present, the ignore list in the
config file is ignored
--trusted-registry REGISTRY (e.g. docker.io)
A docker registry to allow to appear in FROM
instructions
--require-label LABELSCHEMA (e.g. maintainer:text)
The option --require-label=label:format makes
Hadolint check that the label `label` conforms to
format requirement `format`
--strict-labels Do not permit labels other than specified in
`label-schema`
-t,--failure-theshold THRESHOLD
Exit with failure code only when rules with a
severity above THRESHOLD are violated. Accepted
values: [error | warning | info | style | ignore |
none] (default: info)
```
## Configure
Configuration files can be used globally or per project. By default,
`hadolint` will look for a configuration file in the current directory
with the name `.hadolint.yaml` or `.hadolint.yml`
`hadolint` full `yaml` config file schema
```yaml
failure-threshold: string # name of threshold level (error | warning | info | style | ignore | none)
format: string # Output format (tty | json | checkstyle | codeclimate | gitlab_codeclimate | codacy)
ignored: [string] # list of rules
label-schema: # See Linting Labels below for specific label-schema details
author: string # Your name
contact: string # email address
created: timestamp # rfc3339 datetime
version: string # semver
documentation: string # url
git-revision: string # hash
license: string # spdx
no-color: boolean # true | false
no-fail: boolean # true | false
override:
error: [string] # list of rules
warning: [string] # list of rules
info: [string] # list of rules
style: [string] # list of rules
strict-labels: boolean # true | false
trustedRegistries: string | [string] # registry or list of registries
```
`hadolint` supports specifying the ignored rules using a configuration
file. The configuration file should be in `yaml` format. This is one
valid configuration file as an example:
```yaml
ignored:
- DL3000
- SC1010
```
Additionally, `hadolint` can warn you when images from untrusted
repositories are being used in Dockerfiles, you can append the
`trustedRegistries` keys to the configuration file as shown below:
```yaml
ignored:
- DL3000
- SC1010
trustedRegistries:
- docker.io
- my-company.com:5000
```
If you want to override the severity of specific rules, you can do that too:
```yaml
override:
error:
- DL3001
- DL3002
warning:
- DL3042
- DL3033
info:
- DL3032
style:
- DL3015
```
`failure-threshold` Exit with failure code only when rules with a
severity above THRESHOLD are violated (Available in v2.6.0+)
```yaml
failure-threshold: info
warning:
- DL3042
- DL3033
info:
- DL3032
```
The global configuration file should be placed in the folder
specified by `XDG_CONFIG_HOME`,
with the name `hadolint.yaml` or `hadolint.yml`. In summary, the
following locations are valid for the configuration file, in order
or preference:
- `$PWD/.hadolint.yaml`
- `$XDG_CONFIG_HOME/hadolint.yaml`
- `~/.config/hadolint.yaml`
In windows, the `%LOCALAPPDATA%` environment variable is used instead of `XDG_CONFIG_HOME`
Additionally, you can pass a custom configuration file in the command line with
the `--config` option
```bash
hadolint --config /path/to/config.yaml Dockerfile
```
To pass a custom configuration file (using relative or absolute path) to
a container, use the following command:
```bash
docker run --rm -i -v /your/path/to/hadolint.yaml:/.config/hadolint.yaml hadolint/hadolint < Dockerfile
# OR
docker run --rm -i -v /your/path/to/hadolint.yaml:/.config/hadolint.yaml ghcr.io/hadolint/hadolint < Dockerfile
```
## Inline ignores
It is also possible to ignore rules by using a special comment directly
above the Dockerfile instruction you want to make an exception for.
Ignore rule comments look like
`# hadolint ignore=DL3001,SC1081`. For example:
```dockerfile
# hadolint ignore=DL3006
FROM ubuntu
# hadolint ignore=DL3003,SC1035
RUN cd /tmp && echo "hello!"
```
Inline ignores will only work if place directly above the instruction.
## Linting Labels
Hadolint has the ability to check that specific labels be present and conform
to a predefined label schema.
First a label schema must be defined either via commandline:
```bash
hadolint --require-label author:text --require-label version:semver Dockerfile
```
or via config file:
```yaml
label-schema:
author: text
contact: email
created: rfc3339
version: semver
documentation: url
git-revision: hash
license: spdx
```
The value of a label can be either of `text`, `url`, `semver`, `hash` or
`rfc3339`:
| Schema | Description |
|:--------|:---------------------------------------------------|
| text | Anything |
| rfc3339 | A time, formatted according to [RFC 3339][rfc3339] |
| semver | A [semantic version][semver] |
| url | A URI as described in [RFC 3986][rfc3986] |
| hash | Either a short or a long [Git hash][githash] |
| spdx | An [SPDX license identifier][spdxid] |
| email | An email address conforming to [RFC 5322][rfc5322] |
By default, Hadolint ignores any label not specified in the label schema. To
warn on such additional labels, turn on strict labels:
```bash
hadolint --strict-labels --require-label version:semver Dockerfile
```
or in the config file:
```yaml
strict-labels: true
```
When strict labels is enabled, but no label schema has been specified, Hadolint
will warn if any label is present.
### Note on dealing with variables in labels
It is a common pattern to fill the value of a label not statically, but rather
dynamically at build time by using a variable:
```dockerfile
FROM debian:buster
ARG VERSION="du-jour"
LABEL version="${VERSION}"
```
To allow this, the label schema must specify `text` as value for that label:
```yaml
label-schema:
version: text
```
## Integrations
To get most of `hadolint` it is useful to integrate it as a check to your CI
or to your editor, or as a pre-commit hook, to lint your `Dockerfile` as you
write it. See our [Integration][] docs.
- [Code Review Platform Integrations][]
- [Continuous Integrations][]
- [Editor Integrations][]
- [Version Control Integrations][]
## Rules
An incomplete list of implemented rules. Click on the error code to get more
detailed information.
- Rules with the prefix `DL` originate from `hadolint`. Take a look at
`Rules.hs` to find the implementation of the rules.
- Rules with the `SC` prefix originate from **ShellCheck** (Only the most
common rules are listed, there are dozens more)
Please [create an issue][] if you have an idea for a good rule.
| Rule | Default Severity | Description |
|:-------------------------------------------------------------|:-----------------|:----------------------------------------------------------------------------------------------------------------------------------------------------|
| [DL3000](https://github.com/hadolint/hadolint/wiki/DL3000) | Error | Use absolute WORKDIR. |
| [DL3001](https://github.com/hadolint/hadolint/wiki/DL3001) | Info | For some bash commands it makes no sense running them in a Docker container like ssh, vim, shutdown, service, ps, free, top, kill, mount, ifconfig. |
| [DL3002](https://github.com/hadolint/hadolint/wiki/DL3002) | Warning | Last user should not be root. |
| [DL3003](https://github.com/hadolint/hadolint/wiki/DL3003) | Warning | Use WORKDIR to switch to a directory. |
| [DL3004](https://github.com/hadolint/hadolint/wiki/DL3004) | Error | Do not use sudo as it leads to unpredictable behavior. Use a tool like gosu to enforce root. |
| [DL3005](https://github.com/hadolint/hadolint/wiki/DL3005) | Error | Do not use apt-get dist-upgrade. |
| [DL3006](https://github.com/hadolint/hadolint/wiki/DL3006) | Warning | Always tag the version of an image explicitly. |
| [DL3007](https://github.com/hadolint/hadolint/wiki/DL3007) | Warning | Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag. |
| [DL3008](https://github.com/hadolint/hadolint/wiki/DL3008) | Warning | Pin versions in apt-get install. |
| [DL3009](https://github.com/hadolint/hadolint/wiki/DL3009) | Info | Delete the apt-get lists after installing something. |
| [DL3010](https://github.com/hadolint/hadolint/wiki/DL3010) | Info | Use ADD for extracting archives into an image. |
| [DL3011](https://github.com/hadolint/hadolint/wiki/DL3011) | Error | Valid UNIX ports range from 0 to 65535. |
| [DL3012](https://github.com/hadolint/hadolint/wiki/DL3012) | Error | Multiple `HEALTHCHECK` instructions. |
| [DL3013](https://github.com/hadolint/hadolint/wiki/DL3013) | Warning | Pin versions in pip. |
| [DL3014](https://github.com/hadolint/hadolint/wiki/DL3014) | Warning | Use the `-y` switch. |
| [DL3015](https://github.com/hadolint/hadolint/wiki/DL3015) | Info | Avoid additional packages by specifying --no-install-recommends. |
| [DL3016](https://github.com/hadolint/hadolint/wiki/DL3016) | Warning | Pin versions in `npm`. |
| [DL3018](https://github.com/hadolint/hadolint/wiki/DL3018) | Warning | Pin versions in apk add. Instead of `apk add ` use `apk add =`. |
| [DL3019](https://github.com/hadolint/hadolint/wiki/DL3019) | Info | Use the `--no-cache` switch to avoid the need to use `--update` and remove `/var/cache/apk/*` when done installing packages. |
| [DL3020](https://github.com/hadolint/hadolint/wiki/DL3020) | Error | Use `COPY` instead of `ADD` for files and folders. |
| [DL3021](https://github.com/hadolint/hadolint/wiki/DL3021) | Error | `COPY` with more than 2 arguments requires the last argument to end with `/` |
| [DL3022](https://github.com/hadolint/hadolint/wiki/DL3022) | Warning | `COPY --from` should reference a previously defined `FROM` alias |
| [DL3023](https://github.com/hadolint/hadolint/wiki/DL3023) | Error | `COPY --from` cannot reference its own `FROM` alias |
| [DL3024](https://github.com/hadolint/hadolint/wiki/DL3024) | Error | `FROM` aliases (stage names) must be unique |
| [DL3025](https://github.com/hadolint/hadolint/wiki/DL3025) | Warning | Use arguments JSON notation for CMD and ENTRYPOINT arguments |
| [DL3026](https://github.com/hadolint/hadolint/wiki/DL3026) | Error | Use only an allowed registry in the FROM image |
| [DL3027](https://github.com/hadolint/hadolint/wiki/DL3027) | Warning | Do not use `apt` as it is meant to be a end-user tool, use `apt-get` or `apt-cache` instead |
| [DL3028](https://github.com/hadolint/hadolint/wiki/DL3028) | Warning | Pin versions in gem install. Instead of `gem install ` use `gem install :` |
| [DL3029](https://github.com/hadolint/hadolint/wiki/DL3029) | Warning | Do not use --platform flag with FROM. |
| [DL3030](https://github.com/hadolint/hadolint/wiki/DL3030) | Warning | Use the `-y` switch to avoid manual input `yum install -y ` |
| [DL3032](https://github.com/hadolint/hadolint/wiki/DL3032) | Warning | `yum clean all` missing after yum command. |
| [DL3033](https://github.com/hadolint/hadolint/wiki/DL3033) | Warning | Specify version with `yum install -y -` |
| [DL3034](https://github.com/hadolint/hadolint/wiki/DL3034) | Warning | Non-interactive switch missing from `zypper` command: `zypper install -y` |
| [DL3035](https://github.com/hadolint/hadolint/wiki/DL3035) | Warning | Do not use `zypper dist-upgrade`. |
| [DL3036](https://github.com/hadolint/hadolint/wiki/DL3036) | Warning | `zypper clean` missing after zypper use. |
| [DL3037](https://github.com/hadolint/hadolint/wiki/DL3037) | Warning | Specify version with `zypper install -y [=]`. |
| [DL3038](https://github.com/hadolint/hadolint/wiki/DL3038) | Warning | Use the `-y` switch to avoid manual input `dnf install -y ` |
| [DL3040](https://github.com/hadolint/hadolint/wiki/DL3040) | Warning | `dnf clean all` missing after dnf command. |
| [DL3041](https://github.com/hadolint/hadolint/wiki/DL3041) | Warning | Specify version with `dnf install -y -` |
| [DL3042](https://github.com/hadolint/hadolint/wiki/DL3042) | Warning | Avoid cache directory with `pip install --no-cache-dir `. |
| [DL3043](https://github.com/hadolint/hadolint/wiki/DL3043) | Error | `ONBUILD`, `FROM` or `MAINTAINER` triggered from within `ONBUILD` instruction. |
| [DL3044](https://github.com/hadolint/hadolint/wiki/DL3044) | Error | Do not refer to an environment variable within the same `ENV` statement where it is defined. |
| [DL3045](https://github.com/hadolint/hadolint/wiki/DL3045) | Warning | `COPY` to a relative destination without `WORKDIR` set. |
| [DL3046](https://github.com/hadolint/hadolint/wiki/DL3046) | Warning | `useradd` without flag `-l` and high UID will result in excessively large Image. |
| [DL3047](https://github.com/hadolint/hadolint/wiki/DL3047) | Info | `wget` without flag `--progress` will result in excessively bloated build logs when downloading larger files. |
| [DL3048](https://github.com/hadolint/hadolint/wiki/DL3048) | Style | Invalid Label Key |
| [DL3049](https://github.com/hadolint/hadolint/wiki/DL3049) | Info | Label `