packages feed

hadolint 2.12.0 → 2.13.1

raw patch · 45 files changed

+824/−604 lines, 45 filesdep +base16-bytestringdep +cryptohash-sha1dep +xml-conduitdep −cryptonitedep ~Cabaldep ~HsYAMLdep ~ShellChecknew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: base16-bytestring, cryptohash-sha1, xml-conduit

Dependencies removed: cryptonite

Dependency ranges changed: Cabal, HsYAML, ShellCheck, aeson, base, bytestring, colourista, containers, data-default, deepseq, directory, email-validate, filepath, foldl, gitrev, ilist, language-docker, megaparsec, mtl, network-uri, optparse-applicative, parallel, parsec, prettyprinter, semver, spdx, split, text, time, timerep, void

API changes (from Hackage documentation)

- Hadolint.Config.Commandline: instance GHC.Show.Show Hadolint.Config.Commandline.CommandlineConfig
- Hadolint.Config.Configuration: instance Data.Default.Class.Default Hadolint.Config.Configuration.Configuration
- Hadolint.Config.Configuration: instance Data.Default.Class.Default Hadolint.Config.Configuration.PartialConfiguration
- Hadolint.Config.Configuration: instance GHC.Base.Monoid Hadolint.Config.Configuration.OverrideConfig
- Hadolint.Config.Configuration: instance GHC.Base.Monoid Hadolint.Config.Configuration.PartialConfiguration
- Hadolint.Config.Configuration: instance GHC.Base.Semigroup Hadolint.Config.Configuration.OverrideConfig
- Hadolint.Config.Configuration: instance GHC.Base.Semigroup Hadolint.Config.Configuration.PartialConfiguration
- Hadolint.Config.Configuration: instance GHC.Generics.Generic Hadolint.Config.Configuration.OverrideConfig
- Hadolint.Config.Configuration: instance GHC.Show.Show Hadolint.Config.Configuration.Configuration
- Hadolint.Config.Configuration: instance GHC.Show.Show Hadolint.Config.Configuration.OverrideConfig
- Hadolint.Config.Configuration: instance GHC.Show.Show Hadolint.Config.Configuration.PartialConfiguration
- Hadolint.Formatter: GitlabCodeclimateJson :: OutputFormat
- Hadolint.Formatter.Checkstyle: formatResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Maybe FilePath -> Builder
- Hadolint.Formatter.Codeclimate: formatGitlabResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Seq FingerprintIssue
- Hadolint.Formatter.Codeclimate: instance GHC.Generics.Generic Hadolint.Formatter.Codeclimate.Pos
- Hadolint.Formatter.Codeclimate: printGitlabResults :: (Foldable f, VisualStream s, TraversableStream s, ShowErrorComponent e) => f (Result s e) -> IO ()
- Hadolint.Formatter.Format: GitlabCodeclimateJson :: OutputFormat
- Hadolint.Formatter.Format: instance Data.Default.Class.Default Hadolint.Formatter.Format.OutputFormat
- Hadolint.Formatter.Format: instance GHC.Base.Monoid Hadolint.Formatter.Format.OutputFormat
- Hadolint.Formatter.Format: instance GHC.Base.Semigroup Hadolint.Formatter.Format.OutputFormat
- Hadolint.Formatter.Format: instance GHC.Show.Show Hadolint.Formatter.Format.OutputFormat
- Hadolint.Rule: instance Data.Default.Class.Default Hadolint.Rule.DLSeverity
- Hadolint.Rule: instance Data.String.IsString Hadolint.Rule.RuleCode
- Hadolint.Rule: instance GHC.Base.Monoid Hadolint.Rule.DLSeverity
- Hadolint.Rule: instance GHC.Base.Semigroup Hadolint.Rule.DLSeverity
- Hadolint.Rule: instance GHC.Generics.Generic Hadolint.Rule.DLSeverity
- Hadolint.Rule: instance GHC.Show.Show Hadolint.Rule.CheckFailure
- Hadolint.Rule: instance GHC.Show.Show Hadolint.Rule.DLSeverity
- Hadolint.Rule: instance GHC.Show.Show Hadolint.Rule.LabelType
- Hadolint.Rule: instance GHC.Show.Show Hadolint.Rule.RuleCode
- Hadolint.Rule: instance GHC.Show.Show a => GHC.Show.Show (Hadolint.Rule.State a)
- Hadolint.Rule.DL3002: instance GHC.Show.Show Hadolint.Rule.DL3002.Acc
- Hadolint.Rule.DL3005: rule :: Rule ParsedShell
- Hadolint.Rule.DL3009: instance GHC.Show.Show Hadolint.Rule.DL3009.Acc
- Hadolint.Rule.DL3049: instance GHC.Show.Show Hadolint.Rule.DL3049.Acc
- Hadolint.Rule.DL3049: instance GHC.Show.Show Hadolint.Rule.DL3049.StageID
- Hadolint.Rule.DL3057: instance GHC.Show.Show Hadolint.Rule.DL3057.Acc
- Hadolint.Rule.DL3057: instance GHC.Show.Show Hadolint.Rule.DL3057.StageID
- Hadolint.Rule.DL3060: instance GHC.Show.Show Hadolint.Rule.DL3060.Acc
- Hadolint.Shell: instance GHC.Show.Show Hadolint.Shell.CmdPart
- Hadolint.Shell: instance GHC.Show.Show Hadolint.Shell.Command
+ Hadolint.Config.Commandline: instance GHC.Internal.Show.Show Hadolint.Config.Commandline.CommandlineConfig
+ Hadolint.Config.Configuration: instance Data.Default.Internal.Default Hadolint.Config.Configuration.Configuration
+ Hadolint.Config.Configuration: instance Data.Default.Internal.Default Hadolint.Config.Configuration.PartialConfiguration
+ Hadolint.Config.Configuration: instance GHC.Internal.Base.Monoid Hadolint.Config.Configuration.OverrideConfig
+ Hadolint.Config.Configuration: instance GHC.Internal.Base.Monoid Hadolint.Config.Configuration.PartialConfiguration
+ Hadolint.Config.Configuration: instance GHC.Internal.Base.Semigroup Hadolint.Config.Configuration.OverrideConfig
+ Hadolint.Config.Configuration: instance GHC.Internal.Base.Semigroup Hadolint.Config.Configuration.PartialConfiguration
+ Hadolint.Config.Configuration: instance GHC.Internal.Generics.Generic Hadolint.Config.Configuration.OverrideConfig
+ Hadolint.Config.Configuration: instance GHC.Internal.Show.Show Hadolint.Config.Configuration.Configuration
+ Hadolint.Config.Configuration: instance GHC.Internal.Show.Show Hadolint.Config.Configuration.OverrideConfig
+ Hadolint.Config.Configuration: instance GHC.Internal.Show.Show Hadolint.Config.Configuration.PartialConfiguration
+ Hadolint.Formatter: GitLabCodeclimateJson :: OutputFormat
+ Hadolint.Formatter.Codeclimate: formatGitLabResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Seq FingerprintIssue
+ Hadolint.Formatter.Codeclimate: instance GHC.Internal.Generics.Generic Hadolint.Formatter.Codeclimate.Pos
+ Hadolint.Formatter.Codeclimate: printGitLabResults :: (Foldable f, VisualStream s, TraversableStream s, ShowErrorComponent e) => f (Result s e) -> IO ()
+ Hadolint.Formatter.Format: GitLabCodeclimateJson :: OutputFormat
+ Hadolint.Formatter.Format: instance Data.Default.Internal.Default Hadolint.Formatter.Format.OutputFormat
+ Hadolint.Formatter.Format: instance GHC.Internal.Base.Monoid Hadolint.Formatter.Format.OutputFormat
+ Hadolint.Formatter.Format: instance GHC.Internal.Base.Semigroup Hadolint.Formatter.Format.OutputFormat
+ Hadolint.Formatter.Format: instance GHC.Internal.Show.Show Hadolint.Formatter.Format.OutputFormat
+ Hadolint.Rule: instance Data.Default.Internal.Default Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Internal.Base.Monoid Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Internal.Base.Semigroup Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Internal.Data.String.IsString Hadolint.Rule.RuleCode
+ Hadolint.Rule: instance GHC.Internal.Generics.Generic Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Internal.Show.Show Hadolint.Rule.CheckFailure
+ Hadolint.Rule: instance GHC.Internal.Show.Show Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Internal.Show.Show Hadolint.Rule.LabelType
+ Hadolint.Rule: instance GHC.Internal.Show.Show Hadolint.Rule.RuleCode
+ Hadolint.Rule: instance GHC.Internal.Show.Show a => GHC.Internal.Show.Show (Hadolint.Rule.State a)
+ Hadolint.Rule.DL3002: instance GHC.Internal.Show.Show Hadolint.Rule.DL3002.Acc
+ Hadolint.Rule.DL3009: instance GHC.Internal.Show.Show Hadolint.Rule.DL3009.Acc
+ Hadolint.Rule.DL3022: instance GHC.Classes.Eq Hadolint.Rule.DL3022.Acc
+ Hadolint.Rule.DL3049: instance GHC.Internal.Show.Show Hadolint.Rule.DL3049.Acc
+ Hadolint.Rule.DL3049: instance GHC.Internal.Show.Show Hadolint.Rule.DL3049.StageID
+ Hadolint.Rule.DL3057: instance GHC.Internal.Show.Show Hadolint.Rule.DL3057.Acc
+ Hadolint.Rule.DL3057: instance GHC.Internal.Show.Show Hadolint.Rule.DL3057.StageID
+ Hadolint.Rule.DL3060: instance GHC.Internal.Show.Show Hadolint.Rule.DL3060.Acc
+ Hadolint.Shell: countFlag :: Text -> Command -> Int
+ Hadolint.Shell: instance GHC.Internal.Show.Show Hadolint.Shell.CmdPart
+ Hadolint.Shell: instance GHC.Internal.Show.Show Hadolint.Shell.Command
- Hadolint.Rule: type Rule args = Fold (InstructionPos args) Failures
+ Hadolint.Rule: type Rule args = Fold InstructionPos args Failures
- Hadolint.Shell: extractTokensWith :: forall a. (Token -> Maybe a) -> ParseResult -> [a]
+ Hadolint.Shell: extractTokensWith :: (Token -> Maybe a) -> ParseResult -> [a]

Files

README.md view
@@ -3,7 +3,7 @@ [![Build Status][github-actions-img]][github-actions] [![GPL-3 licensed][license-img]][license] [![GitHub release][release-img]][release]-![Github downloads][downloads-img]+![GitHub downloads][downloads-img] <img align="right" alt="pipecat" width="150" src="https://hadolint.github.io/hadolint/img/cat_container.png" /> @@ -16,6 +16,28 @@ hadolint.github.io/hadolint**](https://hadolint.github.io/hadolint) [![Screenshot](screenshot.png)](https://hadolint.github.io/hadolint) +## Table of Contents++- [How to use](#how-to-use)+- [Install](#install)+- [CLI](#cli)+- [Configure](#configure)+- [Non-Posix Shells](#non-posix-shells)+- [Ignoring Rules](#ignoring-rules)+  - [Inline ignores](#inline-ignores)+  - [Global ignores](#global-ignores)+- [Linting Labels](#linting-labels)+  - [Note on dealing with variables in labels](#note-on-dealing-with-variables-in-labels)+- [Integrations](#integrations)+- [Rules](#rules)+- [Develop](#develop)+  - [Setup](#setup)+  - [REPL](#repl)+  - [Tests](#tests)+  - [AST](#ast)+  - [Building against custom libraries](#building-against-custom-libraries)+- [Alternatives](#alternatives)+ ## How to use  You can run `hadolint` locally to lint your Dockerfile.@@ -94,13 +116,15 @@ docker pull ghcr.io/hadolint/hadolint:latest-alpine ``` -You can also build `hadolint` locally. You need [Haskell][] and the [stack][]+You can also build `hadolint` locally. You need [Haskell][] and the [cabal][] build tool to build the binary.  ```bash git clone https://github.com/hadolint/hadolint \-&& cd hadolint \-&& stack install+  && cd hadolint \+  && cabal configure \+  && cabal build \+  && cabal install ```  If you want the@@ -181,13 +205,14 @@ Configuration files can be used globally or per project. Hadolint looks for configuration files in the following locations or their platform specific equivalents in this order and uses the first one exclusively:+ - `$PWD/.hadolint.yaml` - `$XDG_CONFIG_HOME/hadolint.yaml` - `$HOME/.config/hadolint.yaml` - `$HOME/.hadolint/hadolint.yaml or $HOME/hadolint/config.yaml` - `$HOME/.hadolint.yaml` -In windows, the `%LOCALAPPDATA%` environment variable is used instead of +In windows, the `%LOCALAPPDATA%` environment variable is used instead of `XDG_CONFIG_HOME`. Config files can have either `yaml` or `yml` extensions.  `hadolint` full `yaml` config file schema@@ -262,7 +287,8 @@  ```yaml failure-threshold: info-warning:+override:+  warning:     - DL3042     - DL3033   info:@@ -287,6 +313,7 @@  In addition to config files, Hadolint can be configured with environment variables.+ ```bash NO_COLOR=1                               # Set or unset. See https://no-color.org HADOLINT_NOFAIL=1                        # Truthy value e.g. 1, true or yes@@ -316,8 +343,10 @@ RUN Get-Process notepad | Stop-Process ``` -## Inline ignores+## Ignoring Rules +### Inline ignores+ It is also possible to ignore rules by adding a special comment directly above the Dockerfile statement for which you want to make an exception for. Such comments look like@@ -333,10 +362,10 @@  The comment "inline ignores" applies only to the statement following it. -## Global ignores+### Global ignores  Rules can also be ignored on a per-file basis using the global ignore pragma.-It works just like inline ignores, excep that it applies to the whole file+It works just like inline ignores, except that it applies to the whole file instead of just the next line.  ```dockerfile@@ -371,6 +400,7 @@  The value of a label can be either of `text`, `url`, `semver`, `hash` or `rfc3339`:+ | Schema  | Description                                        | |:--------|:---------------------------------------------------| | text    | Anything                                           |@@ -431,10 +461,10 @@ An incomplete list of implemented rules. Click on the error code to get more detailed information. --   Rules with the prefix `DL` are from `hadolint`. Have a look at+- Rules with the prefix `DL` are from `hadolint`. Have a look at     `Rules.hs` to find the implementation of the rules. --   Rules with the `SC` prefix are from **ShellCheck** (only the most+- Rules with the `SC` prefix are 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.@@ -449,7 +479,6 @@ | [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`.                                                                                                                  |@@ -470,7 +499,7 @@ | [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                                                         |+| [DL3027](https://github.com/hadolint/hadolint/wiki/DL3027)   | Warning          | Do not use `apt` as it is meant to be an 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 <gem>` use `gem install <gem>:<version>`                                                       | | [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 <package>`                                                                                |@@ -494,12 +523,12 @@ | [DL3050](https://github.com/hadolint/hadolint/wiki/DL3050)   | Info             | Superfluous label(s) present.                                                                                                                       | | [DL3051](https://github.com/hadolint/hadolint/wiki/DL3051)   | Warning          | Label `<label>` is empty.                                                                                                                           | | [DL3052](https://github.com/hadolint/hadolint/wiki/DL3052)   | Warning          | Label `<label>` is not a valid URL.                                                                                                                 |-| [DL3053](https://github.com/hadolint/hadolint/wiki/DL3053)   | Warning          | Label `<label>` is not a valid time format - must be conform to RFC3339.                                                                            |+| [DL3053](https://github.com/hadolint/hadolint/wiki/DL3053)   | Warning          | Label `<label>` is not a valid time format - must conform to RFC3339.                                                                               | | [DL3054](https://github.com/hadolint/hadolint/wiki/DL3054)   | Warning          | Label `<label>` is not a valid SPDX license identifier.                                                                                             | | [DL3055](https://github.com/hadolint/hadolint/wiki/DL3055)   | Warning          | Label `<label>` is not a valid git hash.                                                                                                            | | [DL3056](https://github.com/hadolint/hadolint/wiki/DL3056)   | Warning          | Label `<label>` does not conform to semantic versioning.                                                                                            | | [DL3057](https://github.com/hadolint/hadolint/wiki/DL3057)   | Ignore           | `HEALTHCHECK` instruction missing.                                                                                                                  |-| [DL3058](https://github.com/hadolint/hadolint/wiki/DL3058)   | Warning          | Label `<label>` is not a valid email format - must be conform to RFC5322.                                                                           |+| [DL3058](https://github.com/hadolint/hadolint/wiki/DL3058)   | Warning          | Label `<label>` is not a valid email format - must conform to RFC5322.                                                                              | | [DL3059](https://github.com/hadolint/hadolint/wiki/DL3059)   | Info             | Multiple consecutive `RUN` instructions. Consider consolidation.                                                                                    | | [DL3060](https://github.com/hadolint/hadolint/wiki/DL3060)   | Info             | `yarn cache clean` missing after `yarn install` was run.                                                                                            | | [DL3061](https://github.com/hadolint/hadolint/wiki/DL3061)   | Error            | Invalid instruction order. Dockerfile must begin with `FROM`, `ARG` or comment.                                                                     |@@ -526,15 +555,16 @@ | [SC1083](https://github.com/koalaman/shellcheck/wiki/SC1083) |                  | This `{/}` is literal. Check expression (missing `;/\n`?) or quote it.                                                                              | | [SC1086](https://github.com/koalaman/shellcheck/wiki/SC1086) |                  | Don't use `$` on the iterator name in for loops.                                                                                                    | | [SC1087](https://github.com/koalaman/shellcheck/wiki/SC1087) |                  | Braces are required when expanding arrays, as in `${array[idx]}`.                                                                                   |+| [SC1091](https://github.com/koalaman/shellcheck/wiki/SC1091) |                  | Not following: Reasons include: file not found, no permissions, not included on the command line, not allowing shellcheck to follow files with -x, etc.                                                                                    | | [SC1095](https://github.com/koalaman/shellcheck/wiki/SC1095) |                  | You need a space or linefeed between the function name and body.                                                                                    | | [SC1097](https://github.com/koalaman/shellcheck/wiki/SC1097) |                  | Unexpected `==`. For assignment, use `=`. For comparison, use `[ .. ]` or `[[ .. ]]`.                                                               | | [SC1098](https://github.com/koalaman/shellcheck/wiki/SC1098) |                  | Quote/escape special characters when using `eval`, e.g. `eval "a=(b)"`.                                                                             |-| [SC1099](https://github.com/koalaman/shellcheck/wiki/SC1099) |                  | You need a space before the `#`.                                                                                                                    |+| [SC1099](https://github.com/koalaman/shellcheck/wiki/SC1099) |                   | You need a space before the `#`.                                                                                                                    | | [SC2002](https://github.com/koalaman/shellcheck/wiki/SC2002) |                  | Useless cat. Consider <code>cmd < file &#124; ..</code> or <code>cmd file &#124; ..</code> instead.                                                 | | [SC2015](https://github.com/koalaman/shellcheck/wiki/SC2015) |                  | Note that <code>A && B &#124;&#124; C</code> is not if-then-else. C may run when A is true.                                                         | | [SC2026](https://github.com/koalaman/shellcheck/wiki/SC2026) |                  | This word is outside of quotes. Did you intend to 'nest '"'single quotes'"' instead'?                                                               | | [SC2028](https://github.com/koalaman/shellcheck/wiki/SC2028) |                  | `echo` won't expand escape sequences. Consider `printf`.                                                                                            |-| [SC2035](https://github.com/koalaman/shellcheck/wiki/SC2035) |                  | Use `./*glob*` or `-- *glob*` so names with dashes won't become options.                                                                            |+| [SC2035](https://github.com/koalaman/shellcheck/wiki/SC2035) |                  | Use `./*glob*` or `-- *glob*` so names with dashes won't become options.                                                                             | | [SC2039](https://github.com/koalaman/shellcheck/wiki/SC2039) |                  | In POSIX sh, something is undefined.                                                                                                                | | [SC2046](https://github.com/koalaman/shellcheck/wiki/SC2046) |                  | Quote this to prevent word splitting                                                                                                                | | [SC2086](https://github.com/koalaman/shellcheck/wiki/SC2086) |                  | Double quote to prevent globbing and word splitting.                                                                                                |@@ -550,27 +580,36 @@ If you are an experienced Haskeller, we would be very grateful if you would tear our code apart in a review. +To compile, you will need a recent Haskell environment and `cabal-install`.+ ### Setup -1.  Clone repository+1. Clone repository      ```bash     git clone --recursive git@github.com:hadolint/hadolint.git     ``` -1.  Install the dependencies+1. Install dependencies and compile source      ```bash-    stack install+    cabal configure+    cabal build     ``` +1. (Optional) Install Hadolint on your system++    ```bash+    cabal install+    ```+ ### REPL  The easiest way to try out the parser is using the REPL.  ```bash # start the repl-stack repl+cabal repl # overload strings to be able to use Text :set -XOverloadedStrings # import parser library@@ -581,10 +620,12 @@  ### Tests -Run unit tests:+Compile with unit tests and run them:  ```bash-stack test+cabal configure --enable-tests+cabal build --enable-tests+cabal test ```  Run integration tests:@@ -605,10 +646,11 @@ language-docker is used to parse Dockerfiles and produce an AST which then can be analyzed. To build Hadolint against a custom version of such libraries, do the following. This example uses language-docker, but it would work with any-other libaray as well.+other library as well.   1) In the same directory (e.g. `/home/user/repos`) clone Hadolint and     language-docker git repositories+ ```bash cd /home/user/repos git clone https://github.com/hadolint/hadolint.git@@ -617,34 +659,39 @@   2) Make your modifications to language-docker - 3) In the Hadolint repo, edit the `stack.yaml` file, such that the `extra-deps`-    property points to the other repo+ 3) In the Hadolint repo, edit the `cabal.project` file, such that the+    `packages` property points to the other repo too+ ```yaml [...]-extra-deps:-  - ../language-docker+packages:+  .+  ../language-docker [...] ```   4) Recompile Hadolint and run the tests+ ```bash cd /home/user/repos/hadolint-stack test+cabal configure --enable-tests+cabal build --enable-tests+cabal test ```  ## Alternatives --   replicatedhq/[dockerfilelint](https://github.com/replicatedhq/dockerfilelint),+- replicatedhq/[dockerfilelint](https://github.com/replicatedhq/dockerfilelint),     the other linter used by the [super-linter](https://github.com/github/super-linter/blob/main/README.md#supported-linters) --   RedCoolBeans/[dockerlint](https://github.com/RedCoolBeans/dockerlint/)+- RedCoolBeans/[dockerlint](https://github.com/RedCoolBeans/dockerlint/) --   projectatomic/[dockerfile_lint](https://github.com/projectatomic/dockerfile_lint/)+- projectatomic/[dockerfile_lint](https://github.com/projectatomic/dockerfile_lint/)  <!-- References --> -[github-actions-img]: https://github.com/hadolint/hadolint/workflows/Haskell%20Tests/badge.svg?branch=master-[github-actions]: https://travis-ci.org/hadolint/hadolint/actions+[github-actions-img]: https://github.com/hadolint/hadolint/actions/workflows/haskell.yml/badge.svg?branch=master+[github-actions]: https://github.com/hadolint/hadolint/actions/workflows/haskell.yml [license-img]: https://img.shields.io/badge/license-GPL--3-blue.svg [license]: https://tldrlegal.com/l/gpl-3.0 [release-img]: https://img.shields.io/github/release/hadolint/hadolint.svg@@ -654,7 +701,7 @@ [shellcheck]: https://github.com/koalaman/shellcheck [release page]: https://github.com/hadolint/hadolint/releases/latest [haskell]: https://www.haskell.org/downloads/-[stack]: http://docs.haskellstack.org/en/stable/install_and_upgrade.html+[cabal]: https://www.haskell.org/cabal/ [integration]: docs/INTEGRATION.md [code review platform integrations]: docs/INTEGRATION.md#code-review [continuous integrations]: docs/INTEGRATION.md#continuous-integration@@ -662,7 +709,7 @@ [version control integrations]: docs/INTEGRATION.md#version-control [create an issue]: https://github.com/hadolint/hadolint/issues/new [dockerfile reference]: http://docs.docker.com/engine/reference/builder/-[syntax.hs]: https://www.stackage.org/haddock/nightly-2018-01-07/language-docker-2.0.1/Language-Docker-Syntax.html+[syntax.hs]: https://www.stackage.org/haddock/nightly-2022-11-15/language-docker-12.0.0/Language-Docker-Syntax.html [rfc3339]: https://www.ietf.org/rfc/rfc3339.txt [semver]: https://semver.org/ [rfc3986]: https://www.ietf.org/rfc/rfc3986.txt
hadolint.cabal view
@@ -1,332 +1,333 @@-cabal-version: 2.0---- This file has been generated from package.yaml by hpack version 0.34.7.------ see: https://github.com/sol/hpack+cabal-version:      2.0+name:               hadolint+version:            2.13.1+synopsis:           Dockerfile Linter JavaScript API+description:+  A smarter Dockerfile linter that helps you build best practice Docker images. -name:           hadolint-version:        2.12.0-synopsis:       Dockerfile Linter JavaScript API-description:    A smarter Dockerfile linter that helps you build best practice Docker images.-category:       Development-homepage:       https://github.com/hadolint/hadolint-author:         Lukas Martinelli-maintainer:     me@lukasmartinelli.ch-copyright:      Lukas Martinelli-license:        GPL-3-license-file:   LICENSE-build-type:     Simple-extra-source-files:-    README.md+category:           Development+homepage:           https://github.com/hadolint/hadolint+author:             Lukas Martinelli+maintainer:         me@lukasmartinelli.ch+copyright:          Lukas Martinelli+license:            GPL-3+license-file:       LICENSE+build-type:         Simple+extra-source-files: README.md  source-repository head-  type: git+  type:     git   location: git@github.com:hadolint/hadolint.git -flag static-  description: Use static linking for the hadolint executable-  manual: True-  default: True- library   exposed-modules:-      Hadolint-      Hadolint.Config-      Hadolint.Config.Commandline-      Hadolint.Config.Configfile-      Hadolint.Config.Configuration-      Hadolint.Config.Environment-      Hadolint.Formatter-      Hadolint.Formatter.Checkstyle-      Hadolint.Formatter.Codacy-      Hadolint.Formatter.Codeclimate-      Hadolint.Formatter.Format-      Hadolint.Formatter.Gnu-      Hadolint.Formatter.Json-      Hadolint.Formatter.Sarif-      Hadolint.Formatter.SonarQube-      Hadolint.Formatter.TTY-      Hadolint.Lint-      Hadolint.Meta-      Hadolint.Pragma-      Hadolint.Process-      Hadolint.Rule-      Hadolint.Rule.DL1001-      Hadolint.Rule.DL3000-      Hadolint.Rule.DL3001-      Hadolint.Rule.DL3002-      Hadolint.Rule.DL3003-      Hadolint.Rule.DL3004-      Hadolint.Rule.DL3005-      Hadolint.Rule.DL3006-      Hadolint.Rule.DL3007-      Hadolint.Rule.DL3008-      Hadolint.Rule.DL3009-      Hadolint.Rule.DL3010-      Hadolint.Rule.DL3011-      Hadolint.Rule.DL3012-      Hadolint.Rule.DL3013-      Hadolint.Rule.DL3014-      Hadolint.Rule.DL3015-      Hadolint.Rule.DL3016-      Hadolint.Rule.DL3018-      Hadolint.Rule.DL3019-      Hadolint.Rule.DL3020-      Hadolint.Rule.DL3021-      Hadolint.Rule.DL3022-      Hadolint.Rule.DL3023-      Hadolint.Rule.DL3024-      Hadolint.Rule.DL3025-      Hadolint.Rule.DL3026-      Hadolint.Rule.DL3027-      Hadolint.Rule.DL3028-      Hadolint.Rule.DL3029-      Hadolint.Rule.DL3030-      Hadolint.Rule.DL3032-      Hadolint.Rule.DL3033-      Hadolint.Rule.DL3034-      Hadolint.Rule.DL3035-      Hadolint.Rule.DL3036-      Hadolint.Rule.DL3037-      Hadolint.Rule.DL3038-      Hadolint.Rule.DL3040-      Hadolint.Rule.DL3041-      Hadolint.Rule.DL3042-      Hadolint.Rule.DL3043-      Hadolint.Rule.DL3044-      Hadolint.Rule.DL3045-      Hadolint.Rule.DL3046-      Hadolint.Rule.DL3047-      Hadolint.Rule.DL3048-      Hadolint.Rule.DL3049-      Hadolint.Rule.DL3050-      Hadolint.Rule.DL3051-      Hadolint.Rule.DL3052-      Hadolint.Rule.DL3053-      Hadolint.Rule.DL3054-      Hadolint.Rule.DL3055-      Hadolint.Rule.DL3056-      Hadolint.Rule.DL3057-      Hadolint.Rule.DL3058-      Hadolint.Rule.DL3059-      Hadolint.Rule.DL3060-      Hadolint.Rule.DL3061-      Hadolint.Rule.DL4000-      Hadolint.Rule.DL4001-      Hadolint.Rule.DL4003-      Hadolint.Rule.DL4004-      Hadolint.Rule.DL4005-      Hadolint.Rule.DL4006-      Hadolint.Rule.Shellcheck-      Hadolint.Shell-  other-modules:-      Paths_hadolint-  autogen-modules:-      Paths_hadolint-  hs-source-dirs:-      src+    Hadolint+    Hadolint.Config+    Hadolint.Config.Commandline+    Hadolint.Config.Configfile+    Hadolint.Config.Configuration+    Hadolint.Config.Environment+    Hadolint.Formatter+    Hadolint.Formatter.Checkstyle+    Hadolint.Formatter.Codacy+    Hadolint.Formatter.Codeclimate+    Hadolint.Formatter.Format+    Hadolint.Formatter.Gnu+    Hadolint.Formatter.Json+    Hadolint.Formatter.Sarif+    Hadolint.Formatter.SonarQube+    Hadolint.Formatter.TTY+    Hadolint.Lint+    Hadolint.Meta+    Hadolint.Pragma+    Hadolint.Process+    Hadolint.Rule+    Hadolint.Rule.DL1001+    Hadolint.Rule.DL3000+    Hadolint.Rule.DL3001+    Hadolint.Rule.DL3002+    Hadolint.Rule.DL3003+    Hadolint.Rule.DL3004+    Hadolint.Rule.DL3006+    Hadolint.Rule.DL3007+    Hadolint.Rule.DL3008+    Hadolint.Rule.DL3009+    Hadolint.Rule.DL3010+    Hadolint.Rule.DL3011+    Hadolint.Rule.DL3012+    Hadolint.Rule.DL3013+    Hadolint.Rule.DL3014+    Hadolint.Rule.DL3015+    Hadolint.Rule.DL3016+    Hadolint.Rule.DL3018+    Hadolint.Rule.DL3019+    Hadolint.Rule.DL3020+    Hadolint.Rule.DL3021+    Hadolint.Rule.DL3022+    Hadolint.Rule.DL3023+    Hadolint.Rule.DL3024+    Hadolint.Rule.DL3025+    Hadolint.Rule.DL3026+    Hadolint.Rule.DL3027+    Hadolint.Rule.DL3028+    Hadolint.Rule.DL3029+    Hadolint.Rule.DL3030+    Hadolint.Rule.DL3032+    Hadolint.Rule.DL3033+    Hadolint.Rule.DL3034+    Hadolint.Rule.DL3035+    Hadolint.Rule.DL3036+    Hadolint.Rule.DL3037+    Hadolint.Rule.DL3038+    Hadolint.Rule.DL3040+    Hadolint.Rule.DL3041+    Hadolint.Rule.DL3042+    Hadolint.Rule.DL3043+    Hadolint.Rule.DL3044+    Hadolint.Rule.DL3045+    Hadolint.Rule.DL3046+    Hadolint.Rule.DL3047+    Hadolint.Rule.DL3048+    Hadolint.Rule.DL3049+    Hadolint.Rule.DL3050+    Hadolint.Rule.DL3051+    Hadolint.Rule.DL3052+    Hadolint.Rule.DL3053+    Hadolint.Rule.DL3054+    Hadolint.Rule.DL3055+    Hadolint.Rule.DL3056+    Hadolint.Rule.DL3057+    Hadolint.Rule.DL3058+    Hadolint.Rule.DL3059+    Hadolint.Rule.DL3060+    Hadolint.Rule.DL3061+    Hadolint.Rule.DL4000+    Hadolint.Rule.DL4001+    Hadolint.Rule.DL4003+    Hadolint.Rule.DL4004+    Hadolint.Rule.DL4005+    Hadolint.Rule.DL4006+    Hadolint.Rule.Shellcheck+    Hadolint.Shell++  other-modules:      Paths_hadolint+  autogen-modules:    Paths_hadolint+  hs-source-dirs:     src   default-extensions:-      DeriveAnyClass-      DeriveGeneric-      NamedFieldPuns-      OverloadedStrings-      PatternSynonyms-      RecordWildCards-      ScopedTypeVariables-      StrictData-      TemplateHaskell-      TupleSections-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path -flate-dmd-anal+    DeriveAnyClass+    DeriveGeneric+    NamedFieldPuns+    OverloadedStrings+    PatternSynonyms+    RecordWildCards+    ScopedTypeVariables+    StrictData+    TemplateHaskell+    TupleSections++  ghc-options:+    -Wall -Wcompat -Wincomplete-record-updates+    -Wincomplete-uni-patterns -Wredundant-constraints+    -optP-Wno-nonportable-include-path -flate-dmd-anal+   build-depends:-      Cabal-    , HsYAML-    , ShellCheck >=0.8.0-    , aeson-    , base >=4.8 && <5-    , bytestring-    , colourista-    , containers-    , cryptonite-    , data-default-    , deepseq >=1.4.4 && <1.5-    , directory >=1.3.0-    , email-validate-    , filepath-    , foldl-    , gitrev >=1.3.1-    , ilist-    , language-docker >=11.0.0 && <12-    , megaparsec >=9.0.0-    , mtl-    , network-uri-    , optparse-applicative >=0.14.0-    , parallel-    , parsec >=3.1.14-    , prettyprinter >=1.7.0-    , semver-    , spdx-    , split >=0.2-    , text-    , time-    , timerep >=2.0-    , void-  default-language: Haskell2010+      aeson                 >=2.2.3    && <2.3+    , base                  >=4.20.1   && <5+    , base16-bytestring     >=1.0.2    && <1.1+    , bytestring            >=0.12.2   && <0.13+    , Cabal                 >=3.12.1   && <3.13+    , colourista            >=0.1.0    && <0.2+    , containers            >=0.7      && <0.8+    , cryptohash-sha1       >=0.11.101 && <0.12+    , data-default          >=0.8.0    && <0.9+    , deepseq               >=1.5.0    && <1.6+    , directory             >=1.3.8    && <1.4+    , email-validate        >=2.3.2    && <2.4+    , filepath              >=1.5.4    && <1.6+    , foldl                 >=1.4.18   && <1.5+    , gitrev                >=1.3.1    && <1.4+    , HsYAML                >=0.2.1    && <0.3+    , ilist                 >=0.3.1    && <0.4+    , language-docker       >=14.0.1   && <15+    , megaparsec            >=9.0.0    && <9.8+    , mtl                   >=2.3.1    && <2.4+    , network-uri           >=2.6.4    && <2.7+    , optparse-applicative  >=0.19.0   && <0.20+    , parallel              >=3.2.2    && <3.3+    , parsec                >=3.1.18   && <3.2+    , prettyprinter         >=1.7.1    && <1.8+    , semver                >=0.4.0    && <0.5+    , ShellCheck            >=0.11.0   && <0.12+    , spdx                  >=1.1      && <1.2+    , split                 >=0.2.5    && <0.3+    , text                  >=2.1.2    && <2.2+    , time                  >=1.12.2   && <1.13+    , timerep               >=2.1.0    && <2.2+    , void                  >=0.7.3    && <0.8+    , xml-conduit           >=1.10.0   && <1.11 +  default-language:   GHC2021+ executable hadolint-  main-is: Main.hs-  other-modules:-      Paths_hadolint-  autogen-modules:-      Paths_hadolint-  hs-source-dirs:-      app+  main-is:            Main.hs+  other-modules:      Paths_hadolint+  autogen-modules:    Paths_hadolint+  hs-source-dirs:     app   default-extensions:-      DeriveAnyClass-      DeriveGeneric-      NamedFieldPuns-      OverloadedStrings-      PatternSynonyms-      RecordWildCards-      ScopedTypeVariables-      StrictData-      TemplateHaskell-      TupleSections-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path -flate-dmd-anal -O2 -threaded -rtsopts "-with-rtsopts=-N5 -A4m"+    DeriveAnyClass+    DeriveGeneric+    NamedFieldPuns+    OverloadedStrings+    PatternSynonyms+    RecordWildCards+    ScopedTypeVariables+    StrictData+    TemplateHaskell+    TupleSections++  ghc-options:+    -Wall -Wcompat -Wincomplete-record-updates+    -Wincomplete-uni-patterns -Wredundant-constraints+    -optP-Wno-nonportable-include-path -flate-dmd-anal -threaded+    -rtsopts "-with-rtsopts=-N5 -A4m"+   build-depends:-      base >=4.8 && <5-    , containers-    , data-default+      base                  >=4.20.1    && <5+    , containers            >=0.7       && <0.8+    , data-default          >=0.8.0     && <0.9     , hadolint-    , language-docker >=11.0.0 && <12-    , megaparsec >=9.0.0-    , optparse-applicative >=0.14.0-    , prettyprinter >=1.7.0-    , text-  if flag(static) && !(os(osx))-    ld-options: -static -pthread-  default-language: Haskell2010+    , language-docker       >=14.0.1    && <15+    , megaparsec            >=9.7.0     && <9.8+    , optparse-applicative  >=0.19.0    && <0.20+    , prettyprinter         >=1.7.1     && <1.8+    , text                  >=2.1.2     && <2.2 +  default-language:   GHC2021+ test-suite hadolint-unit-tests-  type: exitcode-stdio-1.0-  main-is: Spec.hs+  type:               exitcode-stdio-1.0+  main-is:            Spec.hs   other-modules:-      Hadolint.Config.CommandlineSpec-      Hadolint.Config.ConfigfileSpec-      Hadolint.Config.ConfigurationSpec-      Hadolint.Config.EnvironmentSpec-      Hadolint.Config.SpecHook-      Hadolint.Formatter.GnuSpec-      Hadolint.Formatter.ParseErrorSpec-      Hadolint.Formatter.SarifSpec-      Hadolint.Formatter.TTYSpec-      Hadolint.PragmaSpec-      Hadolint.Rule.DL1001Spec-      Hadolint.Rule.DL3000Spec-      Hadolint.Rule.DL3001Spec-      Hadolint.Rule.DL3002Spec-      Hadolint.Rule.DL3003Spec-      Hadolint.Rule.DL3004Spec-      Hadolint.Rule.DL3005Spec-      Hadolint.Rule.DL3006Spec-      Hadolint.Rule.DL3007Spec-      Hadolint.Rule.DL3008Spec-      Hadolint.Rule.DL3009Spec-      Hadolint.Rule.DL3010Spec-      Hadolint.Rule.DL3011Spec-      Hadolint.Rule.DL3012Spec-      Hadolint.Rule.DL3013Spec-      Hadolint.Rule.DL3014Spec-      Hadolint.Rule.DL3015Spec-      Hadolint.Rule.DL3016Spec-      Hadolint.Rule.DL3018Spec-      Hadolint.Rule.DL3019Spec-      Hadolint.Rule.DL3020Spec-      Hadolint.Rule.DL3021Spec-      Hadolint.Rule.DL3022Spec-      Hadolint.Rule.DL3023Spec-      Hadolint.Rule.DL3024Spec-      Hadolint.Rule.DL3025Spec-      Hadolint.Rule.DL3026Spec-      Hadolint.Rule.DL3027Spec-      Hadolint.Rule.DL3028Spec-      Hadolint.Rule.DL3029Spec-      Hadolint.Rule.DL3030Spec-      Hadolint.Rule.DL3032Spec-      Hadolint.Rule.DL3033Spec-      Hadolint.Rule.DL3034Spec-      Hadolint.Rule.DL3035Spec-      Hadolint.Rule.DL3036Spec-      Hadolint.Rule.DL3037Spec-      Hadolint.Rule.DL3038Spec-      Hadolint.Rule.DL3040Spec-      Hadolint.Rule.DL3041Spec-      Hadolint.Rule.DL3042Spec-      Hadolint.Rule.DL3043Spec-      Hadolint.Rule.DL3044Spec-      Hadolint.Rule.DL3045Spec-      Hadolint.Rule.DL3046Spec-      Hadolint.Rule.DL3047Spec-      Hadolint.Rule.DL3048Spec-      Hadolint.Rule.DL3049Spec-      Hadolint.Rule.DL3050Spec-      Hadolint.Rule.DL3051Spec-      Hadolint.Rule.DL3052Spec-      Hadolint.Rule.DL3053Spec-      Hadolint.Rule.DL3054Spec-      Hadolint.Rule.DL3055Spec-      Hadolint.Rule.DL3056Spec-      Hadolint.Rule.DL3057Spec-      Hadolint.Rule.DL3058Spec-      Hadolint.Rule.DL3059Spec-      Hadolint.Rule.DL3060Spec-      Hadolint.Rule.DL3061Spec-      Hadolint.Rule.DL4000Spec-      Hadolint.Rule.DL4001Spec-      Hadolint.Rule.DL4003Spec-      Hadolint.Rule.DL4004Spec-      Hadolint.Rule.DL4005Spec-      Hadolint.Rule.DL4006Spec-      Hadolint.Rule.ShellcheckSpec-      Hadolint.ShellSpec-      Helpers-      RegressionSpec-      Paths_hadolint-  autogen-modules:-      Paths_hadolint-  hs-source-dirs:-      test+    Hadolint.Config.CommandlineSpec+    Hadolint.Config.ConfigfileSpec+    Hadolint.Config.ConfigurationSpec+    Hadolint.Config.EnvironmentSpec+    Hadolint.Config.SpecHook+    Hadolint.Formatter.GnuSpec+    Hadolint.Formatter.ParseErrorSpec+    Hadolint.Formatter.SarifSpec+    Hadolint.Formatter.TTYSpec+    Hadolint.PragmaSpec+    Hadolint.Rule.DL1001Spec+    Hadolint.Rule.DL3000Spec+    Hadolint.Rule.DL3001Spec+    Hadolint.Rule.DL3002Spec+    Hadolint.Rule.DL3003Spec+    Hadolint.Rule.DL3004Spec+    Hadolint.Rule.DL3006Spec+    Hadolint.Rule.DL3007Spec+    Hadolint.Rule.DL3008Spec+    Hadolint.Rule.DL3009Spec+    Hadolint.Rule.DL3010Spec+    Hadolint.Rule.DL3011Spec+    Hadolint.Rule.DL3012Spec+    Hadolint.Rule.DL3013Spec+    Hadolint.Rule.DL3014Spec+    Hadolint.Rule.DL3015Spec+    Hadolint.Rule.DL3016Spec+    Hadolint.Rule.DL3018Spec+    Hadolint.Rule.DL3019Spec+    Hadolint.Rule.DL3020Spec+    Hadolint.Rule.DL3021Spec+    Hadolint.Rule.DL3022Spec+    Hadolint.Rule.DL3023Spec+    Hadolint.Rule.DL3024Spec+    Hadolint.Rule.DL3025Spec+    Hadolint.Rule.DL3026Spec+    Hadolint.Rule.DL3027Spec+    Hadolint.Rule.DL3028Spec+    Hadolint.Rule.DL3029Spec+    Hadolint.Rule.DL3030Spec+    Hadolint.Rule.DL3032Spec+    Hadolint.Rule.DL3033Spec+    Hadolint.Rule.DL3034Spec+    Hadolint.Rule.DL3035Spec+    Hadolint.Rule.DL3036Spec+    Hadolint.Rule.DL3037Spec+    Hadolint.Rule.DL3038Spec+    Hadolint.Rule.DL3040Spec+    Hadolint.Rule.DL3041Spec+    Hadolint.Rule.DL3042Spec+    Hadolint.Rule.DL3043Spec+    Hadolint.Rule.DL3044Spec+    Hadolint.Rule.DL3045Spec+    Hadolint.Rule.DL3046Spec+    Hadolint.Rule.DL3047Spec+    Hadolint.Rule.DL3048Spec+    Hadolint.Rule.DL3049Spec+    Hadolint.Rule.DL3050Spec+    Hadolint.Rule.DL3051Spec+    Hadolint.Rule.DL3052Spec+    Hadolint.Rule.DL3053Spec+    Hadolint.Rule.DL3054Spec+    Hadolint.Rule.DL3055Spec+    Hadolint.Rule.DL3056Spec+    Hadolint.Rule.DL3057Spec+    Hadolint.Rule.DL3058Spec+    Hadolint.Rule.DL3059Spec+    Hadolint.Rule.DL3060Spec+    Hadolint.Rule.DL3061Spec+    Hadolint.Rule.DL4000Spec+    Hadolint.Rule.DL4001Spec+    Hadolint.Rule.DL4003Spec+    Hadolint.Rule.DL4004Spec+    Hadolint.Rule.DL4005Spec+    Hadolint.Rule.DL4006Spec+    Hadolint.Rule.ShellcheckSpec+    Hadolint.ShellSpec+    Helpers+    Paths_hadolint+    RegressionSpec++  autogen-modules:    Paths_hadolint+  hs-source-dirs:     test   default-extensions:-      DeriveAnyClass-      DeriveGeneric-      NamedFieldPuns-      OverloadedStrings-      PatternSynonyms-      RecordWildCards-      ScopedTypeVariables-      StrictData-      TemplateHaskell-      TupleSections-      ImplicitParams-      OverloadedLists-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path -flate-dmd-anal-  build-tool-depends:-      hspec-discover:hspec-discover ==2.*+    DeriveAnyClass+    DeriveGeneric+    ImplicitParams+    NamedFieldPuns+    OverloadedLists+    OverloadedStrings+    PatternSynonyms+    RecordWildCards+    ScopedTypeVariables+    StrictData+    TemplateHaskell+    TupleSections++  ghc-options:+    -Wall -Wcompat -Wincomplete-record-updates+    -Wincomplete-uni-patterns -Wredundant-constraints+    -optP-Wno-nonportable-include-path -flate-dmd-anal++  build-tool-depends: hspec-discover:hspec-discover >=2 && <3   build-depends:-      HUnit >=1.2-    , HsYAML-    , ShellCheck >=0.8.0-    , aeson-    , base >=4.8 && <5-    , bytestring >=0.10+      aeson+    , base+    , bytestring     , containers     , data-default     , foldl     , hadolint-    , hspec >=2.8.3-    , language-docker >=11.0.0 && <12-    , megaparsec >=9.0.0-    , optparse-applicative >=0.14.0+    , hspec                 >=2.8.3+    , HsYAML+    , HUnit                 >=1.2+    , language-docker+    , megaparsec+    , optparse-applicative+    , ShellCheck     , silently-    , split >=0.2+    , split     , text-  default-language: Haskell2010++  default-language:   GHC2021
src/Hadolint/Formatter.hs view
@@ -31,7 +31,7 @@     Checkstyle -> FormatCheckstyle.printResults allResults filePathInReport     Codacy -> FormatCodacy.printResults allResults     CodeclimateJson -> FormatCodeclimate.printResults allResults-    GitlabCodeclimateJson -> FormatCodeclimate.printGitlabResults allResults+    GitLabCodeclimateJson -> FormatCodeclimate.printGitLabResults allResults     Gnu -> FormatGnu.printResults allResults     Json -> FormatJson.printResults allResults     Sarif -> FormatSarif.printResults allResults
src/Hadolint/Formatter/Checkstyle.hs view
@@ -1,15 +1,11 @@-module Hadolint.Formatter.Checkstyle-  ( printResults,-    formatResult,-  )+module Hadolint.Formatter.Checkstyle ( printResults ) where -import qualified Control.Foldl as Foldl-import qualified Data.ByteString.Builder as Builder import qualified Data.ByteString.Lazy.Char8 as B-import Data.Char (isAsciiLower, isAsciiUpper, isDigit, ord)+import Data.Foldable+import qualified Data.Map as Map+import qualified Data.Maybe as Maybe import qualified Data.Text as Text-import Data.Text.Encoding (encodeUtf8Builder) import Hadolint.Formatter.Format   ( Result (..),     errorBundlePretty,@@ -17,7 +13,6 @@     severityText,   ) import Hadolint.Rule (CheckFailure (..), DLSeverity (..), RuleCode (..))-import System.IO (stdout) import Text.Megaparsec (TraversableStream) import Text.Megaparsec.Error   ( ParseErrorBundle,@@ -25,95 +20,91 @@   ) import Text.Megaparsec.Pos (sourceColumn, sourceLine, unPos) import Text.Megaparsec.Stream (VisualStream)--data CheckStyle = CheckStyle-  { line :: Int,-    column :: Int,-    impact :: Text.Text,-    msg :: Text.Text,-    source :: Text.Text-  }+import qualified Text.XML as XML -errorToCheckStyle :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => ParseErrorBundle s e -> CheckStyle-errorToCheckStyle err =-  CheckStyle-    { line = unPos (sourceLine pos),-      column = unPos (sourceColumn pos),-      impact = severityText DLErrorC,-      msg = Text.pack (errorBundlePretty err),-      source = "DL1000"+errorToNode ::+  (VisualStream s, TraversableStream s, ShowErrorComponent e) =>+  ParseErrorBundle s e -> XML.Node+errorToNode err =+  XML.NodeElement XML.Element+    { elementName = "error",+      elementAttributes =+        Map.fromList+          [ ("line", Text.pack $ show $ unPos $ sourceLine $ errorPosition err),+            ("column", Text.pack $ show $ unPos $ sourceColumn $ errorPosition err),+            ("severity", severityText DLErrorC),+            ("message", Text.pack $ errorBundlePretty err)+          ],+      elementNodes = []     }-  where-    pos = errorPosition err -ruleToCheckStyle :: CheckFailure -> CheckStyle-ruleToCheckStyle CheckFailure {..} =-  CheckStyle-    { line = line,-      column = 1,-      impact = severityText severity,-      msg = message,-      source = unRuleCode code+checkToNode :: CheckFailure -> XML.Node+checkToNode CheckFailure {..} =+  XML.NodeElement XML.Element+    { elementName = "error",+      elementAttributes =+        Map.fromList+          [ ("line", Text.pack $ show line),+            ("column", "1"),+            ("severity", severityText severity),+            ("message", message),+            ("source", unRuleCode code)+          ],+      elementNodes = []     } -toXml :: CheckStyle -> Builder.Builder-toXml CheckStyle {..} =-  "<error "-    <> attr "line" (Builder.intDec line)-    <> attr "column" (Builder.intDec column)-    <> attr "severity" (encode impact)-    <> attr "message" (encode msg)-    <> attr "source" (encode source)-    <> "/>"--encode :: Text.Text -> Builder.Builder-encode = encodeUtf8Builder . escape--attr :: Text.Text -> Builder.Builder -> Builder.Builder-attr name value = encodeUtf8Builder name <> "='" <> value <> "' "--escape :: Text.Text -> Text.Text-escape = Text.concatMap doEscape+renderNodes ::+  (VisualStream s, TraversableStream s, ShowErrorComponent e) =>+  Result s e -> [XML.Node]+renderNodes (Result _ errors checks) =+  if isEmpty then [] else toList ( errorNodes <> checkNodes )   where-    doEscape c =-      if isOk c-        then Text.singleton c-        else "&#" <> Text.pack (show (ord c)) <> ";"-    isOk x = any (\check -> check x) [isAsciiUpper, isAsciiLower, isDigit, (`elem` [' ', '.', '/'])]+    errorNodes = fmap errorToNode errors+    checkNodes = fmap checkToNode checks+    isEmpty = null checks && null errors -formatResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Maybe FilePath -> Builder.Builder-formatResult (Result filename errors checks) filePathInReport = header <> xmlBody <> footer+toFile ::+  (VisualStream s, TraversableStream s, ShowErrorComponent e) =>+  Result s e -> Maybe FilePath -> XML.Node+toFile results filePathInReport =+  XML.NodeElement XML.Element+    { elementName = "file",+      elementAttributes = Map.fromList [("name", filepath)],+      elementNodes = renderNodes results+    }   where-    xmlBody = Foldl.fold (Foldl.premap toXml Foldl.mconcat) issues--    issues = checkstyleErrors <> checkstyleChecks-    checkstyleErrors = fmap errorToCheckStyle errors-    checkstyleChecks = fmap ruleToCheckStyle checks+    filepath = if null filePathInReport then filename results else getFilePath filePathInReport+    filename Result {fileName=fn} = fn -    isEmpty = null checks && null errors-    name = if null filePathInReport then filename else getFilePath filePathInReport-    header =-      if isEmpty-        then ""-        else "<file " <> attr "name" (encode name) <> ">"-    footer = if isEmpty then "" else "</file>"+renderResults ::+  (Foldable f, VisualStream s, TraversableStream s, ShowErrorComponent e) =>+  f (Result s e) -> Maybe FilePath -> XML.Element+renderResults results filePathInReport = XML.Element+  { elementName = "checkstyle",+    elementAttributes = Map.fromList [("version", "4.3")],+    elementNodes = Maybe.mapMaybe maybeFile ( toList results )+  }+  where+    maybeFile r = if isEmpty r then Nothing else Just $ toFile r filePathInReport+    isEmpty Result {errors=e, checks=c} = null e && null c  printResults ::   (Foldable f, VisualStream s, TraversableStream s, ShowErrorComponent e) =>-  f (Result s e) -> Maybe FilePath ->-  IO ()-printResults results filePathInReport = do-  B.putStr header-  mapM_ put results-  B.putStr footer+  f (Result s e) -> Maybe FilePath -> IO ()+printResults results filePathInReport =+  B.putStr $ XML.renderLBS settings document   where-    header = "<?xml version='1.0' encoding='UTF-8'?><checkstyle version='4.3'>"-    footer = "</checkstyle>"-    put result = Builder.hPutBuilder stdout (formatResult result filePathInReport)+    settings = XML.def -- use default render settings+    document =+      XML.Document+        { documentPrologue = XML.Prologue [] Nothing [],+          documentRoot = renderResults results filePathInReport,+          documentEpilogue = []+        } -getFilePath :: Maybe FilePath -> Text.Text +getFilePath :: Maybe FilePath -> Text.Text getFilePath Nothing = "" getFilePath (Just filePath) = toText [filePath] -toText :: [FilePath] -> Text.Text +toText :: [FilePath] -> Text.Text toText = foldMap Text.pack
src/Hadolint/Formatter/Codeclimate.hs view
@@ -1,15 +1,17 @@ module Hadolint.Formatter.Codeclimate   ( printResults,-    printGitlabResults,+    printGitLabResults,     formatResult,-    formatGitlabResult,+    formatGitLabResult,   ) where  import qualified Control.Foldl as Foldl-import Crypto.Hash (Digest, SHA1 (..), hash)+import qualified Crypto.Hash.SHA1 as SHA1 import Data.Aeson hiding (Result) import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Base16 as B16+import Data.ByteString.Char8 as Char8 import Data.Sequence (Seq) import qualified Data.Text as Text import GHC.Generics@@ -29,7 +31,7 @@  data FingerprintIssue = FingerprintIssue   { issue :: Issue,-    fingerprint :: Digest SHA1+    fingerprint :: ByteString   }  data Location@@ -68,7 +70,7 @@   toJSON FingerprintIssue {..} =     object       [ "type" .= ("issue" :: Text.Text),-        "fingerprint" .= show fingerprint,+        "fingerprint" .= Char8.unpack fingerprint,         "check_name" .= checkName issue,         "description" .= description issue,         "categories" .= (["Bug Risk"] :: [Text.Text]),@@ -107,8 +109,8 @@     DLStyleC -> "minor"     _ -> "" -generateFingerprint :: Issue -> Digest SHA1-generateFingerprint = hash . B.toStrict . encode+generateFingerprint :: Issue -> ByteString+generateFingerprint = B16.encode . SHA1.hashlazy . encode  issueToFingerprintIssue :: Issue -> FingerprintIssue issueToFingerprintIssue i =@@ -120,8 +122,8 @@ formatResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Seq Issue formatResult (Result filename errors checks) = (errorToIssue <$> errors) <> (checkToIssue filename <$> checks) -formatGitlabResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Seq FingerprintIssue-formatGitlabResult result = issueToFingerprintIssue <$> formatResult result+formatGitLabResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> Seq FingerprintIssue+formatGitLabResult result = issueToFingerprintIssue <$> formatResult result  printResult :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => Result s e -> IO () printResult result = mapM_ output (formatResult result)@@ -133,7 +135,7 @@ printResults :: (VisualStream s, TraversableStream s, ShowErrorComponent e, Foldable f) => f (Result s e) -> IO () printResults = mapM_ printResult -printGitlabResults :: (Foldable f, VisualStream s, TraversableStream s, ShowErrorComponent e) => f (Result s e) -> IO ()-printGitlabResults results = B.putStr . encode $ flattened+printGitLabResults :: (Foldable f, VisualStream s, TraversableStream s, ShowErrorComponent e) => f (Result s e) -> IO ()+printGitLabResults results = B.putStr . encode $ flattened   where-    flattened = Foldl.fold (Foldl.premap formatGitlabResult Foldl.mconcat) results+    flattened = Foldl.fold (Foldl.premap formatGitLabResult Foldl.mconcat) results
src/Hadolint/Formatter/Format.hs view
@@ -32,7 +32,7 @@   | SonarQube   | TTY   | CodeclimateJson-  | GitlabCodeclimateJson+  | GitLabCodeclimateJson   | Gnu   | Checkstyle   | Codacy@@ -44,7 +44,7 @@   pretty SonarQube = "sonarqube"   pretty TTY = "tty"   pretty CodeclimateJson = "codeclimate"-  pretty GitlabCodeclimateJson = "gitlab_codeclimate"+  pretty GitLabCodeclimateJson = "gitlab_codeclimate"   pretty Gnu = "gnu"   pretty Checkstyle = "checkstyle"   pretty Codacy = "codacy"@@ -77,7 +77,7 @@ readMaybeOutputFormat "sonarqube" = Just SonarQube readMaybeOutputFormat "tty" = Just TTY readMaybeOutputFormat "codeclimate" = Just CodeclimateJson-readMaybeOutputFormat "gitlab_codeclimate" = Just GitlabCodeclimateJson+readMaybeOutputFormat "gitlab_codeclimate" = Just GitLabCodeclimateJson readMaybeOutputFormat "gnu" = Just Gnu readMaybeOutputFormat "checkstyle" = Just Checkstyle readMaybeOutputFormat "codacy" = Just Codacy
src/Hadolint/Pragma.hs view
@@ -46,8 +46,14 @@ ignoreParser = hadolintPragma >> ignore  globalIgnoreParser :: Megaparsec.Parsec Void Text [Text]-globalIgnoreParser = hadolintPragma >> string "global" >> spaces1 >> ignore+globalIgnoreParser = hadolintPragma >> global >> ignore +hadolintPragma :: Megaparsec.Parsec Void Text Text+hadolintPragma = spaces >> string "hadolint" >> spaces1++global :: Megaparsec.Parsec Void Text Text+global = string "global" >> spaces1+ ignore :: Megaparsec.Parsec Void Text [Text] ignore = string "ignore" >> spaces >> string "=" >> spaces >> ruleList @@ -55,8 +61,9 @@ ruleList = Megaparsec.sepBy1 ruleName ( spaces >> string "," >> spaces )  ruleName :: Megaparsec.ParsecT Void Text Identity (Megaparsec.Tokens Text)-ruleName = Megaparsec.takeWhile1P Nothing (\c -> c `elem` Set.fromList "DLSC0123456789")-+ruleName =+  Megaparsec.takeWhile1P Nothing (\c -> c `elem` Set.fromList "DLSC0123456789")+  <* inlineComment  parseShell :: Text -> Maybe Text parseShell = Megaparsec.parseMaybe shellParser@@ -65,12 +72,13 @@ shellParser = hadolintPragma >> string "shell" >> spaces >> string "=" >> spaces >> shellName  shellName :: Megaparsec.ParsecT Void Text Identity (Megaparsec.Tokens Text)-shellName = Megaparsec.takeWhile1P Nothing (/= '\n')---hadolintPragma :: Megaparsec.Parsec Void Text Text-hadolintPragma = spaces >> string "hadolint" >> spaces1+shellName =+  Megaparsec.takeWhile1P Nothing (\c -> c `notElem` Set.fromList "\n\t ")+  <* inlineComment +inlineComment :: Megaparsec.Parsec Void Text (Maybe Text)+inlineComment =+  spaces >> Megaparsec.optional ( string "#" >> Megaparsec.takeWhileP Nothing (/= '\n') )  string :: Megaparsec.Tokens Text   -> Megaparsec.ParsecT Void Text Identity (Megaparsec.Tokens Text)
src/Hadolint/Process.hs view
@@ -15,7 +15,6 @@ import qualified Hadolint.Rule.DL3002 import qualified Hadolint.Rule.DL3003 import qualified Hadolint.Rule.DL3004-import qualified Hadolint.Rule.DL3005 import qualified Hadolint.Rule.DL3006 import qualified Hadolint.Rule.DL3007 import qualified Hadolint.Rule.DL3008@@ -120,7 +119,6 @@     <> Hadolint.Rule.DL3002.rule     <> Hadolint.Rule.DL3003.rule     <> Hadolint.Rule.DL3004.rule-    <> Hadolint.Rule.DL3005.rule     <> Hadolint.Rule.DL3006.rule     <> Hadolint.Rule.DL3007.rule     <> Hadolint.Rule.DL3008.rule
src/Hadolint/Rule/DL1001.hs view
@@ -11,7 +11,7 @@   where     code = "DL1001"     severity = DLIgnoreC-    message = "Please refrain from using inline igore pragmas \+    message = "Please refrain from using inline ignore pragmas \               \ `# hadolint ignore=DLxxxx`."     check (Comment com) =       case parseIgnorePragma com of
− src/Hadolint/Rule/DL3005.hs
@@ -1,22 +0,0 @@-module Hadolint.Rule.DL3005 (rule) where--import Hadolint.Rule-import Hadolint.Shell (ParsedShell)-import qualified Hadolint.Shell as Shell-import Language.Docker.Syntax (Instruction (..), RunArgs (..))---rule :: Rule ParsedShell-rule = dl3005 <> onbuild dl3005-{-# INLINEABLE rule #-}--dl3005 :: Rule ParsedShell-dl3005 = simpleRule code severity message check-  where-    code = "DL3005"-    severity = DLErrorC-    message = "Do not use apt-get dist-upgrade"-    check (Run (RunArgs args _)) =-      foldArguments (Shell.noCommands (Shell.cmdHasArgs "apt-get" ["dist-upgrade"])) args-    check _ = True-{-# INLINEABLE dl3005 #-}
src/Hadolint/Rule/DL3006.hs view
@@ -1,6 +1,7 @@ module Hadolint.Rule.DL3006 (rule) where  import qualified Data.Set as Set+import qualified Data.Text as Text import Data.Text (Text) import Hadolint.Rule import Language.Docker.Syntax@@ -21,7 +22,7 @@               -- When the image being used is a previously defined FROM alias,               -- then we can safely ignore that the image is not tagged. Otherwise               -- we marked it as a failure-              if Set.member i (state st)+              if Text.isPrefixOf "$" i || Set.member i (state st)                 then newState                 else newState |> addFail (CheckFailure {..})             _ -> newState
src/Hadolint/Rule/DL3009.hs view
@@ -28,7 +28,7 @@   where     code = "DL3009"     severity = DLInfoC-    message = "Delete the apt-get lists after installing something"+    message = "Delete the apt lists (/var/lib/apt/lists) after installing something"      check line st (From from) = st |> modify (rememberStage line from)     check line st (Run (RunArgs args flags))@@ -76,8 +76,12 @@       any (Shell.cmdHasArgs "rm" ["-rf", "/var/lib/apt/lists/*"]) (Shell.presentCommands args)  hasUpdate :: Shell.ParsedShell -> Bool-hasUpdate args =-  any (Shell.cmdHasArgs "apt-get" ["update"]) (Shell.presentCommands args)+hasUpdate args = any isPackageUpdate (Shell.presentCommands args)+  where+    isPackageUpdate cmd =+      Shell.cmdHasArgs "apt" ["update"] cmd ||+      Shell.cmdHasArgs "apt-get" ["update"] cmd ||+      Shell.cmdHasArgs "aptitude" ["update"] cmd  disabledDockerClean :: Shell.ParsedShell -> Bool disabledDockerClean args
src/Hadolint/Rule/DL3010.hs view
@@ -3,14 +3,13 @@ import Data.Foldable (toList) import Data.Function ((&)) import Data.List.NonEmpty (NonEmpty)-import qualified Data.Set as Set-import qualified Data.Sequence as Seq-import qualified Data.Text as Text+import Data.Sequence qualified as Seq+import Data.Set qualified as Set+import Data.Text qualified as Text import Hadolint.Rule-import qualified Hadolint.Shell as Shell+import Hadolint.Shell qualified as Shell import Language.Docker.Syntax - data Acc   = Acc       { archives :: Set.Set (Linenumber, Text.Text),@@ -26,7 +25,7 @@     message = "Use `ADD` for extracting archives into an image"      check _ _ (From _) = emptyState Empty-    check line st (Copy (CopyArgs srcs tgt) (CopyFlags _ _ _ NoSource)) =+    check line st (Copy (CopyArgs srcs tgt) (CopyFlags _ _ _ NoSource _)) =       st |> modify (rememberArchives line srcs tgt)     check _ st (Run (RunArgs args _))       | Acc archives _ <- state st,@@ -44,7 +43,6 @@     makeFail (line, _) = CheckFailure {..} {-# INLINEABLE rule #-} - extractsThisArchive :: (Linenumber, Text.Text) -> Shell.Command -> Bool extractsThisArchive (_, archive) cmd =   (isTarExtractCommand cmd || isUnzipCommand cmd) && archive `elem` arguments@@ -72,22 +70,22 @@  isUnzipCommand :: Shell.Command -> Bool isUnzipCommand (Shell.Command name _ _) =-  name `elem`-    [ "unzip",-      "gunzip",-      "bunzip2",-      "unlzma",-      "unxz",-      "zgz",-      "uncompress",-      "zcat",-      "gzcat"-    ]+  name+    `elem` [ "unzip",+             "gunzip",+             "bunzip2",+             "unlzma",+             "unxz",+             "zgz",+             "uncompress",+             "zcat",+             "gzcat"+           ]  markExtracted :: Set.Set (Linenumber, Text.Text) -> Acc -> Acc markExtracted _ Empty = Empty markExtracted exarcv Acc {archives, extracted} =-  Acc { archives, extracted = Set.union exarcv extracted }+  Acc {archives, extracted = Set.union exarcv extracted}  rememberArchives ::   Linenumber ->@@ -97,38 +95,42 @@   Acc rememberArchives line paths target Empty =   if isArchive $ unTargetPath target-    then Acc-          { archives = Set.singleton (line, basename $ unTargetPath target),-            extracted = Set.empty-          }-    else Acc-          { archives =-              paths-                & toList-                & map (basename . unSourcePath)-                & Set.fromList-                & Set.filter isArchive-                & Set.map (line,),-            extracted = Set.empty-          }+    then+      Acc+        { archives = Set.singleton (line, basename $ unTargetPath target),+          extracted = Set.empty+        }+    else+      Acc+        { archives =+            paths+              & toList+              & map (basename . unSourcePath)+              & Set.fromList+              & Set.filter isArchive+              & Set.map (line,),+          extracted = Set.empty+        } rememberArchives line paths target Acc {archives, extracted} =   if isArchive $ unTargetPath target-    then Acc-          { archives =-              Set.insert (line, basename $ unTargetPath target) archives,-            extracted-          }-    else Acc-          { archives =-              paths-                & toList-                & map (basename . unSourcePath)-                & Set.fromList-                & Set.filter isArchive-                & Set.map (line,)-                & Set.union archives,-            extracted-          }+    then+      Acc+        { archives =+            Set.insert (line, basename $ unTargetPath target) archives,+          extracted+        }+    else+      Acc+        { archives =+            paths+              & toList+              & map (basename . unSourcePath)+              & Set.fromList+              & Set.filter isArchive+              & Set.map (line,)+              & Set.union archives,+          extracted+        }  basename :: Text.Text -> Text.Text basename = Text.takeWhileEnd (\c -> c /= '/' && c /= '\\') . dropQuotes
src/Hadolint/Rule/DL3011.hs view
@@ -10,7 +10,7 @@     severity = DLErrorC     message = "Valid UNIX ports range from 0 to 65535"     check (Expose (Ports ports)) =-      and [p <= 65535 | Port p _ <- ports]-        && and [l <= 65535 && m <= 65535 | PortRange l m _ <- ports]+      and [p <= 65535 | PortSpec (Port p _) <- ports]+        && and [l <= 65535 && m <= 65535 | PortRangeSpec (PortRange (Port l _) (Port m _)) <- ports]     check _ = True {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3014.hs view
@@ -22,5 +22,9 @@      forgotAptYesOption cmd = isAptGetInstall cmd && not (hasYesOption cmd)     isAptGetInstall = Shell.cmdHasArgs "apt-get" ["install"]-    hasYesOption = Shell.hasAnyFlag ["y", "yes", "q", "assume-yes"]+    hasYesOption cmd =+      Shell.hasAnyFlag ["y", "yes", "qq", "assume-yes"] cmd+        || ( Shell.countFlag "q" cmd == 2 )+        || ( Shell.countFlag "quiet" cmd == 2 )+        || "-q=2" `elem` Shell.getArgs cmd {-# INLINEABLE dl3014 #-}
src/Hadolint/Rule/DL3022.hs view
@@ -1,21 +1,46 @@ module Hadolint.Rule.DL3022 (rule) where -import qualified Data.Set as Set-import qualified Data.Text as Text+import Data.Set qualified as Set+import Data.Text qualified as Text+import Data.Text.Read qualified as Read import Hadolint.Rule import Language.Docker.Syntax +data Acc+  = Acc {count :: Int, names :: Set.Set Text.Text}+  | Empty+  deriving (Eq)+ rule :: Rule args-rule = customRule check (emptyState Set.empty)+rule = customRule check (emptyState Empty)   where     code = "DL3022"     severity = DLWarningC     message = "`COPY --from` should reference a previously defined `FROM` alias" -    check _ st (From BaseImage {alias = Just (ImageAlias als)}) = st |> modify (Set.insert als)-    check line st (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource s)))+    check _ st (From BaseImage {alias = Just (ImageAlias als)}) = st |> modify (incAndAddName als)+    check _ st (From BaseImage {}) = st |> modify incCount+    check line st (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource s) _))       | ":" `Text.isInfixOf` dropQuotes s = st-      | Set.member s (state st) = st-      | otherwise = st |> addFail CheckFailure {..}+      | isMember s (state st) = st+      | otherwise = case Read.decimal s of+          Right (v, _) | v < nameCount (state st) -> st+          _ -> st |> addFail CheckFailure {..}     check _ st _ = st {-# INLINEABLE rule #-}++incAndAddName :: Text.Text -> Acc -> Acc+incAndAddName s Empty = Acc {count = 1, names = Set.singleton s}+incAndAddName s Acc {count, names} = Acc {count = count + 1, names = Set.insert s names}++incCount :: Acc -> Acc+incCount Empty = Acc {count = 1, names = Set.empty}+incCount Acc {count, names} = Acc {count = count + 1, names = names}++isMember :: Text.Text -> Acc -> Bool+isMember _ Empty = False+isMember s Acc {names} = Set.member s names++nameCount :: Acc -> Int+nameCount Empty = 0+nameCount Acc {count} = count
src/Hadolint/Rule/DL3023.hs view
@@ -11,7 +11,7 @@     message = "`COPY --from` cannot reference its own `FROM` alias"      check _ st f@(From _) = st |> replaceWith (Just f) -- Remember the last FROM instruction found-    check line st@(State _ (Just fromInstr)) (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource stageName)))+    check line st@(State _ (Just fromInstr)) (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource stageName) _))       | aliasMustBe (/= stageName) fromInstr = st       | otherwise = st |> addFail CheckFailure {..}     -- cannot copy from the same stage!
src/Hadolint/Rule/DL3027.hs view
@@ -14,7 +14,7 @@   where     code = "DL3027"     severity = DLWarningC-    message = "Do not use apt as it is meant to be a end-user tool, use apt-get\+    message = "Do not use apt as it is meant to be an end-user tool, use apt-get\               \ or apt-cache instead"      check (Run (RunArgs args _)) = foldArguments (not . usingProgram "apt") args
src/Hadolint/Rule/DL3028.hs view
@@ -34,8 +34,15 @@       not (Shell.cmdHasArgs "gem" ["-v"] cmd),       not (Shell.cmdHasArgs "gem" ["--version"] cmd),       not (Shell.cmdHasPrefixArg "gem" "--version=" cmd),-      arg <- Shell.getArgsNoFlags cmd,+      let args = Shell.getArgs cmd,+      let argsUntilDoubleDash = takeWhile (/= "--") args,+      arg <- removeOptions argsUntilDoubleDash,       arg /= "install",-      arg /= "i",-      arg /= "--"+      arg /= "i"   ]+  where+    removeOptions [] = []+    removeOptions (x : xs)+      | x == "--" = removeOptions xs+      | "-" `Text.isPrefixOf` x = removeOptions (drop 1 xs)+      | otherwise = x : removeOptions xs
src/Hadolint/Rule/DL3030.hs view
@@ -14,7 +14,7 @@   where     code = "DL3030"     severity = DLWarningC-    message = "Use the -y switch to avoid manual input `yum install -y <package`"+    message = "Use the -y switch to avoid manual input `yum install -y <package>`"      check (Run (RunArgs args _)) = foldArguments (Shell.noCommands forgotYumYesOption) args     check _ = True
src/Hadolint/Rule/DL3038.hs view
@@ -14,7 +14,7 @@   where     code = "DL3038"     severity = DLWarningC-    message = "Use the -y switch to avoid manual input `dnf install -y <package`"+    message = "Use the -y switch to avoid manual input `dnf install -y <package>`"      check (Run (RunArgs args _)) = foldArguments (Shell.noCommands forgotDnfYesOption) args     check _ = True
src/Hadolint/Rule/DL3041.hs view
@@ -4,7 +4,7 @@ import Hadolint.Rule import qualified Hadolint.Shell as Shell import Language.Docker.Syntax-+import Data.Char (isDigit, isAsciiUpper, isAsciiLower)  rule :: Rule Shell.ParsedShell rule = dl3041 <> onbuild dl3041@@ -35,8 +35,26 @@     ]  packageVersionFixed :: Text.Text -> Bool-packageVersionFixed package =-  "-" `Text.isInfixOf` package || ".rpm" `Text.isSuffixOf` package+packageVersionFixed package+  | length parts <= 1 = False  -- No dashes, definitively no version+  | ".rpm" `Text.isSuffixOf` package = True  -- rpm files always have a version+  | otherwise = isVersionLike $ drop 1 parts+  where+    parts = Text.splitOn "-" package++isVersionLike :: [Text.Text] -> Bool+isVersionLike parts =+  case parts of+    [] -> False  -- No parts after splitting by hyphen+    _ -> all partIsValid parts && any partStartsWithDigit parts+  where+    partIsValid part = Text.all isVersionChar part+    partStartsWithDigit part = case Text.uncons part of+                                 Just (c, _) -> isDigit c+                                 Nothing -> False -- Empty Text++isVersionChar :: Char -> Bool+isVersionChar c = isDigit c || isAsciiUpper c || isAsciiLower c || c `elem` ['.', '~', '^', '_']  dnfModules :: Shell.ParsedShell -> [Text.Text] dnfModules args =
src/Hadolint/Rule/DL3048.hs view
@@ -36,4 +36,4 @@ hasConsecutiveSeparators l = ".." `Text.isInfixOf` l || "--" `Text.isInfixOf` l  validChars :: String-validChars = ['0'..'9'] ++ ['a' .. 'z'] ++ ['.', '-']+validChars = ['0'..'9'] ++ ['a' .. 'z'] ++ ['.', '-', '_', '/']
src/Hadolint/Rule/DL3049.hs view
@@ -1,29 +1,27 @@ module Hadolint.Rule.DL3049 (rule) where -import qualified Data.Map as Map-import qualified Data.Set as Set-import qualified Data.Sequence as Seq-import qualified Data.Text as Text+import Data.Map qualified as Map+import Data.Sequence qualified as Seq+import Data.Set qualified as Set+import Data.Text qualified as Text import Hadolint.Rule import Language.Docker.Syntax - rule :: LabelSchema -> Rule args rule labelschema = mconcat $ fmap missingLabelRule (Map.keys labelschema) {-# INLINEABLE rule #-} - data StageID = StageID   { name :: BaseImage,     line :: Linenumber-  } deriving (Eq, Ord, Show)+  }+  deriving (Eq, Ord, Show)  data Acc   = Acc StageID (Set.Set StageID) (Set.Set StageID) (Set.Set StageID)   | Empty   deriving (Show) - -- missingLabelRule -- -- triggers on a `FROM` instruction when label `label` is not defined within@@ -36,7 +34,7 @@     message = "Label `" <> label <> "` is missing."     check line state (From img) =       state |> modify (currentStage (StageID img line))-    check _ state (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource src))) =+    check _ state (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource src) _)) =       state |> modify (markSilentByAlias src)     check _ state (Label pairs)       | label `elem` fmap fst pairs =@@ -51,7 +49,6 @@     markFailure st = failures st      markFail (StageID _ line) = CheckFailure {..}-  currentStage :: StageID -> Acc -> Acc currentStage stageid Empty = Acc stageid Set.empty Set.empty (Set.singleton stageid)
src/Hadolint/Rule/DL3053.hs view
@@ -18,7 +18,7 @@   where     code = "DL3053"     severity = DLWarningC-    message = "Label `" <> label <> "` is not a valid time format - must be conform to RFC3339."+    message = "Label `" <> label <> "` is not a valid time format - must conform to RFC3339."     check (Label ls) = null $ getBadTimeformatLabels label ls     check _ = True 
src/Hadolint/Rule/DL3058.hs view
@@ -18,7 +18,7 @@   where     code = "DL3058"     severity = DLWarningC-    message = "Label `" <> label <> "` is not a valid email format - must be conform to RFC5322."+    message = "Label `" <> label <> "` is not a valid email format - must conform to RFC5322."     check (Label ls) = null $ getBadEmailformatLabels label ls     check _ = True 
src/Hadolint/Rule/DL3059.hs view
@@ -13,7 +13,7 @@ -- | This Rule catches multiple consecutive `RUN` instructions. -- It ignores the case where multiple commands are chained together (e.g. with -- `&&`) because in that case the programmer most likely has deliberately--- chosen to use multiuple `RUN` instructions. Cases where --mount=xxx flags+-- chosen to use multiple `RUN` instructions. Cases where --mount=xxx flags -- differ are excluded as well. rule :: Rule Shell.ParsedShell rule = customRule check (emptyState Empty)
src/Hadolint/Rule/DL3060.hs view
@@ -5,7 +5,7 @@ import Hadolint.Rule import qualified Hadolint.Shell as Shell import Language.Docker.Syntax-+import Data.Set  data Acc   = Acc@@ -16,7 +16,22 @@   | Empty   deriving (Show) +-- check if a RunMount is a CacheMount+isCacheMount :: RunMount -> Bool+isCacheMount (CacheMount _) = True+isCacheMount _ = False +-- Set of RunMounts must contain at least one CacheMount++containsOneCacheMount :: Set RunMount -> Bool+containsOneCacheMount = Data.Set.foldl foldable False+  where +    foldable a b = a || isCacheMount b++-- do not flag this as a problem if using a cacheMount+cacheMount :: RunFlags -> Bool+cacheMount RunFlags {mount} = containsOneCacheMount mount+ rule :: Rule Shell.ParsedShell rule = dl3060 <> onbuild dl3060 {-# INLINEABLE rule #-}@@ -30,9 +45,10 @@      check line st (From from) =       st |> modify (rememberStage line from)-    check line st (Run (RunArgs args _))+    check line st (Run (RunArgs args flags))       | foldArguments (Shell.anyCommands yarnInstall) args-          && foldArguments (Shell.noCommands yarnCacheClean) args =+          && foldArguments (Shell.noCommands yarnCacheClean) args+          && not (cacheMount flags) =         st |> modify (rememberLine line)       | otherwise = st     check _ st _ = st@@ -66,7 +82,7 @@ yarnCacheClean = Shell.cmdHasArgs "yarn" ["cache", "clean"]  -- | This is needed as placeholder when no FROM statement has yet been--- envountered.+-- encountered. scratch :: BaseImage scratch =   ( BaseImage
src/Hadolint/Shell.hs view
@@ -69,7 +69,7 @@     si = mockedSystemInterface [("", "")]     spec =       emptyCheckSpec-        { csFilename = "", -- filename can be ommited because we only want the parse results back+        { csFilename = "", -- filename can be omitted because we only want the parse results back           csScript = script,           csCheckSourced = False,           csExcludedWarnings = exclusions,@@ -79,7 +79,8 @@     script = Text.unpack $ "#!" <> extractShell sh <> "\n" <> printVars <> txt     exclusions =       [ 2187, -- exclude the warning about the ash shell not being supported-        1090 -- requires a directive (shell comment) that can't be expressed in a Dockerfile+        1090, -- requires a directive (shell comment) that can't be expressed in a Dockerfile+        1091 -- requires a directive (shell comment) that can't be expressed in a Dockerfile       ]      extractShell s = fromMaybe "" (listToMaybe . Text.words $ s)@@ -205,6 +206,9 @@ hasFlag :: Text.Text -> Command -> Bool hasFlag flag Command {flags} = not $ null [f | CmdPart f _ <- flags, f == flag] +countFlag :: Text.Text -> Command -> Int+countFlag flag Command {flags} = length [ f | CmdPart f _ <- flags, f == flag ]+ hasAnyFlag :: [Text.Text] -> Command -> Bool hasAnyFlag fs Command {flags} = not $ null [f | CmdPart f _ <- flags, f `elem` fs] @@ -212,14 +216,14 @@ hasArg arg Command {arguments} = not $ null [a | CmdPart a _ <- arguments, a == arg]  dropFlagArg :: [Text.Text] -> Command -> Command-dropFlagArg flagsToDrop Command {name, arguments, flags} = Command name filterdArgs flags+dropFlagArg flagsToDrop Command {name, arguments, flags} = Command name filteredArgs flags   where     idsToDrop = Set.fromList [getValueId fId arguments | CmdPart f fId <- flags, f `elem` flagsToDrop]-    filterdArgs = [arg | arg@(CmdPart _ aId) <- arguments, not (aId `Set.member` idsToDrop)]+    filteredArgs = [arg | arg@(CmdPart _ aId) <- arguments, not (aId `Set.member` idsToDrop)] --- | given a flag and a command, return list of arguments for that particulat+-- | given a flag and a command, return list of arguments for that particular -- flag. E.g., if the command is `useradd -u 12345 luser` and this function is--- called for the command `u`, it returns ["12345"].+-- called for the flag `u`, it returns ["12345"]. getFlagArg :: Text.Text -> Command -> [Text.Text] getFlagArg flag Command {arguments, flags} = extractArgs   where@@ -238,6 +242,7 @@   where     isStdPipInstall =       "pip" `Text.isPrefixOf` name+        && not ("pipenv" `Text.isPrefixOf` name)         && ["install"] `isInfixOf` getArgs cmd     isPythonPipInstall =       "python" `Text.isPrefixOf` name
test/Hadolint/Config/EnvironmentSpec.hs view
@@ -38,7 +38,7 @@         conf `shouldBe` mempty { partialNoColor = Just True }      -- The expected value in this test changes based on the OS, but in order to-    -- repect the spec of https://no-color.org, an environment variable set to+    -- respect the spec of https://no-color.org, an environment variable set to     -- the empty string must still count as set, at least on platforms that     -- support setting an environment variable to the empty string (POSIX).     withJustEnv "NO_COLOR" "" $ do
test/Hadolint/PragmaSpec.hs view
@@ -82,3 +82,28 @@        in do             ruleCatchesNot "DL3023" $ Text.unlines dockerFile             ruleCatchesNot "DL3021" $ Text.unlines dockerFile++  describe "A comment can follow in the same line as a pragma" $ do++    it "pragma followed just by space" $+      let dockerFile =+            [ "FROM ubuntu",+              "# hadolint ignore=DL3002 ",+              "USER root"+            ]+       in ruleCatchesNot "DL3002" $ Text.unlines dockerFile++    it "ingore pragma with comment" $+      let dockerFile =+            [ "FROM ubuntu",+              "# hadolint ignore=DL3002 # foobar",+              "USER root"+            ]+       in ruleCatchesNot "DL3002" $ Text.unlines dockerFile++    it "shell pragma with comment" $+      let dockerFile =+            [ "# hadolint shell=powershell # foobar",+              "FROM ubuntu"+            ]+       in ruleCatchesNot "DL1001" $ Text.unlines dockerFile
− test/Hadolint/Rule/DL3005Spec.hs
@@ -1,15 +0,0 @@-module Hadolint.Rule.DL3005Spec (spec) where--import Data.Default-import Helpers-import Test.Hspec---spec :: SpecWith ()-spec = do-  let ?config = def--  describe "DL3005" $ do-    it "apt-get dist-upgrade" $ do-      ruleCatches "DL3005" "RUN apt-get update && apt-get dist-upgrade"-      onBuildRuleCatches "DL3005" "RUN apt-get update && apt-get dist-upgrade"
test/Hadolint/Rule/DL3006Spec.hs view
@@ -17,6 +17,8 @@       ruleCatchesNot "DL3006" "FROM ruby@sha256:f1dbca0f5dbc9"     it "untagged digest is not an error" $       ruleCatchesNot "DL3006" "FROM ruby:2"+    it "using args is not an error" $+      ruleCatchesNot "DL3006" "FROM ${VALUE}"     it "local aliases are OK to be untagged" $       let dockerFile =             [ "FROM golang:1.9.3-alpine3.7 AS build",
test/Hadolint/Rule/DL3009Spec.hs view
@@ -10,7 +10,7 @@ spec = do   let ?config = def -  describe "DL3009 - Delete the apt-get lists after installing something." $ do+  describe "DL3009 - Delete the apt lists (/var/lib/apt/lists) after installing something." $ do     it "apt-get no cleanup" $       let dockerFile =             [ "FROM scratch",@@ -131,3 +131,39 @@        in do             ruleCatches "DL3009" $ Text.unlines dockerFile             onBuildRuleCatches "DL3009" $ Text.unlines dockerFile++    it "apt no cleanup" $+      let dockerFile =+            [ "FROM scratch",+              "RUN apt update && apt install python"+            ]+       in do+            ruleCatches "DL3009" $ Text.unlines dockerFile+            onBuildRuleCatches "DL3009" $ Text.unlines dockerFile++    it "apt cleanup" $+      let dockerFile =+            [ "FROM scratch",+              "RUN apt update && apt install python && rm -rf /var/lib/apt/lists/*"+            ]+       in do+            ruleCatchesNot "DL3009" $ Text.unlines dockerFile+            onBuildRuleCatchesNot "DL3009" $ Text.unlines dockerFile++    it "aptitude no cleanup" $+      let dockerFile =+            [ "FROM scratch",+              "RUN aptitude update && aptitude install python"+            ]+       in do+            ruleCatches "DL3009" $ Text.unlines dockerFile+            onBuildRuleCatches "DL3009" $ Text.unlines dockerFile++    it "aptitude cleanup" $+      let dockerFile =+            [ "FROM scratch",+              "RUN aptitude update && aptitude install python && rm -rf /var/lib/apt/lists/*"+            ]+       in do+            ruleCatchesNot "DL3009" $ Text.unlines dockerFile+            onBuildRuleCatchesNot "DL3009" $ Text.unlines dockerFile
test/Hadolint/Rule/DL3011Spec.hs view
@@ -9,6 +9,13 @@ spec = do   let ?config = def -  describe "EXPOSE rules" $ do-    it "invalid port" $ ruleCatches "DL3011" "EXPOSE 80000"-    it "valid port" $ ruleCatchesNot "DL3011" "EXPOSE 60000"+  describe "DL3011 - Valid UNIX ports range from 0 to 65535" $ do+    describe "DL3011 - single port" $ do+      it "invalid port" $ ruleCatches "DL3011" "EXPOSE 80000"+      it "valid port" $ ruleCatchesNot "DL3011" "EXPOSE 60000"+      it "valid port variable" $ ruleCatchesNot "DL3011" "EXPOSE ${FOOBAR}"++    describe "DL3011 - port range" $ do+      it "invalid port in range" $ ruleCatches "DL3011" "EXPOSE 40000-80000/tcp"+      it "valid port range" $ ruleCatchesNot "DL3011" "EXPOSE 40000-60000/tcp"+      it "valid port range variable" $ ruleCatchesNot "DL3011" "EXPOSE 40000-${FOOBAR}"
test/Hadolint/Rule/DL3013Spec.hs view
@@ -165,3 +165,6 @@       onBuildRuleCatchesNot         "DL3013"         "RUN pip install --index-url https://user:pass@eg.com/foo --extra-index-url https://user:pass@ex-eg.io/foo foobar==1.0.0"+    it "pipenv is not pip" $ do+      ruleCatchesNot "DL3013" "RUN pipenv install black"+      onBuildRuleCatchesNot "DL3013" "RUN pipenv install black"
test/Hadolint/Rule/DL3014Spec.hs view
@@ -13,12 +13,18 @@     it "apt-get auto yes" $ do       ruleCatches "DL3014" "RUN apt-get install python"       onBuildRuleCatches "DL3014" "RUN apt-get install python"++    describe "Insufficient Quiet Levels" $ do+      it "apt-get -q" $ do+        ruleCatches "DL3014" "RUN apt-get install -q python"+        onBuildRuleCatches "DL3014" "RUN apt-get install -q python"+      it "apt-get --quiet" $ do+        ruleCatches "DL3014" "RUN apt-get install --quiet python"+        onBuildRuleCatches "DL3014" "RUN apt-get install -q python"+     it "apt-get yes shortflag" $ do       ruleCatchesNot "DL3014" "RUN apt-get install -yq python"       onBuildRuleCatchesNot "DL3014" "RUN apt-get install -yq python"-    it "apt-get yes quiet level 2 implies -y" $ do-      ruleCatchesNot "DL3014" "RUN apt-get install -qq python"-      onBuildRuleCatchesNot "DL3014" "RUN apt-get install -qq python"     it "apt-get yes different pos" $ do       ruleCatchesNot "DL3014" "RUN apt-get install -y python"       onBuildRuleCatchesNot "DL3014" "RUN apt-get install -y python"@@ -31,3 +37,18 @@     it "apt-get with assume-yes" $ do       ruleCatchesNot "DL3014" "RUN apt-get --assume-yes install python"       onBuildRuleCatchesNot "DL3014" "RUN apt-get --assume-yes install python"++    describe "Quiet level 2 implies assume-yes" $ do+      it "apt-get -qq" $ do+        ruleCatchesNot "DL3014" "RUN apt-get install -qq python"+        onBuildRuleCatchesNot "DL3014" "RUN apt-get install -qq python"+      it "apt-get -q -q" $ do+        ruleCatchesNot "DL3014" "RUN apt-get install -q -q python"+        onBuildRuleCatchesNot "DL3014" "RUN apt-get install -q -q python"+      it "apt-get -q=2" $ do+        ruleCatchesNot "DL3014" "RUN apt-get install -q=2 python"+        onBuildRuleCatchesNot "DL3014" "RUN apt-get install -q=2 python"+      it "apt-get --quiet --quiet" $ do+        ruleCatchesNot "DL3014" "RUN apt-get install --quiet --quiet python"+        onBuildRuleCatchesNot "DL3014"+          "RUN apt-get install --quiet --quiet python"
test/Hadolint/Rule/DL3022Spec.hs view
@@ -30,3 +30,20 @@             ]        in ruleCatchesNot "DL3022" $ Text.unlines dockerFile     it "don't warn on external images" $ ruleCatchesNot "DL3022" "COPY --from=haskell:latest bar ."+    it "warn on invalid stage count as --from=<count>" $ ruleCatches "DL3022" "COPY --from=0 bar ."+    it "don't warn on valid stage count as --from=<count>" $+      let dockerFile =+            [ "FROM scratch as build",+              "RUN foo",+              "FROM node",+              "COPY --from=0 foo ."+            ]+      in ruleCatchesNot "DL3022" $ Text.unlines dockerFile+    it "don't warn on valid stage count as --from=<count>" $+      let dockerFile =+            [ "FROM scratch",+              "RUN foo",+              "FROM node",+              "COPY --from=0 foo ."+            ]+      in ruleCatchesNot "DL3022" $ Text.unlines dockerFile
test/Hadolint/Rule/DL3027Spec.hs view
@@ -10,7 +10,7 @@ spec = do   let ?config = def -  describe "DL3027 - Do not use `apt` as it is meant to be a end-user tool, use `apt-get` or `apt-cache` instead" $ do+  describe "DL3027 - Do not use `apt` as it is meant to be an end-user tool, use `apt-get` or `apt-cache` instead" $ do     it "apt" $       let dockerFile =             [ "FROM ubuntu",
test/Hadolint/Rule/DL3028Spec.hs view
@@ -39,6 +39,15 @@         it "does not warn on --version with =" $ do           ruleCatchesNot "DL3028" "RUN gem install bundler --version='2.0.1'"           onBuildRuleCatchesNot "DL3028" "RUN gem install bundler --version='2.0.1'"-        it "does not warn on extra flags" $ do+        it "does not warn when using extra flags with equal sign and double dashes" $ do           ruleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 -- --use-system-libraries=true"           onBuildRuleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 -- --use-system-libraries=true"+        it "does not warn when using extra flags with double dashes" $ do+          ruleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 -- --use-system-libraries true"+          onBuildRuleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 -- --use-system-libraries true"+        it "does not warn when using extra flags" $ do+          ruleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 --use-system-libraries true"+          onBuildRuleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 --use-system-libraries true"+        it "does not warn when using extra flags with equal sign" $ do+          ruleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 --use-system-libraries=true"+          onBuildRuleCatchesNot "DL3028" "RUN gem install bundler:2.0.1 --use-system-libraries=true"
test/Hadolint/Rule/DL3033Spec.hs view
@@ -10,7 +10,7 @@   let ?config = def    describe "DL3033 - Specify version with `yum install -y <package>-<version>`" $ do-    it "not ok wihout yum version pinning" $ do+    it "not ok without yum version pinning" $ do       ruleCatches "DL3033" "RUN yum install -y tomcat && yum clean all"       onBuildRuleCatches "DL3033" "RUN yum install -y tomcat && yum clean all"     it "ok with yum version pinning" $ do@@ -18,7 +18,7 @@       ruleCatchesNot "DL3033" "RUN bash -c `# not even a yum command`"       onBuildRuleCatchesNot "DL3033" "RUN yum install -y tomcat-9.2 && yum clean all"       onBuildRuleCatchesNot "DL3033" "RUN bash -c `# not even a yum command`"-    it "not ok wihout yum version pinning - modules" $ do+    it "not ok without yum version pinning - modules" $ do       ruleCatches "DL3033" "RUN yum module install -y tomcat && yum clean all"       onBuildRuleCatches "DL3033" "RUN yum module install -y tomcat && yum clean all"     it "ok with yum version pinning - modules" $ do
test/Hadolint/Rule/DL3041Spec.hs view
@@ -14,6 +14,10 @@       ruleCatches "DL3041" "RUN dnf install -y tomcat && dnf clean all"       ruleCatches "DL3041" "RUN microdnf install -y tomcat && microdnf clean all"       onBuildRuleCatches "DL3041" "RUN dnf install -y tomcat && dnf clean all"+    it "not ok without dnf version pinning - package name with `-`" $ do+      ruleCatches "DL3041" "RUN dnf install -y rpm-sign && dnf clean all"+      ruleCatches "DL3041" "RUN microdnf install -y rpm-sign && microdnf clean all"+      onBuildRuleCatches "DL3041" "RUN dnf install -y rpm-sign && dnf clean all"     it "ok with dnf version pinning" $ do       ruleCatchesNot "DL3041" "RUN dnf install -y tomcat-9.0.1 && dnf clean all"       ruleCatchesNot "DL3041" "RUN microdnf install -y tomcat-9.0.1 && microdnf clean all"@@ -21,7 +25,14 @@       onBuildRuleCatchesNot "DL3041" "RUN dnf install -y tomcat-9.0.1 && dnf clean all"       onBuildRuleCatchesNot "DL3041" "RUN microdnf install -y tomcat-9.0.1 && microdnf clean all"       onBuildRuleCatchesNot "DL3041" "RUN notdnf install tomcat"-    it "not ok without dnf version pinning - moudles" $ do+    it "ok with dnf version pinning - package name with `-`" $ do+      ruleCatchesNot "DL3041" "RUN dnf install -y rpm-sign-4.16.1.3 && dnf clean all"+      ruleCatchesNot "DL3041" "RUN microdnf install -y rpm-sign-4.16.1.3 && microdnf clean all"+      ruleCatchesNot "DL3041" "RUN notdnf install rpm-sign"+      onBuildRuleCatchesNot "DL3041" "RUN dnf install -y rpm-sign-4.16.1.3 && dnf clean all"+      onBuildRuleCatchesNot "DL3041" "RUN microdnf install -y rpm-sign-4.16.1.3 && microdnf clean all"+      onBuildRuleCatchesNot "DL3041" "RUN notdnf install rpm-sign"+    it "not ok without dnf version pinning - modules" $ do       ruleCatches "DL3041" "RUN dnf module install -y tomcat && dnf clean all"       ruleCatches "DL3041" "RUN microdnf module install -y tomcat && microdnf clean all"       onBuildRuleCatches "DL3041" "RUN dnf module install -y tomcat && dnf clean all"
test/Hadolint/Rule/DL3053Spec.hs view
@@ -12,7 +12,7 @@ spec = do   let ?config = def { labelSchema = Map.fromList [("datelabel", Rule.Rfc3339)] } -  describe "DL3053 - Label `<label>` is not a valid time format - must be conform to RFC3339." $ do+  describe "DL3053 - Label `<label>` is not a valid time format - must conform to RFC3339." $ do     it "not ok with label not containing RFC3339 date" $ do       ruleCatches "DL3053" "LABEL datelabel=\"not-date\""       onBuildRuleCatches "DL3053" "LABEL datelabel=\"not-date\""
test/Hadolint/Rule/DL3058Spec.hs view
@@ -12,7 +12,7 @@ spec = do   let ?config = def { labelSchema = Map.fromList [("maintainer", Rule.Email)] } -  describe "DL3058 - Label `<label>` is not a valid email format - must be conform to RFC5322." $ do+  describe "DL3058 - Label `<label>` is not a valid email format - must conform to RFC5322." $ do     it "not ok with label not containing valid email" $ do       ruleCatches "DL3058" "LABEL maintainer=\"not-email\""       onBuildRuleCatches "DL3058" "LABEL maintainer=\"not-email\""
test/Hadolint/Rule/ShellcheckSpec.hs view
@@ -11,7 +11,7 @@   let ?config = def    describe "Shellcheck" $ do-    it "runs shellchek on RUN instructions" $ do+    it "runs shellcheck on RUN instructions" $ do       assertChecks "RUN echo $MISSING_QUOTES" failsShellcheck       assertOnBuildChecks "RUN echo $MISSING_QUOTES" failsShellcheck     it "not warns on valid scripts" $ do@@ -88,7 +88,7 @@               ]        in do             assertChecks dockerFile passesShellcheck-            -- This is debatable, as it should actaully pass, but detecting it correctly+            -- This is debatable, as it should actually pass, but detecting it correctly             -- is quite difficult             assertOnBuildChecks dockerFile failsShellcheck     it "Resets the SHELL to sh after a FROM" $