packages feed

hadolint 2.10.0 → 2.11.0

raw patch · 19 files changed

+305/−53 lines, 19 filesdep ~language-dockerPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: language-docker

API changes (from Hackage documentation)

Files

README.md view
@@ -300,7 +300,8 @@ HADOLINT_IGNORE=DL3010,DL3020            # comma separated list of rule codes HADOLINT_STRICT_LABELS=1                 # Truthy value e.g. 1, true or yes HADOLINT_DISABLE_IGNORE_PRAGMA=1         # Truthy value e.g. 1, true or yes-HADOLINT_TRUSTED_REGISTRIES              # comma separated list of registry urls+HADOLINT_TRUSTED_REGISTRIES=docker.io    # comma separated list of registry urls+HADOLINT_REQUIRE_LABELS=maintainer:text  # comma separated list of label schema items ```  ## Non-Posix Shells
hadolint.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.0 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.34.6. -- -- see: https://github.com/sol/hpack  name:           hadolint-version:        2.10.0+version:        2.11.0 synopsis:       Dockerfile Linter JavaScript API description:    A smarter Dockerfile linter that helps you build best practice Docker images. category:       Development@@ -155,7 +155,7 @@     , foldl     , gitrev >=1.3.1     , ilist-    , language-docker >=10.4.3 && <11+    , language-docker >=11.0.0 && <12     , megaparsec >=9.0.0     , mtl     , network-uri@@ -176,6 +176,8 @@   main-is: Main.hs   other-modules:       Paths_hadolint+  autogen-modules:+      Paths_hadolint   hs-source-dirs:       app   default-extensions:@@ -195,7 +197,7 @@     , containers     , data-default     , hadolint-    , language-docker >=10.4.3 && <11+    , language-docker >=11.0.0 && <12     , megaparsec >=9.0.0     , optparse-applicative >=0.14.0     , prettyprinter >=1.7.0@@ -289,6 +291,8 @@       Helpers       RegressionSpec       Paths_hadolint+  autogen-modules:+      Paths_hadolint   hs-source-dirs:       test   default-extensions:@@ -317,7 +321,7 @@     , foldl     , hadolint     , hspec >=2.8.3-    , language-docker >=10.4.3 && <11+    , language-docker >=11.0.0 && <12     , megaparsec >=9.0.0     , optparse-applicative >=0.14.0     , silently
src/Hadolint/Config/Configuration.hs view
@@ -192,7 +192,7 @@     partialNoFail <- m .:? "no-fail" .!= Nothing     partialNoColor <- m .:? "no-color" .!= Nothing     partialVerbose <- m .:? "verbose" .!= Nothing-    partialFormat <- m .:? "output-format"+    partialFormat <- m .:? "format"     override <- m .:? "override" .!= mempty     ignored <- m .:? "ignored" .!= mempty     trusted <- m .:? "trustedRegistries" .!= mempty
src/Hadolint/Rule/DL3010.hs view
@@ -26,7 +26,7 @@     message = "Use `ADD` for extracting archives into an image"      check _ _ (From _) = emptyState Empty-    check line st (Copy (CopyArgs srcs tgt _ _ 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,
src/Hadolint/Rule/DL3013.hs view
@@ -44,12 +44,18 @@         || ["."] `isInfixOf` Shell.getArgs cmd      hasBuildConstraint cmd = Shell.hasFlag "constraint" cmd || Shell.hasFlag "c" cmd-    versionFixed package = hasVersionSymbol package || isVersionedGit package || isLocalPackage package-    isVersionedGit package = "git+http" `Text.isInfixOf` package && "@" `Text.isInfixOf` package+    versionFixed package = hasVersionSymbol package+      || isVersionedVcs package+      || isLocalPackage package+      || isNoVcsPathSource package+    isVersionedVcs package = isVcs package+      && "@" `Text.isInfixOf` package     versionSymbols = ["==", ">=", "<=", ">", "<", "!=", "~=", "==="]     hasVersionSymbol package = or [s `Text.isInfixOf` package | s <- versionSymbols]     localPackageFileExtensions = [".whl", ".tar.gz"]     isLocalPackage package = or [s `Text.isSuffixOf` package | s <- localPackageFileExtensions]+    isNoVcsPathSource package = not (isVcs package) && "/" `Text.isInfixOf` package+    isVcs package = any (`Text.isPrefixOf` package) vcsSchemes {-# INLINEABLE dl3013 #-}  packages :: Shell.Command -> [Text.Text]@@ -83,6 +89,35 @@           "upgrade-strategy"         ]         cmd++-- Supported schemes vcs[+protocol] are found here:+-- https://pip.pypa.io/en/stable/topics/vcs-support/+vcsSchemes :: [Text.Text]+vcsSchemes =+  [+    "git+file",+    "git+https",+    "git+ssh",+    "git+http",+    "git+git",+    "git",+    "hg+file",+    "hg+http",+    "hg+https",+    "hg+ssh",+    "hg+static-http",+    "svn",+    "svn+svn",+    "svn+http",+    "svn+https",+    "svn+ssh",+    "bzr+http",+    "bzr+https",+    "bzr+ssh",+    "bzr+sftp",+    "bzr+ftp",+    "bzr+lp"+  ]  stripInstallPrefix :: [Text.Text] -> [Text.Text] stripInstallPrefix cmd = dropWhile (== "install") (dropWhile (/= "install") cmd)
src/Hadolint/Rule/DL3020.hs view
@@ -12,7 +12,7 @@     severity = DLErrorC     message = "Use COPY instead of ADD for files and folders" -    check (Add (AddArgs srcs _ _ _)) =+    check (Add (AddArgs srcs _) _) =       and [isArchive src || isUrl src | SourcePath src <- toList srcs]     check _ = True {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3021.hs view
@@ -11,7 +11,7 @@     severity = DLErrorC     message = "COPY with more than 2 arguments requires the last argument to end with /" -    check (Copy (CopyArgs sources t _ _ _))+    check (Copy (CopyArgs sources t) _)       | length sources > 1 = endsWithSlash t       | otherwise = True     check _ = True
src/Hadolint/Rule/DL3022.hs view
@@ -1,6 +1,7 @@ module Hadolint.Rule.DL3022 (rule) where  import qualified Data.Set as Set+import qualified Data.Text as Text import Hadolint.Rule import Language.Docker.Syntax @@ -12,7 +13,8 @@     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 _ _ _ _ (CopySource s)))+    check line st (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource s)))+      | ":" `Text.isInfixOf` dropQuotes s = st       | Set.member s (state st) = st       | otherwise = st |> addFail CheckFailure {..}     check _ st _ = st
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 _ _ _ _ (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/DL3045.hs view
@@ -32,7 +32,7 @@      check _ st (From from) = st |> modify (rememberStage from)     check _ st (Workdir _) = st |> modify rememberWorkdir-    check line st (Copy (CopyArgs _ (TargetPath dest) _ _ _))+    check line st (Copy (CopyArgs _ (TargetPath dest)) _)       | Acc s m <- state st, Just True <- Map.lookup s m = st -- workdir has been set       | "/" `Text.isPrefixOf` Text.dropAround quotePredicate dest = st -- absolute dest. normal       | isWindowsAbsolute (Text.dropAround quotePredicate dest) = st -- absolute dest. windows
src/Hadolint/Rule/DL3049.hs view
@@ -1,4 +1,4 @@- module Hadolint.Rule.DL3049 (rule) where+module Hadolint.Rule.DL3049 (rule) where  import qualified Data.Map as Map import qualified Data.Set as Set@@ -12,16 +12,18 @@ rule labelschema = mconcat $ fmap missingLabelRule (Map.keys labelschema) {-# INLINEABLE rule #-} + data StageID = StageID-  { name :: Text.Text,+  { name :: BaseImage,     line :: Linenumber   } deriving (Eq, Ord, Show)  data Acc-  = Acc StageID (Set.Set StageID) (Set.Set StageID)+  = 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@@ -32,29 +34,52 @@     code = "DL3049"     severity = DLInfoC     message = "Label `" <> label <> "` is missing."-    check line state (From BaseImage {image, alias = Just als}) =-        state |> modify (currentStage (imageName image) (StageID (unImageAlias als) line))-    check line state (From BaseImage {image, alias = Nothing}) =-        state |> modify (currentStage (imageName image) (StageID (imageName image) line))+    check line state (From img) =+      state |> modify (currentStage (StageID img line))+    check _ state (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource src))) =+      state |> modify (markSilentByAlias src)     check _ state (Label pairs)-        | label `elem` fmap fst pairs = state |> modify goodStage-        | otherwise = state+      | label `elem` fmap fst pairs =+          state+            |> modify (markSilentByAlias (getCurrentStageName state))+            |> modify markGood+      | otherwise = state     check _ state _ = state      markFailure :: State Acc -> Failures-    markFailure (State fails (Acc _ _ b)) = Set.foldl' (Seq.|>) fails (Set.map markFail b)+    markFailure (State fails (Acc _ _ _ b)) = Set.foldl' (Seq.|>) fails (Set.map markFail b)     markFailure st = failures st      markFail (StageID _ line) = CheckFailure {..} -currentStage :: Text.Text -> StageID -> Acc -> Acc-currentStage src stageid (Acc _ g b)-    | not $ Set.null (Set.filter (predicate src) g) = Acc stageid (g |> Set.insert stageid) b-    | otherwise = Acc stageid g (b |> Set.insert stageid)++currentStage :: StageID -> Acc -> Acc+currentStage stageid Empty = Acc stageid Set.empty Set.empty (Set.singleton stageid)+currentStage stageid (Acc _ g s b)+  | not $ Set.null (Set.filter (predicate stageid) g) =+      Acc stageid (g |> Set.insert stageid) s b+  | otherwise = Acc stageid g s (b |> Set.insert stageid)   where-    predicate n0 StageID {name = n1} = n1 == n0-currentStage _ stageid Empty = Acc stageid Set.empty (Set.singleton stageid)+    predicate (StageID _ _) (StageID BaseImage {alias = Nothing} _) = False+    predicate (StageID BaseImage {image} _) (StageID BaseImage {alias = Just als} _) =+      unImageAlias als == imageName image -goodStage :: Acc -> Acc-goodStage (Acc stageid g b) = Acc stageid (g |> Set.insert stageid) (b |> Set.delete stageid)-goodStage Empty = Empty+markGood :: Acc -> Acc+markGood Empty = Empty+markGood (Acc stageid good silent bad) =+  Acc stageid (good |> Set.insert stageid) (silent |> Set.delete stageid) (bad |> Set.delete stageid)++markSilentByAlias :: Text.Text -> Acc -> Acc+markSilentByAlias _ Empty = Empty+markSilentByAlias silentname (Acc stageid good silent bad) =+  Acc stageid good (silent |> Set.union stages) (bad |> remove stages)+  where+    stages = Set.filter byName bad+    byName (StageID BaseImage {alias = Nothing} _) = False+    byName (StageID BaseImage {alias = Just als} _) = unImageAlias als == silentname+    remove set fromThis = Set.difference fromThis set++getCurrentStageName :: State Acc -> Text.Text+getCurrentStageName (State _ (Acc (StageID BaseImage {image, alias = Nothing} _) _ _ _)) = imageName image+getCurrentStageName (State _ (Acc (StageID BaseImage {alias = Just als} _) _ _ _)) = unImageAlias als+getCurrentStageName _ = ""
src/Hadolint/Rule/DL3057.hs view
@@ -8,7 +8,8 @@   data StageID = StageID-  { name :: Text.Text,+  { src :: Text.Text,+    name :: Text.Text,     line :: Linenumber   } deriving (Show, Eq, Ord) @@ -25,16 +26,24 @@     message = "`HEALTHCHECK` instruction missing."      check line state (From BaseImage {image, alias = Just als}) =-      state |> modify (currentStage (imageName image) (StageID (unImageAlias als) line))+      state |> modify+                  ( currentStage+                      (imageName image)+                      (StageID (imageName image) (unImageAlias als) line)+                  )     check line state (From BaseImage {image, alias = Nothing}) =-      state |> modify (currentStage (imageName image) (StageID (imageName image) line))+      state |> modify+                  ( currentStage+                      (imageName image)+                      (StageID (imageName image) (imageName image) line)+                  )     check _ state (Healthcheck _) = state |> modify goodStage     check _ state _ = state      markFailures :: State Acc -> Failures     markFailures (State fails (Acc _ _ b)) = Set.foldl' (Seq.|>) fails (Set.map makeFail b)     markFailures st = failures st-    makeFail (StageID _ line) = CheckFailure {..}+    makeFail (StageID _ _ line) = CheckFailure {..} {-# INLINEABLE rule #-}  currentStage :: Text.Text -> StageID -> Acc -> Acc@@ -46,5 +55,29 @@ currentStage _ stageid Empty = Acc stageid Set.empty (Set.singleton stageid)  goodStage :: Acc -> Acc-goodStage (Acc stageid g b) = Acc stageid (g |> Set.insert stageid) (b |> Set.delete stageid)+goodStage (Acc stageid g b) = do+  let nowGood = recurseGood b stageid+  let good =+        g+          |> Set.union nowGood+          |> Set.insert stageid+      bad =+        b+          |> flip Set.difference nowGood+          |> Set.delete stageid+   in Acc+        stageid+        good+        bad+  where+    predicate StageID { src = s1 } StageID { name = n1 } = n1 == s1++    recurseGood :: Set.Set StageID -> StageID -> Set.Set StageID+    recurseGood bad sid = do+      let g1 = Set.filter (predicate sid) bad  -- bad stages to be marked good+          b1 = Set.difference bad g1  -- bad stages not to be marked good+       in if Set.null g1+            then g1+            else Set.union g1 $ Set.unions $ Set.map (recurseGood b1) g1+ goodStage Empty = Empty
test/Hadolint/Config/ConfigfileSpec.hs view
@@ -46,13 +46,13 @@           conf = parseYaml yaml       conf `shouldBe` Right mempty { partialVerbose = Just False } -    it "parse `output-format: json`" $ do-      let yaml = ["output-format: json"]+    it "parse `format: json`" $ do+      let yaml = ["format: json"]           conf = parseYaml yaml       conf `shouldBe` Right mempty { partialFormat = Just Json } -    it "parse `output-format: sarif`" $ do-      let yaml = ["output-format: sarif"]+    it "parse `format: sarif`" $ do+      let yaml = ["format: sarif"]           conf = parseYaml yaml       conf `shouldBe` Right mempty { partialFormat = Just Sarif } 
test/Hadolint/Config/EnvironmentSpec.hs view
@@ -210,6 +210,7 @@   unsetEnv "HADOLINT_REQUIRE_LABELS"   unsetEnv "HADOLINT_STRICT_LABELS"   unsetEnv "HADOLINT_FAILURE_THRESHOLD"+  unsetEnv "HADOLINT_DISABLE_IGNORE_PRAGMA"  -- On Windows setting an environment variable to the empty string is the same as -- unsetting it. On POSIX, an environment variable can be set and contain the
test/Hadolint/Rule/DL3013Spec.hs view
@@ -76,6 +76,12 @@       onBuildRuleCatchesNot         "DL3013"         "RUN pip install git+https://github.com/rtfd/r-ext.git@0.6-alpha#egg=r-ext"+      ruleCatchesNot+        "DL3013"+        "RUN pip install git+ssh://github.com/rtfd/r-ext.git@0.6-alpha#egg=r-ext"+      onBuildRuleCatchesNot+        "DL3013"+        "RUN pip install git+ssh://github.com/rtfd/r-ext.git@0.6-alpha#egg=r-ext"     it "pip install unversioned git" $ do       ruleCatches         "DL3013"@@ -83,6 +89,26 @@       onBuildRuleCatches         "DL3013"         "RUN pip install git+https://github.com/rtfd/read-ext.git#egg=read-ext"+      ruleCatches+        "DL3013"+        "RUN pip install git+ssh://github.com/rtfd/read-ext.git#egg=read-ext"+      onBuildRuleCatches+        "DL3013"+        "RUN pip install git+ssh://github.com/rtfd/read-ext.git#egg=read-ext"+    it "pip install local dir" $ do+      ruleCatchesNot+        "DL3013"+        "RUN pip install foo/bar"+      onBuildRuleCatchesNot+        "DL3013"+        "RUN pip install foo/bar"+    it "pip install https url package" $ do+      ruleCatchesNot+        "DL3013"+        "RUN pip install https://foo.bar/baz.zip"+      onBuildRuleCatchesNot+        "DL3013"+        "RUN pip install https://foo.bar/baz.zip"     it "pip install upper bound" $ do       ruleCatchesNot "DL3013" "RUN pip install 'alabaster>=0.7'"       onBuildRuleCatchesNot "DL3013" "RUN pip install 'alabaster>=0.7'"
test/Hadolint/Rule/DL3022Spec.hs view
@@ -29,3 +29,4 @@               "RUN baz"             ]        in ruleCatchesNot "DL3022" $ Text.unlines dockerFile+    it "don't warn on external images" $ ruleCatchesNot "DL3022" "COPY --from=haskell:latest bar ."
test/Hadolint/Rule/DL3026Spec.hs view
@@ -11,7 +11,7 @@ spec = do   let ?config = def -  describe "DL2036 - Use only an allowed registry in the FROM image" $ do+  describe "DL3026 - Use only an allowed registry in the FROM image" $ do     it "does not warn on empty allowed registries" $ do       let dockerFile =             [ "FROM random.com/debian"
test/Hadolint/Rule/DL3049Spec.hs view
@@ -43,6 +43,15 @@        in assertChecks             (Text.unlines dockerFile)             (failsWith 2 "DL3049")+    it "warn once: two stages, label present in first only" $+      let dockerFile =+            [ "FROM baseimage",+              "LABEL foo=\"bar\"",+              "FROM newimage"+            ]+       in assertChecks+            (Text.unlines dockerFile)+            (failsWith 1 "DL3049")     it "warn once: two stages, label present in second only" $       let dockerFile =             [ "FROM baseimage",@@ -62,14 +71,41 @@        in assertChecks             (Text.unlines dockerFile)             (failsWith 1 "DL3049")-    it "warn once: two stages, inheritance, label only defined in second stage" $+    it "warn twice: two stages, inheritance, no labels" $       let dockerFile =             [ "FROM baseimage as base",+              "FROM base"+            ]+       in assertChecks+            (Text.unlines dockerFile)+            (failsWith 2 "DL3049")+    it "don't warn: two stages, inheritance, label defined in second stage" $+      let dockerFile =+            [ "FROM baseimage as base",               "FROM base",               "LABEL foo=\"bar\""             ]        in assertChecks             (Text.unlines dockerFile)+            (failsWith 0 "DL3049")+    it "don't warn: two stages, no inheritance, label in last stage, with copy" $+      let dockerFile =+            [ "FROM baseimage as base",+              "FROM anotherimage",+              "LABEL foo=\"bar\"",+              "COPY --from=base /bar /baz"+            ]+       in assertChecks+            (Text.unlines dockerFile)+            (failsWith 0 "DL3049")+    it "warn once: two stages, no inheritance, label in last stage, no connection" $+      let dockerFile =+            [ "FROM baseimage as base",+              "FROM anotherimage",+              "LABEL foo=\"bar\""+            ]+       in assertChecks+            (Text.unlines dockerFile)             (failsWith 1 "DL3049")     it "don't warn: two stages, inheritance" $       let dockerFile =@@ -80,3 +116,38 @@        in assertChecks             (Text.unlines dockerFile)             (failsWith 0 "DL3049")+    it "warn once: multiple results, no inheritance, label in one result" $+      let dockerFile =+            [ "FROM baseimage as base",+              "FROM newimage",+              "LABEL foo=\"bar\"",+              "COPY --from=base /bar /baz",+              "",+              "FROM newimage",+              "COPY --from=base /bar /baz"+            ]+       in assertChecks+            (Text.unlines dockerFile)+            (failsWith 1 "DL3049")+    it "warn once: multiple results, inheritance, label in one result" $+      let dockerFile =+            [ "FROM baseimage as base",+              "FROM base",+              "LABEL foo=\"bar\"",+              "",+              "FROM base"+            ]+       in assertChecks+            (Text.unlines dockerFile)+            (failsWith 1 "DL3049")+    it "warn once: multiple results, inheritance, label in one result" $+      let dockerFile =+            [ "FROM baseimage as base",+              "FROM base",+              "",+              "FROM base",+              "LABEL foo=\"bar\""+            ]+       in assertChecks+            (Text.unlines dockerFile)+            (failsWith 1 "DL3049")
test/Hadolint/Rule/DL3057Spec.hs view
@@ -1,6 +1,7 @@ module Hadolint.Rule.DL3057Spec (spec) where  import Data.Default+import Data.Text as Text import Helpers import Test.Hspec @@ -10,11 +11,63 @@   let ?config = def    describe "DL3057 - `HEALTHCHECK instruction missing" $ do-    it "warn with no HEALTHCHECK instructions" $-      ruleCatches "DL3057" "FROM scratch"-    it "ok with one HEALTHCHECK instruction" $-      ruleCatchesNot "DL3057" "FROM scratch\nHEALTHCHECK CMD /bin/bla"-    it "ok with inheriting HEALTHCHECK instruction" $-      ruleCatchesNot "DL3057" "FROM scratch AS base\nHEALTHCHECK CMD /bin/bla\nFROM base"-    it "warn when not inheriting with no HEALTHCHECK instruction" $-      ruleCatches "DL3057" "FROM scratch AS base\nHEALTHCHECK CMD /bin/bla\nFROM scratch"++    it "warn with no HEALTHCHECK instructions" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch"+            ]+       in ruleCatches "DL3057" dockerfile++    it "ok when HEALTHCHECK is explicitly disabled" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch",+              "HEALTHCHECK NONE"+            ]+       in ruleCatchesNot "DL3057" dockerfile++    it "ok with one HEALTHCHECK instruction" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch",+              "HEALTHCHECK CMD /bin/bla"+            ]+       in ruleCatchesNot "DL3057" dockerfile++    it "ok with inheriting HEALTHCHECK instruction" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch AS base",+              "HEALTHCHECK CMD /bin/bla",+              "FROM base"+            ]+       in ruleCatchesNot "DL3057" dockerfile++    it "ok with ending inheritance chain with HEALTCHECK" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch AS base1",+              "FROM base1 AS base2",+              "FROM base2 AS base3",+              "FROM base3 AS end",+              "HEALTHCHECK NONE"+            ]+       in ruleCatchesNot "DL3057" dockerfile++    it "warn when inheritance chain bifurcates" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch AS base1",+              "FROM base1 AS base2",+              "FROM base2 AS base3.1",+              "FROM base2 AS base3.2",  -- This will trigger DL3057+              "",+              "FROM base3.1 AS end1",+              "HEALTHCHECK NONE",+              "",+              "FROM base3.2 AS end2"  -- This will trigger DL3057+            ]+       in ruleCatches "DL3057" dockerfile++    it "warn when not inheriting with no HEALTHCHECK instruction" $ do+      let dockerfile = Text.unlines+            [ "FROM scratch AS base",+              "HEALTHCHECK CMD /bin/bla",+              "FROM scratch"+            ]+       in ruleCatches "DL3057" dockerfile