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 +2/−1
- hadolint.cabal +9/−5
- src/Hadolint/Config/Configuration.hs +1/−1
- src/Hadolint/Rule/DL3010.hs +1/−1
- src/Hadolint/Rule/DL3013.hs +37/−2
- src/Hadolint/Rule/DL3020.hs +1/−1
- src/Hadolint/Rule/DL3021.hs +1/−1
- src/Hadolint/Rule/DL3022.hs +3/−1
- src/Hadolint/Rule/DL3023.hs +1/−1
- src/Hadolint/Rule/DL3045.hs +1/−1
- src/Hadolint/Rule/DL3049.hs +44/−19
- src/Hadolint/Rule/DL3057.hs +38/−5
- test/Hadolint/Config/ConfigfileSpec.hs +4/−4
- test/Hadolint/Config/EnvironmentSpec.hs +1/−0
- test/Hadolint/Rule/DL3013Spec.hs +26/−0
- test/Hadolint/Rule/DL3022Spec.hs +1/−0
- test/Hadolint/Rule/DL3026Spec.hs +1/−1
- test/Hadolint/Rule/DL3049Spec.hs +72/−1
- test/Hadolint/Rule/DL3057Spec.hs +61/−8
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