hadolint 2.3.0 → 2.4.0
raw patch · 10 files changed
+274/−75 lines, 10 filesdep ~language-dockerPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: language-docker
API changes (from Hackage documentation)
+ Hadolint.Config: [failureThreshold] :: ConfigFile -> Maybe DLSeverity
+ Hadolint.Config: getConfig :: Maybe FilePath -> IO (Maybe FilePath)
+ Hadolint.Lint: [failThreshold] :: LintOptions -> DLSeverity
+ Hadolint.Rule: instance Data.YAML.FromYAML Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Base.Monoid Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Base.Semigroup Hadolint.Rule.DLSeverity
+ Hadolint.Rule: instance GHC.Read.Read Hadolint.Rule.DLSeverity
+ Hadolint.Rule: readSeverity :: Text -> Either Text DLSeverity
+ Hadolint.Rule: withSeverity :: (DLSeverity -> Parser a) -> Node Pos -> Parser a
+ Hadolint.Rule.DL3060: instance GHC.Show.Show Hadolint.Rule.DL3060.Acc
- Hadolint.Config: ConfigFile :: Maybe OverrideConfig -> Maybe [IgnoreRule] -> Maybe [TrustedRegistry] -> Maybe LabelSchema -> Maybe Bool -> ConfigFile
+ Hadolint.Config: ConfigFile :: Maybe OverrideConfig -> Maybe [IgnoreRule] -> Maybe [TrustedRegistry] -> Maybe LabelSchema -> Maybe Bool -> Maybe DLSeverity -> ConfigFile
- Hadolint.Lint: LintOptions :: [ErrorRule] -> [WarningRule] -> [InfoRule] -> [StyleRule] -> [IgnoreRule] -> RulesConfig -> LintOptions
+ Hadolint.Lint: LintOptions :: [ErrorRule] -> [WarningRule] -> [InfoRule] -> [StyleRule] -> [IgnoreRule] -> RulesConfig -> DLSeverity -> LintOptions
- Hadolint.Lint: type ErrorRule = Text
+ Hadolint.Lint: type ErrorRule = RuleCode
- Hadolint.Lint: type InfoRule = Text
+ Hadolint.Lint: type InfoRule = RuleCode
- Hadolint.Lint: type StyleRule = Text
+ Hadolint.Lint: type StyleRule = RuleCode
- Hadolint.Lint: type WarningRule = Text
+ Hadolint.Lint: type WarningRule = RuleCode
Files
- README.md +4/−3
- app/Main.hs +69/−18
- hadolint.cabal +6/−6
- src/Hadolint/Config.hs +35/−18
- src/Hadolint/Lint.hs +13/−11
- src/Hadolint/Rule.hs +24/−1
- src/Hadolint/Rule/DL3060.hs +54/−7
- test/ConfigSpec.hs +17/−10
- test/DL3060.hs +49/−0
- test/Spec.hs +3/−1
README.md view
@@ -127,11 +127,12 @@ ``` 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`+a configuration file in the current directory with the name `.hadolint.yaml` or+`.hadolint.yml` The global configuration file should be placed in the folder specified by `XDG_CONFIG_HOME`,-with the name `hadolint.yaml`. In summary, the following locations are valid for the configuration-file, in order or preference:+with the name `hadolint.yaml` or `hadolint.yml`. In summary, the following locations are valid+for the configuration file, in order or preference: - `$PWD/.hadolint.yaml` - `$XDG_CONFIG_HOME/hadolint.yaml`
app/Main.hs view
@@ -1,11 +1,12 @@-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} module Main where import Control.Applicative+import Control.Monad (when) import qualified Data.Bifunctor as Bifunctor import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map as Map@@ -17,9 +18,11 @@ import qualified Data.Version import qualified Development.GitRev import qualified Hadolint+import qualified Hadolint.Formatter.Format as Format import qualified Hadolint.Rule as Rule import Options.Applicative ( Parser,+ ReadM, action, argument, completeWith,@@ -35,7 +38,6 @@ metavar, option, progDesc,- ReadM, short, showDefaultWith, str,@@ -47,12 +49,14 @@ import qualified Paths_hadolint as Meta import System.Environment import System.Exit (exitFailure, exitSuccess)+import System.IO (hPutStrLn, stderr) data CommandOptions = CommandOptions { showVersion :: Bool, noFail :: Bool, nocolor :: Bool, configFile :: Maybe FilePath,+ isVerbose :: Bool, format :: Hadolint.OutputFormat, dockerfiles :: [String], lintingOptions :: Hadolint.LintOptions@@ -75,6 +79,15 @@ showFormat Hadolint.Checkstyle = "checkstyle" showFormat Hadolint.Codacy = "codacy" +toNofailSeverity :: String -> Maybe Rule.DLSeverity+toNofailSeverity "error" = Just Rule.DLErrorC+toNofailSeverity "warning" = Just Rule.DLWarningC+toNofailSeverity "info" = Just Rule.DLInfoC+toNofailSeverity "style" = Just Rule.DLStyleC+toNofailSeverity "ignore" = Just Rule.DLIgnoreC+toNofailSeverity "none" = Just Rule.DLIgnoreC+toNofailSeverity _ = Nothing+ parseOptions :: Parser CommandOptions parseOptions = CommandOptions@@ -82,6 +95,7 @@ <*> noFail <*> nocolor <*> configFile+ <*> isVerbose <*> outputFormat <*> files <*> lintOptions@@ -90,10 +104,28 @@ noFail = switch (long "no-fail" <> help "Don't exit with a failure status code when any rule is violated") + noFailCutoff =+ option+ (maybeReader toNofailSeverity)+ ( short 't'+ <> long "failure-theshold"+ <> help+ "Exit with failure code only when rules with a severity \+ \above THRESHOLD are violated. Accepted values: \+ \[error | warning | info | style | ignore | none]"+ <> value Rule.DLInfoC+ <> metavar "THRESHOLD"+ <> showDefaultWith (Text.unpack . Format.severityText)+ <> completeWith ["error", "warning", "info", "style", "ignore", "none"]+ )+ nocolor = switch (long "no-color" <> help "Don't colorize output") - strictlabels = switch (long "strict-labels"- <> help "Do not permit labels other than specified in `label-schema`")+ strictlabels =+ switch+ ( long "strict-labels"+ <> help "Do not permit labels other than specified in `label-schema`"+ ) configFile = optional@@ -103,6 +135,8 @@ ) ) + isVerbose = switch (long "verbose" <> short 'V' <> help "Enables verbose logging of hadolint's output to stderr")+ outputFormat = option (maybeReader toOutputFormat)@@ -170,10 +204,13 @@ <*> styleList <*> ignoreList <*> parseRulesConfig+ <*> noFailCutoff - labels = Map.fromList+ labels =+ Map.fromList <$> many- ( option readSingleLabelSchema+ ( option+ readSingleLabelSchema ( long "require-label" <> help "The option --require-label=label:format makes Hadolint check that the label `label` conforms to format requirement `format`" <> metavar "LABELSCHEMA (e.g. maintainer:text)"@@ -186,7 +223,8 @@ <*> labels <*> strictlabels - parseAllowedRegistries = Set.fromList . fmap fromString+ parseAllowedRegistries =+ Set.fromList . fmap fromString <$> many ( strOption ( long "trusted-registry"@@ -202,19 +240,26 @@ labelParser :: Text.Text -> Either String (Rule.LabelName, Rule.LabelType) labelParser l =- case Bifunctor.second (Rule.read . Text.drop 1) $ Text.breakOn ":" l of- (ln, Right lt) -> Right (ln, lt)- (_, Left e) -> Left $ Text.unpack e+ case Bifunctor.second (Rule.read . Text.drop 1) $ Text.breakOn ":" l of+ (ln, Right lt) -> Right (ln, lt)+ (_, Left e) -> Left $ Text.unpack e -noFailure :: Hadolint.Result s e -> Bool-noFailure (Hadolint.Result _ Seq.Empty Seq.Empty) = True-noFailure _ = False+noFailure :: Hadolint.Result s e -> Rule.DLSeverity -> Bool+noFailure (Hadolint.Result _ Seq.Empty Seq.Empty) _ = True+noFailure (Hadolint.Result _ Seq.Empty fails) cutoff =+ Seq.null (Seq.filter (\f -> Rule.severity f < cutoff) fails)+noFailure _ _ = False -exitProgram :: Foldable f => CommandOptions -> f (Hadolint.Result s e) -> IO ()-exitProgram cmd res+exitProgram ::+ Foldable f =>+ CommandOptions ->+ Hadolint.LintOptions ->+ f (Hadolint.Result s e) ->+ IO ()+exitProgram cmd conf res | noFail cmd = exitSuccess | Hadolint.shallSkipErrorStatus (format cmd) = exitSuccess- | all noFailure res = exitSuccess+ | all (`noFailure` Hadolint.failThreshold conf) res = exitSuccess | otherwise = exitFailure runLint :: CommandOptions -> Hadolint.LintOptions -> NonEmpty.NonEmpty String -> IO ()@@ -223,7 +268,7 @@ noColorEnv <- lookupEnv "NO_COLOR" let noColor = nocolor cmd || isJust noColorEnv Hadolint.printResults (format cmd) noColor res- exitProgram cmd res+ exitProgram cmd conf res main :: IO () main = do@@ -234,7 +279,9 @@ execute CommandOptions {dockerfiles = []} = putStrLn "Please provide a Dockerfile" >> exitFailure execute cmd = do- lintConfig <- Hadolint.applyConfig (configFile cmd) (lintingOptions cmd)+ maybeConfig <- Hadolint.getConfig (configFile cmd)+ when (isVerbose cmd) (hPutStrLn stderr $ getFilePathDescription maybeConfig)+ lintConfig <- Hadolint.applyConfig maybeConfig (lintingOptions cmd) let files = NonEmpty.fromList (dockerfiles cmd) case lintConfig of Left err -> error err@@ -253,3 +300,7 @@ | otherwise = "Haskell Dockerfile Linter " ++ version where version = $(Development.GitRev.gitDescribe)++getFilePathDescription :: Maybe FilePath -> String+getFilePathDescription Nothing = "No configuration was specified. Using default configuration"+getFilePathDescription (Just filepath) = "Configuration file used: " ++ filepath
hadolint.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 76044842a02febfc721b4776d4e4bbfdb11c9327f25de10eca894d0d19c1af6b+-- hash: 0122b347f3d7e60bbead61f38f32acd69b57e1794597b5243bb2b6cabf2a358f name: hadolint-version: 2.3.0+version: 2.4.0 synopsis: Dockerfile Linter JavaScript API description: A smarter Dockerfile linter that helps you build best practice Docker images. category: Development@@ -137,7 +137,7 @@ , filepath , foldl , ilist- , language-docker >=9.3.0 && <10+ , language-docker >=10.0.0 && <11 , megaparsec >=9.0.0 , mtl , network-uri@@ -158,14 +158,14 @@ Paths_hadolint hs-source-dirs: app- default-extensions: OverloadedStrings NamedFieldPuns DeriveGeneric DeriveAnyClass RecordWildCards StrictData ScopedTypeVariables PatternSynonyms+ default-extensions: OverloadedStrings NamedFieldPuns DeriveGeneric DeriveAnyClass RecordWildCards StrictData ScopedTypeVariables PatternSynonyms TemplateHaskell 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" build-depends: base >=4.8 && <5 , containers , gitrev >=1.3.1 , hadolint- , language-docker >=9.3.0 && <10+ , language-docker >=10.0.0 && <11 , megaparsec >=9.0.0 , optparse-applicative >=0.14.0 , text@@ -264,7 +264,7 @@ , foldl , hadolint , hspec- , language-docker >=9.3.0 && <10+ , language-docker >=10.0.0 && <11 , megaparsec >=9.0.0 , split >=0.2 , text
src/Hadolint/Config.hs view
@@ -1,5 +1,6 @@ module Hadolint.Config ( applyConfig,+ getConfig, ConfigFile (..), OverrideConfig (..), )@@ -47,17 +48,22 @@ ignoredRules :: Maybe [Lint.IgnoreRule], trustedRegistries :: Maybe [Lint.TrustedRegistry], labelSchemaConfig :: Maybe Rule.LabelSchema,- strictLabelSchema :: Maybe Bool+ strictLabelSchema :: Maybe Bool,+ failureThreshold :: Maybe Rule.DLSeverity } deriving (Show, Eq, Generic) instance Yaml.FromYAML OverrideConfig where- parseYAML = Yaml.withMap "OverrideConfig" $ \m ->- OverrideConfig- <$> m .:? "error"- <*> m .:? "warning"- <*> m .:? "info"- <*> m .:? "style"+ parseYAML = Yaml.withMap "OverrideConfig" $ \m -> do+ err <- m .:? "error"+ wrn <- m .:? "warning"+ inf <- m .:? "info"+ sty <- m .:? "style"+ let overrideErrorRules = coerce (err :: Maybe [Text.Text])+ overrideWarningRules = coerce (wrn :: Maybe [Text.Text])+ overrideInfoRules = coerce (inf :: Maybe [Text.Text])+ overrideStyleRules = coerce (sty:: Maybe [Text.Text])+ return OverrideConfig {..} instance Yaml.FromYAML ConfigFile where parseYAML = Yaml.withMap "ConfigFile" $ \m -> do@@ -67,6 +73,7 @@ trustedRegistries <- m .:? "trustedRegistries" labelSchemaConfig <- m .:? "label-schema" strictLabelSchema <- m .:? "strict-labels"+ failureThreshold <- m .:? "failure-threshold" return ConfigFile {..} -- | If both the ignoreRules and rulesConfig properties of Lint options are empty@@ -77,19 +84,10 @@ applyConfig maybeConfig o | not (Prelude.null (Lint.ignoreRules o)) && Lint.rulesConfig o /= mempty = return (Right o) | otherwise = do- theConfig <-- case maybeConfig of- Nothing -> findConfig- c -> return c- case theConfig of+ case maybeConfig of Nothing -> return (Right o) Just config -> parseAndApply config where- findConfig = do- localConfigFile <- (</> ".hadolint.yaml") <$> getCurrentDirectory- configFile <- getXdgDirectory XdgConfig "hadolint.yaml"- listToMaybe <$> filterM doesFileExist [localConfigFile, configFile]- parseAndApply :: FilePath -> IO (Either String Lint.LintOptions) parseAndApply configFile = do contents <- Bytes.readFile configFile@@ -106,6 +104,7 @@ overrideInfo <- overrideInfoRules <|> Just mempty overrideStyle <- overrideStyleRules <|> Just mempty overrideIgnored <- ignoredRules <|> Just mempty+ overrideThreshold <- failureThreshold <|> Just mempty trusted <- Set.fromList . coerce <$> (trustedRegistries <|> Just mempty) schema <- labelSchemaConfig <|> Just mempty@@ -125,7 +124,8 @@ { Process.allowedRegistries = Process.allowedRegistries rulesConfig `ifNull` trusted, Process.labelSchema = Process.labelSchema rulesConfig `ifNull` schema, Process.strictLabels = Process.strictLabels rulesConfig || strictLabels- }+ },+ Lint.failThreshold = Lint.failThreshold o <> overrideThreshold } ifNull value override = if null value then override else value@@ -151,3 +151,20 @@ "", err ]++-- | Gets the configuration file which Hadolint uses+getConfig :: Maybe FilePath -> IO (Maybe FilePath)+getConfig maybeConfig =+ case maybeConfig of+ Nothing -> findConfig+ _ -> return maybeConfig+ where+ findConfig :: IO (Maybe FilePath)+ findConfig = do+ localConfigFiles <- traverse+ (\filePath -> (</> filePath) <$> getCurrentDirectory)+ (fmap ("."++) acceptedConfigs)+ configFiles <- traverse (getXdgDirectory XdgConfig) acceptedConfigs+ listToMaybe <$> filterM doesFileExist (localConfigFiles ++ configFiles)+ where+ acceptedConfigs = ["hadolint.yaml", "hadolint.yml"]
src/Hadolint/Lint.hs view
@@ -24,13 +24,13 @@ import Language.Docker.Parser (DockerfileError, Error) import Language.Docker.Syntax (Dockerfile) -type ErrorRule = Text+type ErrorRule = Hadolint.Rule.RuleCode -type WarningRule = Text+type WarningRule = Hadolint.Rule.RuleCode -type InfoRule = Text+type InfoRule = Hadolint.Rule.RuleCode -type StyleRule = Text+type StyleRule = Hadolint.Rule.RuleCode type IgnoreRule = Hadolint.Rule.RuleCode @@ -42,12 +42,13 @@ infoRules :: [InfoRule], styleRules :: [StyleRule], ignoreRules :: [IgnoreRule],- rulesConfig :: Hadolint.Process.RulesConfig+ rulesConfig :: Hadolint.Process.RulesConfig,+ failThreshold :: Hadolint.Rule.DLSeverity } deriving (Show) instance Semigroup LintOptions where- LintOptions a1 a2 a3 a4 a5 a6 <> LintOptions b1 b2 b3 b4 b5 b6 =+ LintOptions a1 a2 a3 a4 a5 a6 a7 <> LintOptions b1 b2 b3 b4 b5 b6 b7 = LintOptions (a1 <> b1) (a2 <> b2)@@ -55,9 +56,10 @@ (a4 <> b4) (a5 <> b5) (a6 <> b6)+ (a7 <> b7) instance Monoid LintOptions where- mempty = LintOptions mempty mempty mempty mempty mempty mempty+ mempty = LintOptions mempty mempty mempty mempty mempty mempty mempty -- | Performs the process of parsing the dockerfile and analyzing it with all the applicable -- rules, depending on the list of ignored rules.@@ -99,10 +101,10 @@ fixSeverity LintOptions {..} = Seq.filter ignoredRules . Seq.mapWithIndex (const correctSeverity) where correctSeverity =- makeSeverity Hadolint.Rule.DLErrorC (fmap Hadolint.Rule.RuleCode errorRules)- . makeSeverity Hadolint.Rule.DLWarningC (fmap Hadolint.Rule.RuleCode warningRules)- . makeSeverity Hadolint.Rule.DLInfoC (fmap Hadolint.Rule.RuleCode infoRules)- . makeSeverity Hadolint.Rule.DLStyleC (fmap Hadolint.Rule.RuleCode styleRules)+ makeSeverity Hadolint.Rule.DLErrorC errorRules+ . makeSeverity Hadolint.Rule.DLWarningC warningRules+ . makeSeverity Hadolint.Rule.DLInfoC infoRules+ . makeSeverity Hadolint.Rule.DLStyleC styleRules ignoredRules = ignoreFilter ignoreRules
src/Hadolint/Rule.hs view
@@ -21,7 +21,30 @@ | DLInfoC | DLStyleC | DLIgnoreC- deriving (Show, Eq, Ord, Generic, NFData)+ deriving (Show, Read, Eq, Ord, Generic, NFData)++instance Yaml.FromYAML DLSeverity where+ parseYAML = withSeverity pure++withSeverity :: (DLSeverity -> Yaml.Parser a) -> Yaml.Node Yaml.Pos -> Yaml.Parser a+withSeverity f v@(Yaml.Scalar _ (Yaml.SStr b)) =+ case Hadolint.Rule.readSeverity b of+ Right s -> f s+ Left _ -> Yaml.typeMismatch "severity" v+withSeverity _ v = Yaml.typeMismatch "severity" v++readSeverity :: Text.Text -> Either Text.Text DLSeverity+readSeverity "error" = Right DLErrorC+readSeverity "warning" = Right DLWarningC+readSeverity "info" = Right DLInfoC+readSeverity "style" = Right DLStyleC+readSeverity "ignore" = Right DLIgnoreC+readSeverity "none" = Right DLIgnoreC+readSeverity t = Left ("Invalid severity: " <> t)++instance Semigroup DLSeverity where s1 <> s2 = min s1 s2++instance Monoid DLSeverity where mempty = DLIgnoreC newtype RuleCode = RuleCode {unRuleCode :: Text.Text} deriving (Show, Eq, Ord)
src/Hadolint/Rule/DL3060.hs view
@@ -1,27 +1,74 @@ module Hadolint.Rule.DL3060 (rule) where +import qualified Data.Map.Strict as Map+import qualified Data.Text as Text import Hadolint.Rule import qualified Hadolint.Shell as Shell import Language.Docker.Syntax +data Acc+ = Acc+ { current :: BaseImage,+ active :: Map.Map Text.Text Linenumber,+ inactive :: Map.Map Linenumber BaseImage+ }+ | Empty+ deriving (Show)+ rule :: Rule Shell.ParsedShell-rule = simpleRule code severity message check+rule = veryCustomRule check (emptyState Empty) markFailures 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+ check line st (From from) =+ st |> modify (rememberStage line from)+ check line st (Run (RunArgs args _))+ | foldArguments (Shell.anyCommands yarnInstall) args+ && foldArguments (Shell.noCommands yarnCacheClean) args =+ st |> modify (rememberLine line)+ | otherwise = st+ check _ st _ = st++ -- Produce failures from the final state Acc+ markFailures :: State Acc -> Failures+ markFailures (State fails Empty) = fails+ markFailures (State _ Acc {..}) = inactive |> Map.foldMapWithKey mapFail+ where+ mapFail line from+ | from == current = pure CheckFailure {..}+ | BaseImage {alias = Just (ImageAlias als)} <- from,+ Just _ <- Map.lookup als active = pure CheckFailure {..}+ | otherwise = mempty {-# INLINEABLE rule #-} +rememberStage :: Linenumber -> BaseImage -> Acc -> Acc+rememberStage line stage@BaseImage {image = Image _ als} Empty =+ Acc stage (Map.singleton als line) Map.empty+rememberStage line stage@BaseImage {image = Image _ als} (Acc _ stages o) =+ Acc stage (Map.insert als line stages) o++rememberLine :: Linenumber -> Acc -> Acc+rememberLine line Empty = Acc scratch mempty (Map.singleton line scratch)+rememberLine line (Acc from stages o) = Acc from stages (Map.insert line from o)+ yarnInstall :: Shell.Command -> Bool yarnInstall = Shell.cmdHasArgs "yarn" ["install"] yarnCacheClean :: Shell.Command -> Bool yarnCacheClean = Shell.cmdHasArgs "yarn" ["cache", "clean"]++-- | This is needed as placeholder when no FROM statement has yet been+-- envountered.+scratch :: BaseImage+scratch =+ ( BaseImage+ { image = "scratch",+ tag = Nothing,+ digest = Nothing,+ alias = Nothing,+ platform = Nothing+ }+ )
test/ConfigSpec.hs view
@@ -20,7 +20,7 @@ " - SC1010" ] override = Just (OverrideConfig (Just ["DL3000", "SC1010"]) Nothing Nothing Nothing)- expected = ConfigFile override Nothing Nothing Nothing Nothing+ expected = ConfigFile override Nothing Nothing Nothing Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only warning severities" $@@ -31,7 +31,7 @@ " - SC1010" ] override = Just (OverrideConfig Nothing (Just ["DL3000", "SC1010"]) Nothing Nothing)- expected = ConfigFile override Nothing Nothing Nothing Nothing+ expected = ConfigFile override Nothing Nothing Nothing Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only info severities" $@@ -42,7 +42,7 @@ " - SC1010" ] override = Just (OverrideConfig Nothing Nothing (Just ["DL3000", "SC1010"]) Nothing)- expected = ConfigFile override Nothing Nothing Nothing Nothing+ expected = ConfigFile override Nothing Nothing Nothing Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only style severities" $@@ -53,7 +53,7 @@ " - SC1010" ] override = Just (OverrideConfig Nothing Nothing Nothing (Just ["DL3000", "SC1010"]))- expected = ConfigFile override Nothing Nothing Nothing Nothing+ expected = ConfigFile override Nothing Nothing Nothing Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only ignores" $@@ -62,7 +62,7 @@ "- DL3000", "- SC1010" ]- expected = ConfigFile Nothing (Just ["DL3000", "SC1010"]) Nothing Nothing Nothing+ expected = ConfigFile Nothing (Just ["DL3000", "SC1010"]) Nothing Nothing Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only trustedRegistries" $@@ -71,7 +71,7 @@ "- hub.docker.com", "- my.shady.xyz" ]- expected = ConfigFile Nothing Nothing (Just ["hub.docker.com", "my.shady.xyz"]) Nothing Nothing+ expected = ConfigFile Nothing Nothing (Just ["hub.docker.com", "my.shady.xyz"]) Nothing Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only label-schema" $@@ -80,14 +80,19 @@ " author: text", " url: url" ]- expected = ConfigFile Nothing Nothing Nothing (Just (fromList [("author", Rule.RawText), ("url", Rule.Url)])) Nothing+ expected = ConfigFile Nothing Nothing Nothing (Just (fromList [("author", Rule.RawText), ("url", Rule.Url)])) Nothing Nothing in assertConfig expected (Bytes.unlines configFile) it "Parses config with only label-schema" $ let configFile = [ "strict-labels: true" ]- expected = ConfigFile Nothing Nothing Nothing Nothing (Just True)+ expected = ConfigFile Nothing Nothing Nothing Nothing (Just True) Nothing in assertConfig expected (Bytes.unlines configFile) + it "Parses config with failure-threshold" $+ let configFile = [ "failure-threshold: error" ]+ expected = ConfigFile Nothing Nothing Nothing Nothing Nothing (Just Rule.DLErrorC)+ in assertConfig expected (Bytes.unlines configFile)+ it "Parses full file" $ let configFile = [ "override:",@@ -109,11 +114,13 @@ "strict-labels: false", "label-schema:", " author: text",- " url: url"+ " url: url",+ "",+ "failure-threshold: style" ] override = Just (OverrideConfig (Just ["DL3001"]) (Just ["DL3003"]) (Just ["DL3002"]) (Just ["DL3004"])) labelschema = Just (fromList [("author", Rule.RawText), ("url", Rule.Url)])- expected = ConfigFile override (Just ["DL3000"]) (Just ["hub.docker.com"]) labelschema (Just False)+ expected = ConfigFile override (Just ["DL3000"]) (Just ["hub.docker.com"]) labelschema (Just False) (Just Rule.DLStyleC) in assertConfig expected (Bytes.unlines configFile) assertConfig :: HasCallStack => ConfigFile -> Bytes.ByteString -> Assertion
test/DL3060.hs view
@@ -1,5 +1,6 @@ module DL3060 (tests) where +import qualified Data.Text as Text import Helpers import Test.Hspec @@ -17,3 +18,51 @@ it "ok with cache clean" $ do ruleCatchesNot "DL3060" "RUN yarn install bar && yarn cache clean" onBuildRuleCatchesNot "DL3060" "RUN yarn install bar && yarn cache clean"++ it "not ok when yarn install is in last stage w/o yarn clean" $+ let dockerFile =+ Text.unlines+ [ "FROM node:lts-alpine as foo",+ "RUN hey!",+ "FROM scratch",+ "RUN yarn install"+ ]+ in do+ ruleCatches "DL3060" dockerFile+ onBuildRuleCatches "DL3060" dockerFile++ it "not ok when inheriting from stage with yarn install w/o yarn clean" $+ let dockerFile =+ Text.unlines+ [ "FROM node:lts-alpine as foo",+ "RUN yarn install",+ "FROM foo",+ "RUN hey!"+ ]+ in do+ ruleCatches "DL3060" dockerFile+ onBuildRuleCatches "DL3060" dockerFile++ it "ok when inheriting from stage with yarn cache clear" $+ let dockerFile =+ Text.unlines+ [ "FROM node:lts-alpine as foo",+ "RUN yarn install && yarn cache clean",+ "FROM foo",+ "RUN hey!"+ ]+ in do+ ruleCatchesNot "DL3060" dockerFile+ onBuildRuleCatchesNot "DL3060" dockerFile++ it "ok when omitting yarn cache clean in stage that is not reused later" $+ let dockerFile =+ Text.unlines+ [ "FROM node:lts-alpine as foo",+ "RUN yarn install foo",+ "FROM scratch",+ "RUN hey!"+ ]+ in do+ ruleCatchesNot "DL3060" dockerFile+ onBuildRuleCatches "DL3060" dockerFile
test/Spec.hs view
@@ -60,6 +60,7 @@ import qualified DL3057 import qualified DL3058 import qualified DL3059+import qualified DL3060 import qualified DL4001 import qualified DL4003 import qualified DL4004@@ -84,7 +85,7 @@ expectedMsg = "<string>:1:1 unexpected 'F' expecting '#', ADD, ARG, CMD, COPY, ENTRYPOINT, " <> "ENV, EXPOSE, FROM, HEALTHCHECK, LABEL, MAINTAINER, ONBUILD, RUN, SHELL, STOPSIGNAL, "- <> "USER, VOLUME, WORKDIR, or end of input "+ <> "USER, VOLUME, WORKDIR, a pragma, end of input, or whitespaces " case ast of Left err -> assertEqual "Unexpected error msg" expectedMsg (formatError err) Right _ -> assertFailure "AST should fail parsing"@@ -230,6 +231,7 @@ DL3057.tests DL3058.tests DL3059.tests+ DL3060.tests DL4001.tests DL4003.tests DL4004.tests