hadolint 2.1.0 → 2.2.0
raw patch · 16 files changed
+320/−24 lines, 16 filesdep ~language-dockerPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: language-docker
API changes (from Hackage documentation)
+ Hadolint.Formatter.Format: errorMessage :: (VisualStream s, ShowErrorComponent e) => ParseErrorBundle s e -> String
+ Hadolint.Rule.DL3042: instance GHC.Classes.Eq Hadolint.Rule.DL3042.Stage
+ Hadolint.Rule.DL3042: instance GHC.Classes.Ord Hadolint.Rule.DL3042.Stage
+ Hadolint.Rule.DL3059: instance GHC.Classes.Eq Hadolint.Rule.DL3059.Acc
+ Hadolint.Rule.DL3059: instance GHC.Show.Show Hadolint.Rule.DL3059.Acc
+ Hadolint.Rule.DL3059: rule :: Rule args
+ Hadolint.Rule.DL3060: rule :: Rule ParsedShell
Files
- README.md +25/−1
- hadolint.cabal +9/−5
- src/Hadolint/Config.hs +1/−1
- src/Hadolint/Formatter/Format.hs +5/−0
- src/Hadolint/Formatter/Json.hs +7/−2
- src/Hadolint/Process.hs +5/−1
- src/Hadolint/Rule/DL3005.hs +2/−2
- src/Hadolint/Rule/DL3042.hs +98/−8
- src/Hadolint/Rule/DL3059.hs +29/−0
- src/Hadolint/Rule/DL3060.hs +27/−0
- test/DL3005.hs +0/−3
- test/DL3042.hs +52/−0
- test/DL3059.hs +31/−0
- test/DL3060.hs +19/−0
- test/ShellSpec.hs +0/−1
- test/Spec.hs +10/−0
README.md view
@@ -36,6 +36,10 @@ $ docker run --rm -i ghcr.io/hadolint/hadolint < Dockerfile ``` +or if you are using Windows PowerShell:+```powershell+> cat .\Dockerfile | docker run --rm -i hadolint/hadolint+``` ## Install You can download prebuilt binaries for OSX, Windows and Linux from the latest@@ -107,6 +111,21 @@ - my-company.com:5000 ``` +If you want to override the severity of specific rules, you can do that too:+```yaml+override:+ error:+ - DL3001+ - DL3002+ warning:+ - DL3042+ - DL3033+ info:+ - DL3032+ style:+ - DL3015+```+ Configuration files can be used globally or per project. By default, `hadolint` will look for a configuration file in the current directory with the name `.hadolint.yaml` @@ -165,6 +184,7 @@ ```yaml label-schema: author: text+ contact: email created: rfc3339 version: semver documentation: url@@ -181,6 +201,7 @@ | url | A URI as described in [RFC 3986][rfc3986] | | hash | Either a short or a long [Git hash][githash] | | spdx | An [SPDX license identifier][spdxid] |+| email | An email address conforming to [RFC 5322][rfc5322] | By default, Hadolint ignores any label not specified in the label schema. To warn on such additional labels, turn on strict labels:@@ -239,7 +260,7 @@ | [DL3002](https://github.com/hadolint/hadolint/wiki/DL3002) | Last user should not be root. | | [DL3003](https://github.com/hadolint/hadolint/wiki/DL3003) | Use WORKDIR to switch to a directory. | | [DL3004](https://github.com/hadolint/hadolint/wiki/DL3004) | 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) | Do not use apt-get upgrade or dist-upgrade. |+| [DL3005](https://github.com/hadolint/hadolint/wiki/DL3005) | Do not use apt-get dist-upgrade. | | [DL3006](https://github.com/hadolint/hadolint/wiki/DL3006) | Always tag the version of an image explicitly. | | [DL3007](https://github.com/hadolint/hadolint/wiki/DL3007) | 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) | Pin versions in apt-get install. |@@ -293,6 +314,8 @@ | [DL3056](https://github.com/hadolint/hadolint/wiki/DL3056) | Label `<label>` does not conform to semantic versioning. | | [DL3057](https://github.com/hadolint/hadolint/wiki/DL3057) | `HEALTHCHECK` instruction missing. | | [DL3058](https://github.com/hadolint/hadolint/wiki/DL3058) | Label `<label>` is not a valid email format - must be conform to RFC5322. |+| [DL3059](https://github.com/hadolint/hadolint/wiki/DL3059) | Multiple consecutive `RUN` instructions. Consider consolidation. |+| [DL3060](https://github.com/hadolint/hadolint/wiki/DL3060) | `yarn cache clean` missing after `yarn install` was run. | | [DL4000](https://github.com/hadolint/hadolint/wiki/DL4000) | MAINTAINER is deprecated. | | [DL4001](https://github.com/hadolint/hadolint/wiki/DL4001) | Either use Wget or Curl but not both. | | [DL4003](https://github.com/hadolint/hadolint/wiki/DL4003) | Multiple `CMD` instructions found. |@@ -417,3 +440,4 @@ [rfc3986]: https://www.ietf.org/rfc/rfc3986.txt [githash]: https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection [spdxid]: https://spdx.org/licenses/+[rfc5322]: https://www.ietf.org/rfc/rfc5322.txt
hadolint.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 3a6af1aecfc32d960fd1df8de865bb60b8682f8877a9b3bb848a3f59c50c063d+-- hash: 391fff086908037463e385c3450cb46068242dcf3932fbfbb995f2bf9ee6a98c name: hadolint-version: 2.1.0+version: 2.2.0 synopsis: Dockerfile Linter JavaScript API description: A smarter Dockerfile linter that helps you build best practice Docker images. category: Development@@ -103,6 +103,8 @@ Hadolint.Rule.DL3056 Hadolint.Rule.DL3057 Hadolint.Rule.DL3058+ Hadolint.Rule.DL3059+ Hadolint.Rule.DL3060 Hadolint.Rule.DL4000 Hadolint.Rule.DL4001 Hadolint.Rule.DL4003@@ -135,7 +137,7 @@ , filepath , foldl , ilist- , language-docker >=9.1.3 && <10+ , language-docker >=9.2.0 && <10 , megaparsec >=9.0.0 , mtl , network-uri@@ -163,7 +165,7 @@ , containers , gitrev >=1.3.1 , hadolint- , language-docker >=9.1.3 && <10+ , language-docker >=9.2.0 && <10 , megaparsec >=9.0.0 , optparse-applicative >=0.14.0 , text@@ -235,6 +237,8 @@ DL3056 DL3057 DL3058+ DL3059+ DL3060 DL4000 DL4001 DL4003@@ -260,7 +264,7 @@ , foldl , hadolint , hspec- , language-docker >=9.1.3 && <10+ , language-docker >=9.2.0 && <10 , megaparsec >=9.0.0 , split >=0.2 , text
src/Hadolint/Config.hs view
@@ -145,7 +145,7 @@ "\terror:", "\t\t- DL3008\n\n", "The key 'trustedRegistries' should contain the names of the allowed docker registries:\n",- "allowedRegistries:",+ "trustedRegistries:", "\t- docker.io", "\t- my-company.com", "",
src/Hadolint/Formatter/Format.hs view
@@ -1,6 +1,7 @@ module Hadolint.Formatter.Format ( severityText, stripNewlines,+ errorMessage, errorMessageLine, errorPosition, errorPositionPretty,@@ -53,6 +54,10 @@ errorMessageLine :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => ParseErrorBundle s e -> String errorMessageLine err@(ParseErrorBundle e _) = errorPositionPretty err ++ " " ++ parseErrorTextPretty (NE.head e)++errorMessage :: (VisualStream s, ShowErrorComponent e) => ParseErrorBundle s e -> String+errorMessage (ParseErrorBundle e _) =+ reverse . dropWhile (== '\n') . reverse $ parseErrorTextPretty (NE.head e) errorPositionPretty :: TraversableStream s => ParseErrorBundle s e -> String errorPositionPretty err = sourcePosPretty (errorPosition err)
src/Hadolint/Formatter/Json.hs view
@@ -9,7 +9,12 @@ import qualified Data.ByteString.Lazy.Char8 as B import Data.Sequence (Seq) import qualified Data.Text as Text-import Hadolint.Formatter.Format (Result (..), errorPosition, severityText)+import Hadolint.Formatter.Format+ ( Result (..),+ errorPosition,+ severityText,+ errorMessage+ ) import Hadolint.Rule (CheckFailure (..), DLSeverity (..), unRuleCode) import Text.Megaparsec (TraversableStream) import Text.Megaparsec.Error@@ -37,7 +42,7 @@ "column" .= unPos (sourceColumn pos), "level" .= severityText DLErrorC, "code" .= ("DL1000" :: Text.Text),- "message" .= errorBundlePretty err+ "message" .= errorMessage err ] where pos = errorPosition err
src/Hadolint/Process.hs view
@@ -67,6 +67,8 @@ import qualified Hadolint.Rule.DL3056 import qualified Hadolint.Rule.DL3057 import qualified Hadolint.Rule.DL3058+import qualified Hadolint.Rule.DL3059+import qualified Hadolint.Rule.DL3060 import qualified Hadolint.Rule.DL4000 import qualified Hadolint.Rule.DL4001 import qualified Hadolint.Rule.DL4003@@ -194,8 +196,10 @@ <> Hadolint.Rule.DL3054.rule labelSchema <> Hadolint.Rule.DL3055.rule labelSchema <> Hadolint.Rule.DL3056.rule labelSchema- <> Hadolint.Rule.DL3058.rule labelSchema <> Hadolint.Rule.DL3057.rule+ <> Hadolint.Rule.DL3058.rule labelSchema+ <> Hadolint.Rule.DL3059.rule+ <> Hadolint.Rule.DL3060.rule <> Hadolint.Rule.DL4000.rule <> Hadolint.Rule.DL4001.rule <> Hadolint.Rule.DL4003.rule
src/Hadolint/Rule/DL3005.hs view
@@ -10,8 +10,8 @@ where code = "DL3005" severity = DLErrorC- message = "Do not use apt-get upgrade or dist-upgrade"+ message = "Do not use apt-get dist-upgrade" check (Run (RunArgs args _)) =- foldArguments (Shell.noCommands (Shell.cmdHasArgs "apt-get" ["upgrade", "dist-upgrade"])) args+ foldArguments (Shell.noCommands (Shell.cmdHasArgs "apt-get" ["dist-upgrade"])) args check _ = True {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3042.hs view
@@ -1,25 +1,66 @@ module Hadolint.Rule.DL3042 (rule) where import Data.List (isInfixOf)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Maybe (fromMaybe, isNothing, isJust, fromJust)+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Text (Text) import qualified Data.Text as Text import Hadolint.Rule import qualified Hadolint.Shell as Shell import Language.Docker.Syntax ++-- This data encapsulates the name of a build stage. It may be None withing an+-- `ONBUILD` context.+data Stage+ = Stage {stage :: Text}+ | None+ deriving (Eq, Ord)++data Acc+ = Acc {current :: Stage, noCacheMap :: Map Stage Bool}+ | Empty++ rule :: Rule Shell.ParsedShell-rule = simpleRule code severity message check+rule = customRule check (emptyState Empty) where code = "DL3042" severity = DLWarningC- message =- "Avoid use of cache directory with pip. Use `pip install --no-cache-dir <package>`"- check (Run (RunArgs args _)) = foldArguments (Shell.noCommands forgotNoCacheDir) args- check _ = True- forgotNoCacheDir cmd =- Shell.isPipInstall cmd && not (usesNoCacheDir cmd) && not (isPipWrapper cmd)- usesNoCacheDir cmd = "--no-cache-dir" `elem` Shell.getArgs cmd+ message = "Avoid use of cache directory with pip.\+ \ Use `pip install --no-cache-dir <package>`"+ check _ st (From from) = st |> modify (rememberStage from)+ check _ st (Env pairs) = st |> modify (registerEnv pairs)+ check line st (Run (RunArgs args _))+ | Acc s ncm <- state st, Just True <- Map.lookup s ncm = st+ | foldArguments pipNoCacheDirIsSet args = st+ | foldArguments (Shell.noCommands forgotNoCacheDir) args = st+ | otherwise = st |> addFail CheckFailure {..}+ check _ st _ = st {-# INLINEABLE rule #-} +forgotNoCacheDir :: Shell.Command -> Bool+forgotNoCacheDir cmd = Shell.isPipInstall cmd+ && not (usesNoCacheDir cmd)+ && not (isPipWrapper cmd)++usesNoCacheDir :: Shell.Command -> Bool+usesNoCacheDir cmd = "--no-cache-dir" `elem` Shell.getArgs cmd++pipNoCacheDirIsSet :: Shell.ParsedShell -> Bool+pipNoCacheDirIsSet shell = any+ (`Text.isPrefixOf` Text.drop 1+ (Text.dropWhile (/= '=')+ (snd+ (Text.breakOn "PIP_NO_CACHE_DIR=" (Shell.original shell)+ )+ )+ )+ ) truthy+ isPipWrapper :: Shell.Command -> Bool isPipWrapper cmd@(Shell.Command name _ _) = isWrapper "pipx" || isWrapper "pipenv" where@@ -27,3 +68,52 @@ isWrapper w = w `Text.isInfixOf` name || ("python" `Text.isPrefixOf` name && ["-m", w] `isInfixOf` Shell.getArgs cmd)++rememberStage :: BaseImage -> Acc -> Acc+rememberStage BaseImage {alias = Just als} Empty =+ Acc+ { current = Stage {stage = unImageAlias als},+ noCacheMap = mempty+ }+rememberStage BaseImage {alias = Nothing, image} Empty =+ Acc+ { current = Stage {stage = imageName image},+ noCacheMap = mempty+ }+rememberStage BaseImage {alias = Just als, image} Acc {..} =+ Acc+ { current = Stage {stage = unImageAlias als},+ noCacheMap =+ let parentValue =+ Map.lookup (Stage {stage = imageName image}) noCacheMap |> fromMaybe False+ in noCacheMap |> Map.insert (Stage {stage = unImageAlias als}) parentValue+ }+rememberStage BaseImage {alias = Nothing, image} Acc {..} =+ Acc+ { current = Stage {stage = imageName image},+ noCacheMap =+ let parentValue =+ Map.lookup (Stage {stage = imageName image}) noCacheMap |> fromMaybe False+ in noCacheMap |> Map.insert (Stage {stage = imageName image}) parentValue+ }++registerEnv :: Pairs -> Acc -> Acc+registerEnv pairs Empty+ | pipNoCacheDirSet pairs =+ Acc {current = None, noCacheMap = Map.insert None True Map.empty}+ | otherwise = Empty+registerEnv pairs Acc {..}+ | pipNoCacheDirSet pairs =+ Acc {current, noCacheMap = Map.insert current True noCacheMap}+ | otherwise = Acc {..}++pipNoCacheDirSet :: Pairs -> Bool+pipNoCacheDirSet [] = False+pipNoCacheDirSet pairs+ | isNothing (lookup "PIP_NO_CACHE_DIR" pairs) = False+ | val <- lookup "PIP_NO_CACHE_DIR" pairs,+ isJust val && fromJust val `notElem` truthy = False+ | otherwise = True++truthy :: Set Text+truthy = Set.fromList ["1", "true", "True", "TRUE", "on", "On", "ON", "yes", "Yes", "YES"]
+ src/Hadolint/Rule/DL3059.hs view
@@ -0,0 +1,29 @@+module Hadolint.Rule.DL3059 (rule) where++import Hadolint.Rule+import Language.Docker.Syntax+++data Acc+ = Acc RunFlags+ | Empty+ deriving (Eq, Show)++rule :: Rule args+rule = customRule check (emptyState Empty)+ where+ code = "DL3059"+ severity = DLInfoC+ message = "Multiple consecutive `RUN` instructions. Consider consolidation."++ check line st (Run (RunArgs _ flags))+ | state st == Acc flags = st |> addFail CheckFailure {..}+ | otherwise = st |> modify (remember flags)+ check _ st _ = st |> modify reset+{-# INLINEABLE rule #-}++remember :: RunFlags -> Acc -> Acc+remember flags _ = Acc flags++reset :: Acc -> Acc+reset _ = Empty
+ src/Hadolint/Rule/DL3060.hs view
@@ -0,0 +1,27 @@+module Hadolint.Rule.DL3060 (rule) where++import Hadolint.Rule+import qualified Hadolint.Shell as Shell+import Language.Docker.Syntax+++rule :: Rule Shell.ParsedShell+rule = simpleRule code severity message check+ where+ code = "DL3060"+ severity = DLInfoC+ message = "`yarn cache clean` missing after `yarn install` was run."++ check (Run (RunArgs args _)) =+ foldArguments (Shell.noCommands yarnInstall) args+ || ( foldArguments (Shell.anyCommands yarnInstall) args+ && foldArguments (Shell.anyCommands yarnCacheClean) args+ )+ check _ = True+{-# INLINEABLE rule #-}++yarnInstall :: Shell.Command -> Bool+yarnInstall = Shell.cmdHasArgs "yarn" ["install"]++yarnCacheClean :: Shell.Command -> Bool+yarnCacheClean = Shell.cmdHasArgs "yarn" ["cache", "clean"]
test/DL3005.hs view
@@ -8,9 +8,6 @@ tests = do let ?rulesConfig = mempty describe "DL3005" $ do- it "apt-get upgrade" $ do- ruleCatches "DL3005" "RUN apt-get update && apt-get upgrade"- onBuildRuleCatches "DL3005" "RUN apt-get update && apt-get upgrade" 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/DL3042.hs view
@@ -1,5 +1,6 @@ module DL3042 (tests) where +import Data.Text as Text import Helpers import Test.Hspec @@ -32,3 +33,54 @@ it "don't match on pipenv" $ do ruleCatchesNot "DL3042" "RUN pipenv install library" onBuildRuleCatchesNot "DL3042" "RUN pipenv install library"++ -- ENV won't work with the onBuildRuleCatches[Not] wrapper:+ it "respect ENV PIP_NO_CACHE_DIR with truthy values" $ do+ ruleCatchesNot "DL3042" "ENV PIP_NO_CACHE_DIR=1\nRUN pip install MySQL_python"+ ruleCatchesNot "DL3042" "ENV PIP_NO_CACHE_DIR=on\nRUN pip install MySQL_python"+ ruleCatchesNot "DL3042" "ENV PIP_NO_CACHE_DIR=yes\nRUN pip install MySQL_python"+ ruleCatchesNot "DL3042" "ENV PIP_NO_CACHE_DIR=true\nRUN pip install MySQL_python"+ it "respect RUN PIP_NO_CACHE_DIR=... with truthy values" $ do+ ruleCatchesNot "DL3042" "RUN PIP_NO_CACHE_DIR=1 pip install MySQL_python"+ ruleCatchesNot "DL3042" "RUN PIP_NO_CACHE_DIR=on pip install MySQL_python"+ ruleCatchesNot "DL3042" "RUN PIP_NO_CACHE_DIR=yes pip install MySQL_python"+ ruleCatchesNot "DL3042" "RUN PIP_NO_CACHE_DIR=true pip install MySQL_python"+ it "respect RUN export PIP_NO_CACHE_DIR=... with truthy values" $ do+ ruleCatchesNot "DL3042" "RUN export PIP_NO_CACHE_DIR=1 && pip install MySQL_python"+ ruleCatchesNot "DL3042" "RUN export PIP_NO_CACHE_DIR=on && pip install MySQL_python"+ ruleCatchesNot "DL3042" "RUN export PIP_NO_CACHE_DIR=yes && pip install MySQL_python"+ ruleCatchesNot "DL3042" "RUN export PIP_NO_CACHE_DIR=true && pip install MySQL_python"+ it "respect ENV PIP_NO_CACHE_DIR with falsy values" $ do+ ruleCatches "DL3042" "ENV PIP_NO_CACHE_DIR=0\nRUN pip install MySQL_python"+ ruleCatches "DL3042" "ENV PIP_NO_CACHE_DIR=off\nRUN pip install MySQL_python"+ ruleCatches "DL3042" "ENV PIP_NO_CACHE_DIR=no\nRUN pip install MySQL_python"+ ruleCatches "DL3042" "ENV PIP_NO_CACHE_DIR=false\nRUN pip install MySQL_python"+ it "respect RUN PIP_NO_CACHE_DIR=... with falsy values" $ do+ ruleCatches "DL3042" "RUN PIP_NO_CACHE_DIR=0 pip install MySQL_python"+ ruleCatches "DL3042" "RUN PIP_NO_CACHE_DIR=off pip install MySQL_python"+ ruleCatches "DL3042" "RUN PIP_NO_CACHE_DIR=no pip install MySQL_python"+ ruleCatches "DL3042" "RUN PIP_NO_CACHE_DIR=false pip install MySQL_python"+ it "respect RUN export PIP_NO_CACHE_DIR=... with falsy values" $ do+ ruleCatches "DL3042" "RUN export PIP_NO_CACHE_DIR=0 && pip install MySQL_python"+ ruleCatches "DL3042" "RUN export PIP_NO_CACHE_DIR=off && pip install MySQL_python"+ ruleCatches "DL3042" "RUN export PIP_NO_CACHE_DIR=no && pip install MySQL_python"+ ruleCatches "DL3042" "RUN export PIP_NO_CACHE_DIR=false && pip install MySQL_python"++ it "don't trigger if PIP_NO_CACHE_DIR is inherited" $+ let dockerFile = Text.unlines+ [ "FROM debian:buster as base",+ "ENV PIP_NO_CACHE_DIR=1",+ "FROM base",+ "RUN pip install six"+ ]+ in do+ ruleCatchesNot "DL3042" dockerFile+ it "trigger if PIP_NO_CACHE_DIR is not inherited" $+ let dockerFile = Text.unlines+ [ "FROM debian:buster as base",+ "ENV PIP_NO_CACHE_DIR=1",+ "FROM debian:buster",+ "RUN pip install six"+ ]+ in do+ ruleCatches "DL3042" dockerFile
+ test/DL3059.hs view
@@ -0,0 +1,31 @@+module DL3059 (tests) where++import Data.Text as Text+import Helpers+import Test.Hspec+++tests :: SpecWith ()+tests = do+ let ?rulesConfig = mempty+ describe "DL3059 - Multiple consecutive `RUN` instructions" $ do+ it "ok with no `RUN` at all" $ do+ ruleCatchesNot "DL3059" "FROM debian:10"+ it "ok with one `RUN`" $ do+ ruleCatchesNot "DL3059" "RUN /foo.sh"+ it "ok with two not consecutive `RUN`" $ do+ ruleCatchesNot "DL3059" "RUN /foo.sh\nWORKDIR /\nRUN /bar.sh"+ it "not ok with two consecutive `RUN`s" $ do+ ruleCatches "DL3059" "RUN /foo.sh\nRUN /bar.sh"+ it "ok with two consecutive `RUN`s when flags are different 1" $ do+ ruleCatchesNot "DL3059" "RUN --mount=type=secret,id=foo /foo.sh\nRUN /bar.sh"+ it "ok with two consecutive `RUN`s when flags are different 2" $ do+ let dfile = [ "RUN --mount=type=secret,id=foo /foo.sh",+ "RUN --mount=type=secret,id=bar /bar.sh"+ ]+ in ruleCatchesNot "DL3059" $ Text.unlines dfile+ it "not ok with two consecutive `RUN`s when flags are equal" $ do+ let dfile = [ "RUN --mount=type=secret,id=foo /foo.sh",+ "RUN --mount=type=secret,id=foo /bar.sh"+ ]+ in ruleCatches "DL3059" $ Text.unlines dfile
+ test/DL3060.hs view
@@ -0,0 +1,19 @@+module DL3060 (tests) where++import Helpers+import Test.Hspec+++tests :: SpecWith ()+tests = do+ let ?rulesConfig = mempty+ describe "DL3060 - `yarn cache clean` missing after `yarn install`" $ do+ it "ok with non-yarn commands" $ do+ ruleCatchesNot "DL3060" "RUN foo"+ onBuildRuleCatchesNot "DL3060" "RUN foo"+ it "not ok with no cache clean" $ do+ ruleCatches "DL3060" "RUN yarn install foo"+ onBuildRuleCatches "DL3060" "RUN yarn install foo"+ it "ok with cache clean" $ do+ ruleCatchesNot "DL3060" "RUN yarn install bar && yarn cache clean"+ onBuildRuleCatchesNot "DL3060" "RUN yarn install bar && yarn cache clean"
test/ShellSpec.hs view
@@ -1,6 +1,5 @@ module ShellSpec where -import Data.Text as Text import Hadolint.Shell import Test.Hspec
test/Spec.hs view
@@ -59,11 +59,13 @@ import qualified DL3056 import qualified DL3057 import qualified DL3058+import qualified DL3059 import qualified DL4001 import qualified DL4003 import qualified DL4004 import qualified DL4005 import qualified DL4006+import Hadolint.Formatter.Format (errorMessage) import Hadolint.Formatter.TTY (formatError) import Helpers import Language.Docker.Parser@@ -86,6 +88,13 @@ case ast of Left err -> assertEqual "Unexpected error msg" expectedMsg (formatError err) Right _ -> assertFailure "AST should fail parsing"+ describe "errorMessage" $+ it "display just the error message" $ do+ let ast = parseText "RUNNN"+ expectedMsg = "missing whitespace"+ case ast of+ Left err -> assertEqual "Unexpected error msg" expectedMsg (errorMessage err)+ Right _ -> assertFailure "AST should fail parsing" -- describe "Rules can be ignored with inline comments" $ do it "ignores single rule" $@@ -220,6 +229,7 @@ DL3056.tests DL3057.tests DL3058.tests+ DL3059.tests DL4001.tests DL4003.tests DL4004.tests