# Dockerfile Validation

The validator is intended to perform the same kinds of validation that the Docker builder performs when building an image.
Any errors that are generated by the validator should also be generated by the Docker builder (albeit the message strings itself may differ).
If the validator generates an error for a Dockerfile that the Docker builder is able to build, that is considered to be a bug.

However, errors that the Docker builder generates may not necessarily be replicated by the validator due to difficulties in verifying the validity of a given Dockerfile instruction and its arguments given the builder's build context and other factors.

The currently supported version of the Docker builder is **Docker CE 20.10 [2020-12-08]**.

## Command Line Interface

If no file is specified, the CLI will attempt to validate the contents of a file named `Dockerfile` in the current working directory if it exists.

### Help
```
> dockerfile-utils lint --help
Usage: dockerfile-utils lint [options] [file]

Options:

  -h, --help                Output usage information
  -j, --json                Output in JSON format
```

### Example
```Dockerfile
      FROM node
HEALTHCHECK --interva=30s CMD ls
  RUN "echo" ls \
  
  "echoS"sdfdf \
  asdfasdf
  copy . .
ADD app.zip
CMD ls
```
#### CLI Output
```
> dockerfile-utils lint
Line: 2
HEALTHCHECK --interva=30s CMD ls
            ^^^^^^^^^
Error: Unknown flag: interva

Line: 4
Warning: Empty continuation line

Line: 7
  copy . .
  ^^^^
Warning: Instructions should be written in uppercase letters

Line: 8
ADD app.zip
    ^^^^^^^
Error: ADD requires at least two arguments
```
#### JSON Output
For readability purposes, the output below has been formatted manually.
The output on the command line will not include any whitespaces.
```
> dockerfile-utils lint -j
[
  {
    "range": {
      "start": { "line": 1, "character": 12 },
      "end": { "line": 1, "character": 21 }
    },
    "message": "Unknown flag: interva",
    "severity": "error"
  },
  {
    "range": {
      "start": { "line": 3, "character": 0 },
      "end": { "line": 4, "character": 0 }
    },
    "message": "Empty continuation line",
    "severity": "warning"
  },
  {
    "range": {
      "start": { "line": 6, "character": 2 },
      "end": { "line": 6, "character": 6 }
    },
    "message": "Instructions should be written in uppercase letters",
    "severity": "warning"
  },
  {
    "range": {
      "start": { "line": 7, "character": 4 },
      "end": { "line": 7, "character": 11 }
    },
    "message": "ADD requires at least two arguments",
    "severity": "error"
  }
]
```

## Supported Validation Checks
If the validator is flagging something you want it to ignore, you can put a `# dockerfile-utils: ignore` comment right before the originating line of the error. Note that not all errors can be ignored this way. Fatal errors (missing `FROM` instruction for example) or errors related to parser directives (since having a comment would make something _not_ a parser directive anymore) cannot be ignored.

```Dockerfile
FROM alpine
# dockerfile-utils: ignore
UNRECOGNIZED argument
```

The originating line is generally the instruction itself. So if you have a multi-line instruction you must put it before the instruction instead of before the error the line is on.

**Correct:**
```Dockerfile
FROM alpine
# dockerfile-utils: ignore
HEALTHCHECK \
    --interval=30s \
    --typo=example \
    CMD [ "executable" ]
```
**Incorrect:**
```Dockerfile
FROM alpine
HEALTHCHECK \
    --interval=30s \
# dockerfile-utils: ignore
    --typo=example \
    CMD [ "executable" ]
```

If you feel an error cannot be ignored but you feel it is a non-fatal error, please let us know by opening an issue.


### General
#### Instructions
- instructions should be written in uppercase
- instruction has no arguments
- instruction has an insufficient number of arguments
- unknown instruction detected
- duplicate instruction flags detected
- unknown instruction flag detected
- instruction flag has no value defined
#### Directives
- invalid value specified for `escape` parser directive
- directives should be written in lowercase.
#### Others
- empty continuation lines

### CMD
- multiple `CMD` instructions detected

### ENTRYPOINT
- multiple `ENTRYPOINT` instructions detected

### ENV
- syntax missing equals sign '`=`'
- syntax missing single quote '`'`'
- syntax missing double quotes '`"`'
- property has no name

### EXPOSE
- invalid container port specified
- invalid protocol specified

### FROM
- `FROM` instruction not found at the beginning of the Dockerfile
- invalid build stage name specified
- duplicate build stage name detected
- second argument detected but not an `AS`

### HEALTHCHECK
- `CMD` form has no arguments
- `NONE` form has arguments defined
- type that is not `CMD` or `NONE` detected
- `--retries` flag has invalid syntax
- `--retries` value is not at least one
- duration of `--interval`, `--start-period`, or `--timeout` is invalid
- duration of `--interval`, `--start-period`, or `--timeout` is less than one millisecond
- duration of `--interval`, `--start-period`, or `--timeout` has an unknown unit of time specified
- multiple `HEALTHCHECK` instructions detected

### LABEL
- syntax missing equals sign '`=`'
- syntax missing single quote '`'`'
- syntax missing double quotes '`"`'
- property has no name

### MAINTAINER
- use of deprecated instruction detected

### ONBUILD
- can't chain `ONBUILD` instruction with `ONBUILD ONBUILD`
- invalid `ONBUILD` trigger instruction

### SHELL
- `SHELL` not written in JSON form

### STOPSIGNAL
- invalid stop signal
