hadolint 2.8.0 → 2.9.0
raw patch · 35 files changed
+639/−279 lines, 35 filesdep ~ShellCheckdep ~language-dockerPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: ShellCheck, language-docker
API changes (from Hackage documentation)
+ Hadolint.Config.Configuration: [disableIgnorePragma] :: Configuration -> Bool
+ Hadolint.Config.Configuration: [partialDisableIgnorePragma] :: PartialConfiguration -> Maybe Bool
+ Hadolint.Pragma: parseIgnorePragma :: Text -> Maybe [Text]
+ Hadolint.Rule.DL1001: rule :: Rule ParsedShell
+ Hadolint.Rule.DL3061: rule :: Rule args
+ Hadolint.Shell: cmdsHaveArgs :: [Text] -> [Text] -> Command -> Bool
- Hadolint.Config.Configuration: Configuration :: Bool -> Bool -> Bool -> OutputFormat -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> Set Registry -> LabelSchema -> Bool -> DLSeverity -> Configuration
+ Hadolint.Config.Configuration: Configuration :: Bool -> Bool -> Bool -> OutputFormat -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> Set Registry -> LabelSchema -> Bool -> Bool -> DLSeverity -> Configuration
- Hadolint.Config.Configuration: PartialConfiguration :: Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe OutputFormat -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> Set Registry -> LabelSchema -> Maybe Bool -> Maybe DLSeverity -> PartialConfiguration
+ Hadolint.Config.Configuration: PartialConfiguration :: Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe OutputFormat -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> [RuleCode] -> Set Registry -> LabelSchema -> Maybe Bool -> Maybe Bool -> Maybe DLSeverity -> PartialConfiguration
Files
- README.md +59/−12
- hadolint.cabal +10/−9
- src/Hadolint/Config/Commandline.hs +10/−0
- src/Hadolint/Config/Configuration.hs +12/−4
- src/Hadolint/Config/Environment.hs +10/−2
- src/Hadolint/Meta.hs +9/−6
- src/Hadolint/Pragma.hs +4/−3
- src/Hadolint/Process.hs +10/−5
- src/Hadolint/Rule/DL1001.hs +19/−0
- src/Hadolint/Rule/DL3007.hs +1/−0
- src/Hadolint/Rule/DL3021.hs +4/−2
- src/Hadolint/Rule/DL3026.hs +15/−3
- src/Hadolint/Rule/DL3029.hs +1/−1
- src/Hadolint/Rule/DL3038.hs +2/−1
- src/Hadolint/Rule/DL3040.hs +10/−7
- src/Hadolint/Rule/DL3041.hs +6/−3
- src/Hadolint/Rule/DL3061.hs +21/−0
- src/Hadolint/Shell.hs +5/−0
- test/Hadolint/Config/CommandlineSpec.hs +12/−0
- test/Hadolint/Config/ConfigfileSpec.hs +11/−1
- test/Hadolint/Config/ConfigurationSpec.hs +17/−193
- test/Hadolint/Config/EnvironmentSpec.hs +43/−8
- test/Hadolint/Formatter/SarifSpec.hs +194/−13
- test/Hadolint/Rule/DL1001Spec.hs +41/−0
- test/Hadolint/Rule/DL3007Spec.hs +5/−0
- test/Hadolint/Rule/DL3021Spec.hs +2/−0
- test/Hadolint/Rule/DL3025Spec.hs +10/−0
- test/Hadolint/Rule/DL3026Spec.hs +26/−0
- test/Hadolint/Rule/DL3029Spec.hs +1/−0
- test/Hadolint/Rule/DL3038Spec.hs +4/−0
- test/Hadolint/Rule/DL3040Spec.hs +5/−0
- test/Hadolint/Rule/DL3041Spec.hs +6/−0
- test/Hadolint/Rule/DL3061Spec.hs +27/−0
- test/Helpers.hs +15/−0
- test/RegressionSpec.hs +12/−6
README.md view
@@ -124,27 +124,34 @@ ```text hadolint - Dockerfile Linter written in Haskell -Usage: hadolint [-v|--version] [--no-fail] [--no-color] [-c|--config FILENAME]- [-V|--verbose] [-f|--format ARG] [DOCKERFILE...]- [--error RULECODE] [--warning RULECODE] [--info RULECODE]- [--style RULECODE] [--ignore RULECODE]+Usage: hadolint [-v|--version] [-c|--config FILENAME] [DOCKERFILE...]+ [--file-path-in-report FILEPATHINREPORT] [--no-fail]+ [--no-color] [-V|--verbose] [-f|--format ARG] [--error RULECODE]+ [--warning RULECODE] [--info RULECODE] [--style RULECODE]+ [--ignore RULECODE] [--trusted-registry REGISTRY (e.g. docker.io)] [--require-label LABELSCHEMA (e.g. maintainer:text)]- [--strict-labels] [-t|--failure-threshold THRESHOLD]+ [--strict-labels] [--disable-ignore-pragma]+ [-t|--failure-threshold THRESHOLD] Lint Dockerfile for errors and best practices Available options: -h,--help Show this help text -v,--version Show version+ -c,--config FILENAME Path to the configuration file+ --file-path-in-report FILEPATHINREPORT+ The file path referenced in the generated report.+ This only applies for the 'checkstyle' format and is+ useful when running Hadolint with Docker to set the+ correct file path. --no-fail Don't exit with a failure status code when any rule is violated --no-color Don't colorize output- -c,--config FILENAME Path to the configuration file -V,--verbose Enables verbose logging of hadolint's output to stderr -f,--format ARG The output format for the results [tty | json | checkstyle | codeclimate | gitlab_codeclimate |- codacy] (default: tty)+ codacy | sonarqube | sarif] (default: tty) --error RULECODE Make the rule `RULECODE` have the level `error` --warning RULECODE Make the rule `RULECODE` have the level `warning` --info RULECODE Make the rule `RULECODE` have the level `info`@@ -160,11 +167,13 @@ format requirement `format` --strict-labels Do not permit labels other than specified in `label-schema`+ --disable-ignore-pragma Disable inline ignore pragmas `# hadolint+ ignore=DLxxxx` -t,--failure-threshold THRESHOLD Exit with failure code only when rules with a- severity above THRESHOLD are violated. Accepted- values: [error | warning | info | style | ignore |- none] (default: info)+ severity equal to or above THRESHOLD are violated.+ Accepted values: [error | warning | info | style |+ ignore | none] (default: info) ``` ## Configure@@ -203,6 +212,7 @@ info: [string] # list of rules style: [string] # list of rules strict-labels: boolean # true | false+disable-ignore-pragma: boolean # true | false trustedRegistries: string | [string] # registry or list of registries ``` @@ -228,6 +238,7 @@ trustedRegistries: - docker.io - my-company.com:5000+ - "*.gcr.io" ``` If you want to override the severity of specific rules, you can do that too:@@ -277,7 +288,7 @@ In addition to config files, Hadolint can be configured with environment variables. ```bash-NO_COLOR=1 # Truthy value e.g. 1, true or yes+NO_COLOR=1 # Set or unset. See https://no-color.org HADOLINT_NOFAIL=1 # Truthy value e.g. 1, true or yes HADOLINT_VERBOSE=1 # Truthy value e.g. 1, true or yes HADOLINT_FORMAT=json # Output format (tty | json | checkstyle | codeclimate | gitlab_codeclimate | codacy | sarif )@@ -288,6 +299,7 @@ HADOLINT_OVERRIDE_STYLE=DL3010,DL3020 # comma separated list of rule codes 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 ``` @@ -417,6 +429,7 @@ | Rule | Default Severity | Description | | :----------------------------------------------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- |+| [DL1001](https://github.com/hadolint/hadolint/wiki/DL1001) | Ignore | Please refrain from using inline ignore pragmas `# hadolint ignore=DLxxxx`. | | [DL3000](https://github.com/hadolint/hadolint/wiki/DL3000) | Error | Use absolute WORKDIR. | | [DL3001](https://github.com/hadolint/hadolint/wiki/DL3001) | Info | For some bash commands it makes no sense running them in a Docker container like ssh, vim, shutdown, service, ps, free, top, kill, mount, ifconfig. | | [DL3002](https://github.com/hadolint/hadolint/wiki/DL3002) | Warning | Last user should not be root. |@@ -471,10 +484,11 @@ | [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) | IgnoreC | `HEALTHCHECK` instruction missing. |+| [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. | | [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. | | [DL4000](https://github.com/hadolint/hadolint/wiki/DL4000) | Error | MAINTAINER is deprecated. | | [DL4001](https://github.com/hadolint/hadolint/wiki/DL4001) | Warning | Either use Wget or Curl but not both. | | [DL4003](https://github.com/hadolint/hadolint/wiki/DL4003) | Warning | Multiple `CMD` instructions found. |@@ -570,6 +584,39 @@ Dockerfile syntax is fully described in the [Dockerfile reference][]. Just take a look at [Syntax.hs][] in the `language-docker` project to see the AST definition.++### Building against custom libraries++Hadolint uses many libraries to do the dirty work. In particular,+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.++ 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+git clone https://github.com/hadolint/language-docker.git+```++ 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+```yaml+[...]+extra-deps:+ - ../language-docker+[...]+```++ 4) Recompile Hadolint and run the tests+```bash+cd /home/user/repos/hadolint+stack test+``` ## Alternatives
hadolint.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hadolint-version: 2.8.0+version: 2.9.0 synopsis: Dockerfile Linter JavaScript API description: A smarter Dockerfile linter that helps you build best practice Docker images. category: Development@@ -50,6 +50,7 @@ Hadolint.Pragma Hadolint.Process Hadolint.Rule+ Hadolint.Rule.DL1001 Hadolint.Rule.DL3000 Hadolint.Rule.DL3001 Hadolint.Rule.DL3002@@ -108,6 +109,7 @@ Hadolint.Rule.DL3058 Hadolint.Rule.DL3059 Hadolint.Rule.DL3060+ Hadolint.Rule.DL3061 Hadolint.Rule.DL4000 Hadolint.Rule.DL4001 Hadolint.Rule.DL4003@@ -133,12 +135,11 @@ StrictData TemplateHaskell TupleSections- PatternSynonyms 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.7.1+ , ShellCheck >=0.8.0 , aeson , base >=4.8 && <5 , bytestring@@ -153,7 +154,7 @@ , foldl , gitrev >=1.3.1 , ilist- , language-docker >=10.3.0 && <11+ , language-docker >=10.4.2 && <11 , megaparsec >=9.0.0 , mtl , network-uri@@ -187,14 +188,13 @@ StrictData TemplateHaskell TupleSections- PatternSynonyms 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 , data-default , hadolint- , language-docker >=10.3.0 && <11+ , language-docker >=10.4.2 && <11 , megaparsec >=9.0.0 , optparse-applicative >=0.14.0 , prettyprinter >=1.7.0@@ -216,6 +216,7 @@ Hadolint.Formatter.SarifSpec Hadolint.Formatter.TTYSpec Hadolint.PragmaSpec+ Hadolint.Rule.DL1001Spec Hadolint.Rule.DL3000Spec Hadolint.Rule.DL3001Spec Hadolint.Rule.DL3002Spec@@ -274,6 +275,7 @@ Hadolint.Rule.DL3058Spec Hadolint.Rule.DL3059Spec Hadolint.Rule.DL3060Spec+ Hadolint.Rule.DL3061Spec Hadolint.Rule.DL4000Spec Hadolint.Rule.DL4001Spec Hadolint.Rule.DL4003Spec@@ -298,14 +300,13 @@ StrictData TemplateHaskell TupleSections- PatternSynonyms ImplicitParams OverloadedLists ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path -flate-dmd-anal build-depends: HUnit >=1.2 , HsYAML- , ShellCheck >=0.7.1+ , ShellCheck >=0.8.0 , aeson , base >=4.8 && <5 , bytestring >=0.10@@ -314,7 +315,7 @@ , foldl , hadolint , hspec >=2.8.3- , language-docker >=10.3.0 && <11+ , language-docker >=10.4.2 && <11 , megaparsec >=9.0.0 , optparse-applicative >=0.14.0 , silently
src/Hadolint/Config/Commandline.hs view
@@ -95,6 +95,7 @@ <*> parseAllowedRegistries <*> parseLabelSchema <*> parseStrictlabels+ <*> parseDisableIgnorePragma <*> parseFailureThreshold -- All optional flags with boolean value must not have a default value. The@@ -226,6 +227,15 @@ ( long "strict-labels" <> help "Do not permit labels other than specified in\ \ `label-schema`"+ )+ )++ parseDisableIgnorePragma =+ optional+ ( flag' True+ ( long "disable-ignore-pragma"+ <> help "Disable inline ignore pragmas \+ \ `# hadolint ignore=DLxxxx`" ) )
src/Hadolint/Config/Configuration.hs view
@@ -36,6 +36,7 @@ allowedRegistries :: Set.Set Registry, labelSchema :: LabelSchema, strictLabels :: Bool,+ disableIgnorePragma :: Bool, failureThreshold :: DLSeverity } deriving (Eq, Show)@@ -55,6 +56,7 @@ mempty mempty False+ False def applyPartialConfiguration ::@@ -73,6 +75,7 @@ (allowedRegistries config <> partialAllowedRegistries partial) (labelSchema config <> partialLabelSchema partial) (fromMaybe (strictLabels config) (partialStrictLabels partial))+ (fromMaybe (disableIgnorePragma config) (partialDisableIgnorePragma partial)) (fromMaybe (failureThreshold config) (partialFailureThreshold partial)) instance Pretty Configuration where@@ -91,6 +94,7 @@ prettyPrintRulelist "ignore" (ignoreRules c), "strict labels:" <+> pretty (strictLabels c), prettyPrintLabelSchema (labelSchema c),+ "disable ignore pragma:" <+> pretty (disableIgnorePragma c), prettyPrintRegistries (allowedRegistries c) ] )@@ -137,14 +141,15 @@ partialAllowedRegistries :: Set.Set Registry, partialLabelSchema :: LabelSchema, partialStrictLabels :: Maybe Bool,+ partialDisableIgnorePragma :: Maybe Bool, partialFailureThreshold :: Maybe DLSeverity } deriving (Eq, Show) instance Semigroup PartialConfiguration where- PartialConfiguration a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13- <> PartialConfiguration b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 =+ PartialConfiguration a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14+ <> PartialConfiguration b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 = PartialConfiguration (b1 <|> a1) (b2 <|> a2)@@ -158,7 +163,8 @@ (a10 <> b10) (a11 <> b11) (b12 <|> a12)- (a13 <> b13)+ (b13 <|> a13)+ (a14 <> b14) instance Monoid PartialConfiguration where mempty =@@ -175,6 +181,7 @@ mempty mempty Nothing+ Nothing mempty instance Default PartialConfiguration where@@ -188,9 +195,10 @@ partialFormat <- m .:? "output-format" override <- m .:? "override" .!= mempty ignored <- m .:? "ignored" .!= mempty- trusted <- m .:? "trusted-registries" .!= mempty+ trusted <- m .:? "trustedRegistries" .!= mempty partialLabelSchema <- m .:? "label-schema" .!= mempty partialStrictLabels <- m .:? "strict-labels" .!= Nothing+ partialDisableIgnorePragma <- m .:? "disable-ignore-pragma" .!= Nothing let partialIgnoreRules = coerce (ignored :: [Text]) partialErrorRules = overrideErrorRules override partialWarningRules = overrideWarningRules override
src/Hadolint/Config/Environment.hs view
@@ -19,7 +19,7 @@ getConfigFromEnvironment = PartialConfiguration <$> maybeTruthy "HADOLINT_NOFAIL"- <*> maybeTruthy "NO_COLOR"+ <*> isSet "NO_COLOR" <*> maybeTruthy "HADOLINT_VERBOSE" <*> getFormat <*> getOverrideList "HADOLINT_OVERRIDE_ERROR"@@ -27,11 +27,19 @@ <*> getOverrideList "HADOLINT_OVERRIDE_INFO" <*> getOverrideList "HADOLINT_OVERRIDE_STYLE" <*> getOverrideList "HADOLINT_IGNORE"- <*> getAllowedSet "HADOLINT_ALLOWED_REGISTRIES"+ <*> getAllowedSet "HADOLINT_TRUSTED_REGISTRIES" <*> getLabelSchema "HADOLINT_REQUIRE_LABELS" <*> maybeTruthy "HADOLINT_STRICT_LABELS"+ <*> maybeTruthy "HADOLINT_DISABLE_IGNORE_PRAGMA" <*> getFailureThreshold ++isSet :: String -> IO (Maybe Bool)+isSet name = do+ e <- lookupEnv name+ case e of+ Just _ -> return $ Just True+ Nothing -> return Nothing maybeTruthy :: String -> IO (Maybe Bool) maybeTruthy name = do
src/Hadolint/Meta.hs view
@@ -4,7 +4,9 @@ ) where -import qualified Development.GitRev+import Data.Version (showVersion)+import Development.GitRev (gitDirty, gitDescribe)+import Paths_hadolint (version) getVersion :: String@@ -13,9 +15,10 @@ getShortVersion :: String getShortVersion = v ++ d where- version = $(Development.GitRev.gitDescribe)- dirty = $(Development.GitRev.gitDirty)- v = case version of- "UNKONWN" -> "-no-git"- _ -> version+ gitVersion = $(gitDescribe)+ cabalVersion = showVersion version+ dirty = $(gitDirty)+ v = case gitVersion of+ "UNKNOWN" -> cabalVersion ++ "-no-git"+ _ -> gitVersion d = if dirty then "-dirty" else ""
src/Hadolint/Pragma.hs view
@@ -1,5 +1,6 @@ module Hadolint.Pragma ( ignored,+ parseIgnorePragma, parseShell ) where@@ -20,13 +21,13 @@ ignored = Foldl.Fold parse mempty id where parse acc InstructionPos {instruction = Comment comment, lineNumber = line} =- case parseComment comment of+ case parseIgnorePragma comment of Just ignores@(_ : _) -> Map.insert (line + 1) (Set.fromList . fmap RuleCode $ ignores) acc _ -> acc parse acc _ = acc -parseComment :: Text -> Maybe [Text]-parseComment =+parseIgnorePragma :: Text -> Maybe [Text]+parseIgnorePragma = Megaparsec.parseMaybe commentParser commentParser :: Megaparsec.Parsec Void Text [Text]
src/Hadolint/Process.hs view
@@ -9,6 +9,7 @@ import qualified Data.Set as Set import qualified Data.Text as Text import qualified Hadolint.Pragma+import qualified Hadolint.Rule.DL1001 import qualified Hadolint.Rule.DL3000 import qualified Hadolint.Rule.DL3001 import qualified Hadolint.Rule.DL3002@@ -67,6 +68,7 @@ import qualified Hadolint.Rule.DL3058 import qualified Hadolint.Rule.DL3059 import qualified Hadolint.Rule.DL3060+import qualified Hadolint.Rule.DL3061 import qualified Hadolint.Rule.DL4000 import qualified Hadolint.Rule.DL4001 import qualified Hadolint.Rule.DL4003@@ -89,10 +91,11 @@ where AnalisisResult {..} = Foldl.fold (analyze config) dockerfile - shouldKeep CheckFailure {line, code} =- Just True /= do- ignoreList <- SMap.lookup line ignored- return $ code `Set.member` ignoreList+ shouldKeep CheckFailure {line, code}+ | disableIgnorePragma config = True+ | otherwise = Just True /= do+ ignoreList <- SMap.lookup line ignored+ return $ code `Set.member` ignoreList analyze :: Configuration ->@@ -119,7 +122,8 @@ failures :: Configuration -> Rule Shell.ParsedShell failures Configuration {allowedRegistries, labelSchema, strictLabels} =- Hadolint.Rule.DL3000.rule+ Hadolint.Rule.DL1001.rule+ <> Hadolint.Rule.DL3000.rule <> Hadolint.Rule.DL3001.rule <> Hadolint.Rule.DL3002.rule <> Hadolint.Rule.DL3003.rule@@ -177,6 +181,7 @@ <> Hadolint.Rule.DL3058.rule labelSchema <> Hadolint.Rule.DL3059.rule <> Hadolint.Rule.DL3060.rule+ <> Hadolint.Rule.DL3061.rule <> Hadolint.Rule.DL4000.rule <> Hadolint.Rule.DL4001.rule <> Hadolint.Rule.DL4003.rule
+ src/Hadolint/Rule/DL1001.hs view
@@ -0,0 +1,19 @@+module Hadolint.Rule.DL1001 (rule) where++import Hadolint.Pragma+import Hadolint.Rule+import Hadolint.Shell (ParsedShell)+import Language.Docker.Syntax++rule :: Rule ParsedShell+rule = simpleRule code severity message check+ where+ code = "DL1001"+ severity = DLIgnoreC+ message = "Please refrain from using inline igore pragmas \+ \ `# hadolint ignore=DLxxxx`."+ check (Comment com) =+ case parseIgnorePragma com of+ Just _ -> False+ _ -> True+ check _ = True
src/Hadolint/Rule/DL3007.hs view
@@ -11,6 +11,7 @@ message = "Using latest is prone to errors if the image will ever update. Pin the version explicitly \ \to a release tag"+ check (From BaseImage {tag = Just _, digest = Just _}) = True check (From BaseImage {tag = Just t}) = t /= "latest" check _ = True {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3021.hs view
@@ -15,6 +15,8 @@ | length sources > 1 = endsWithSlash t | otherwise = True check _ = True-- endsWithSlash (TargetPath t) = not (Text.null t) && Text.last t == '/' {-# INLINEABLE rule #-}++endsWithSlash :: TargetPath -> Bool+endsWithSlash (TargetPath t) =+ not (Text.null t) && (Text.last . dropQuotes) t == '/'
src/Hadolint/Rule/DL3026.hs view
@@ -1,6 +1,7 @@ module Hadolint.Rule.DL3026 (rule) where import qualified Data.Set as Set+import Data.Text (Text, pack, drop, dropEnd, isSuffixOf, isPrefixOf) import Hadolint.Rule import Language.Docker.Syntax @@ -21,9 +22,20 @@ doCheck st img = Set.member (toImageAlias img) st || Set.null allowed || isAllowed img toImageAlias = Just . ImageAlias . imageName- isAllowed Image {registryName = Just registry} = Set.member registry allowed+ isAllowed Image {registryName = Just registry} = isRegistryAllowed (unRegistry registry) isAllowed Image {registryName = Nothing, imageName} = imageName == "scratch"- || Set.member "docker.io" allowed- || Set.member "hub.docker.com" allowed+ || isRegistryAllowed "docker.io"+ || isRegistryAllowed "hub.docker.com"++ isRegistryAllowed registry = any (\p -> matchRegistry (unRegistry p) registry) allowed++ matchRegistry :: Text -> Text -> Bool+ matchRegistry allow registry | allow == star = True+ | isPrefixOf star allow = isSuffixOf (Data.Text.drop 1 allow) registry+ | isSuffixOf star allow = isPrefixOf (Data.Text.dropEnd 1 allow) registry+ | otherwise = registry == allow+ where+ star = pack "*"+ {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3029.hs view
@@ -10,6 +10,6 @@ severity = DLWarningC message = "Do not use --platform flag with FROM" - check (From BaseImage {platform = Just p}) = p == ""+ check (From BaseImage {platform = Just p}) = p == "$BUILDPLATFORM" check _ = True {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3038.hs view
@@ -15,6 +15,7 @@ check _ = True forgotDnfYesOption cmd = isDnfInstall cmd && not (hasYesOption cmd)- isDnfInstall = Shell.cmdHasArgs "dnf" ["install", "groupinstall", "localinstall"]+ isDnfInstall = Shell.cmdsHaveArgs dnfCmds ["install", "groupinstall", "localinstall"] hasYesOption = Shell.hasAnyFlag ["y", "assumeyes"]+ dnfCmds = ["dnf", "microdnf"] {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3040.hs view
@@ -11,13 +11,16 @@ severity = DLWarningC message = "`dnf clean all` missing after dnf command." - check (Run (RunArgs args _)) =- foldArguments (Shell.noCommands dnfInstall) args- || ( foldArguments (Shell.anyCommands dnfInstall) args- && foldArguments (Shell.anyCommands dnfClean) args- )+ check (Run (RunArgs args _)) = all (checkMissingClean args) dnfCmds check _ = True - dnfInstall = Shell.cmdHasArgs "dnf" ["install"]- dnfClean = Shell.cmdHasArgs "dnf" ["clean", "all"]+ checkMissingClean args cmdName =+ foldArguments (Shell.noCommands $ dnfInstall cmdName) args+ || ( foldArguments (Shell.anyCommands $ dnfInstall cmdName) args+ && foldArguments (Shell.anyCommands $ dnfClean cmdName) args+ )++ dnfInstall cmdName = Shell.cmdHasArgs cmdName ["install"]+ dnfClean cmdName = Shell.cmdHasArgs cmdName ["clean", "all"]+ dnfCmds = ["dnf", "microdnf"] {-# INLINEABLE rule #-}
src/Hadolint/Rule/DL3041.hs view
@@ -18,11 +18,14 @@ check _ = True {-# INLINEABLE rule #-} +dnfCmds :: [Text.Text]+dnfCmds = ["dnf", "microdnf"]+ dnfPackages :: Shell.ParsedShell -> [Text.Text] dnfPackages args = [ arg | cmd <- Shell.presentCommands args,- not (Shell.cmdHasArgs "dnf" ["module"] cmd),+ not (Shell.cmdsHaveArgs dnfCmds ["module"] cmd), arg <- installFilter cmd ] @@ -34,7 +37,7 @@ dnfModules args = [ arg | cmd <- Shell.presentCommands args,- Shell.cmdHasArgs "dnf" ["module"] cmd,+ Shell.cmdsHaveArgs dnfCmds ["module"] cmd, arg <- installFilter cmd ] @@ -44,7 +47,7 @@ installFilter :: Shell.Command -> [Text.Text] installFilter cmd = [ arg- | Shell.cmdHasArgs "dnf" ["install"] cmd,+ | Shell.cmdsHaveArgs dnfCmds ["install"] cmd, arg <- Shell.getArgsNoFlags cmd, arg /= "install", arg /= "module"
+ src/Hadolint/Rule/DL3061.hs view
@@ -0,0 +1,21 @@+module Hadolint.Rule.DL3061 (rule) where++import Hadolint.Rule+import Language.Docker.Syntax+++rule :: Rule args+rule = customRule check (emptyState False)+ where+ code = "DL3061"+ severity = DLErrorC+ message = "Invalid instruction order. Dockerfile must begin with `FROM`,\+ \ `ARG` or comment."++ check _ st (From _) = st |> replaceWith True+ check _ st (Comment _) = st+ check _ st (Arg _ _) = st+ check line st _+ | state st = st+ | otherwise = st |> addFail CheckFailure {..}+{-# INLINEABLE rule #-}
src/Hadolint/Shell.hs view
@@ -165,6 +165,11 @@ | expectedName /= n = False | otherwise = not $ null [arg | CmdPart arg _ <- args, arg `elem` expectedArgs] +cmdsHaveArgs :: [Text.Text] -> [Text.Text] -> Command -> Bool+cmdsHaveArgs expectedNames expectedArgs (Command n args _)+ | n `notElem` expectedNames = False+ | otherwise = not $ null [arg | CmdPart arg _ <- args, arg `elem` expectedArgs]+ cmdHasPrefixArg :: Text.Text -> Text.Text -> Command -> Bool cmdHasPrefixArg expectedName expectedArg (Command n args _) | expectedName /= n = False
test/Hadolint/Config/CommandlineSpec.hs view
@@ -300,6 +300,18 @@ mempty { partialStrictLabels = Just True } ) + describe "parse disable ignore pragma" $ do+ it "parse --disable-ignore-pragma" $ do+ checkCommandline+ ["--disable-ignore-pragma"]+ ( CommandlineConfig+ False+ Nothing+ []+ Nothing+ mempty { partialDisableIgnorePragma = Just True }+ )+ describe "parse failure thresholds" $ do it "parse -t warning" $ do checkCommandline ["-t", "warning"] $ CommandlineConfig
test/Hadolint/Config/ConfigfileSpec.hs view
@@ -117,7 +117,7 @@ { partialIgnoreRules = ["DL3020", "DL3040", "SC1020"] } it "parse trusted registries" $ do- let yaml = [ "trusted-registries:",+ let yaml = [ "trustedRegistries:", " - foobar.com", " - barfoo.com" ]@@ -149,6 +149,16 @@ let yaml = [ "strict-labels: false" ] conf = parseYaml yaml conf `shouldBe` Right mempty { partialStrictLabels = Just False }++ it "parse disable-ignore-pragma: true" $ do+ let yaml = [ "disable-ignore-pragma: true" ]+ conf = parseYaml yaml+ conf `shouldBe` Right mempty { partialDisableIgnorePragma = Just True }++ it "parse disable-ignore-pragma: false" $ do+ let yaml = [ "disable-ignore-pragma: false" ]+ conf = parseYaml yaml+ conf `shouldBe` Right mempty { partialDisableIgnorePragma = Just False } it "parse `failure-threshold: warning`" $ do let yaml = ["failure-threshold: warning"]
test/Hadolint/Config/ConfigurationSpec.hs view
@@ -1,219 +1,43 @@ module Hadolint.Config.ConfigurationSpec where import Data.Default-import qualified Data.Map as Map-import qualified Data.Set as Set import Hadolint import Test.Hspec spec :: SpecWith () spec = do describe "Configuration" $ do- it "default configuration" $ do- def- `shouldBe` Configuration- False- False- False- TTY- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC- it "override default configuration with empty config" $ do applyPartialConfiguration def mempty- `shouldBe` Configuration- False- False- False- TTY- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC+ `shouldBe` def it "override default with specific configuration: no-fail" $ do- let config =- PartialConfiguration- (Just True)- Nothing- Nothing- mempty- mempty- mempty- mempty- mempty- mempty- mempty- mempty- Nothing- mempty+ let config = def { partialNoFail = Just True } applyPartialConfiguration def config- `shouldBe` Configuration- True- False- False- TTY- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC+ `shouldBe` def { noFail = True } it "override default with specific configuration: no-color" $ do- let config =- PartialConfiguration- Nothing- (Just True)- Nothing- mempty- mempty- mempty- mempty- mempty- mempty- mempty- mempty- Nothing- mempty+ let config = def { partialNoColor = Just True } applyPartialConfiguration def config- `shouldBe` Configuration- False- True- False- TTY- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC+ `shouldBe` def { noColor = True } it "empty should not override: no-color" $ do- let config =- PartialConfiguration- Nothing- (Just True)- Nothing- mempty- mempty- mempty- mempty- mempty- mempty- mempty- mempty- Nothing- mempty- config2 =- PartialConfiguration- Nothing- Nothing- Nothing- mempty- mempty- mempty- mempty- mempty- mempty- mempty- mempty- Nothing- mempty+ let config = def { partialNoColor = Just True }+ config2 = def applyPartialConfiguration def (config <> config2)- `shouldBe` Configuration- False- True- False- TTY- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC+ `shouldBe` def { noColor = True } it "override default with specific configuration: verbose" $ do- let config =- PartialConfiguration- Nothing- Nothing- (Just True)- mempty- mempty- mempty- mempty- mempty- mempty- mempty- mempty- Nothing- mempty+ let config = def { partialVerbose = Just True } applyPartialConfiguration def config- `shouldBe` Configuration- False- False- True- TTY- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC+ `shouldBe` def { verbose = True } it "override default with specific configuration: output-format json" $ do- let config =- PartialConfiguration- Nothing- Nothing- Nothing- (Just Json)- mempty- mempty- mempty- mempty- mempty- mempty- mempty- Nothing- mempty+ let config = def { partialFormat = Just Json } applyPartialConfiguration def config- `shouldBe` Configuration- False- False- False- Json- mempty- mempty- mempty- mempty- mempty- mempty- mempty- False- DLInfoC+ `shouldBe` def { format = Json }++ it "override default with specific configuration: disable ignore pragma" $ do+ let config = def { partialDisableIgnorePragma = Just True }+ applyPartialConfiguration def config+ `shouldBe` def { disableIgnorePragma = True }
test/Hadolint/Config/EnvironmentSpec.hs view
@@ -1,7 +1,9 @@ module Hadolint.Config.EnvironmentSpec (spec) where import Hadolint-import System.Environment+import System.Environment hiding (setEnv)+import System.Environment.Blank (setEnv)+import System.Info import Test.Hspec import qualified Data.Map as Map import qualified Data.Set as Set@@ -33,8 +35,22 @@ withJustEnv "NO_COLOR" "n" $ do it "parse NO_COLOR=n" $ do conf <- getConfigFromEnvironment- conf `shouldBe` mempty { partialNoColor = Just False }+ 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+ -- 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+ it "parse NO_COLOR set to empty string" $ do+ conf <- getConfigFromEnvironment+ conf `shouldBe` mempty { partialNoColor = expectedValueVarEmptyString }++ withoutAll $ do+ it "parse NO_COLOR unset" $ do+ conf <- getConfigFromEnvironment+ conf `shouldBe` mempty { partialNoColor = Nothing }+ withJustEnv "HADOLINT_VERBOSE" "on" $ do it "parse HADOLINT_VERBOSE=on" $ do conf <- getConfigFromEnvironment@@ -105,16 +121,16 @@ conf <- getConfigFromEnvironment conf `shouldBe` mempty { partialIgnoreRules = ["DL3010", "DL3011"] } - withJustEnv "HADOLINT_ALLOWED_REGISTRIES" "foobar.com" $ do- it "parse HADOLINT_ALLOWED_REGISTRIES=foobar.com" $ do+ withJustEnv "HADOLINT_TRUSTED_REGISTRIES" "foobar.com" $ do+ it "parse HADOLINT_TRUSTED_REGISTRIES=foobar.com" $ do conf <- getConfigFromEnvironment conf `shouldBe` mempty { partialAllowedRegistries = Set.fromList ["foobar.com"] } - withJustEnv "HADOLINT_ALLOWED_REGISTRIES" "foobar.com,barfoo.com" $ do- it "parse HADOLINT_ALLOWED_REGISTIRES=foobar.com,barfoo.com" $ do+ withJustEnv "HADOLINT_TRUSTED_REGISTRIES" "foobar.com,barfoo.com" $ do+ it "parse HADOLINT_TRUSTED_REGISTRIES=foobar.com,barfoo.com" $ do conf <- getConfigFromEnvironment conf `shouldBe` mempty { partialAllowedRegistries =@@ -145,6 +161,16 @@ conf <- getConfigFromEnvironment conf `shouldBe` mempty { partialStrictLabels = Just False } + withJustEnv "HADOLINT_DISABLE_IGNORE_PRAGMA" "yes" $ do+ it "parse HADOLINT_DISABLE_IGNORE_PRAGMA=yes" $ do+ conf <- getConfigFromEnvironment+ conf `shouldBe` mempty { partialDisableIgnorePragma = Just True }++ withJustEnv "HADOLINT_DISABLE_IGNORE_PRAGMA" "false" $ do+ it "parse HADOLINT_DISABLE_IGNORE_PRAGMA=false" $ do+ conf <- getConfigFromEnvironment+ conf `shouldBe` mempty { partialDisableIgnorePragma = Just False }+ withJustEnv "HADOLINT_FAILURE_THRESHOLD" "error" $ do it "parse HADOLINT_FAILURE_THRESHOLD=error" $ do conf <- getConfigFromEnvironment@@ -167,7 +193,7 @@ setJustEnv :: String -> String -> IO () setJustEnv name value = do unsetAll- setEnv name value+ setEnv name value False unsetAll :: IO () unsetAll = do@@ -180,7 +206,16 @@ unsetEnv "HADOLINT_OVERRIDE_INFO" unsetEnv "HADOLINT_OVERRIDE_STYLE" unsetEnv "HADOLINT_IGNORE"- unsetEnv "HADOLINT_ALLOWED_REGISTRIES"+ unsetEnv "HADOLINT_TRUSTED_REGISTRIES" unsetEnv "HADOLINT_REQUIRE_LABELS" unsetEnv "HADOLINT_STRICT_LABELS" unsetEnv "HADOLINT_FAILURE_THRESHOLD"++-- 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+-- empty string. In order to generate the correct expected value one must check+-- the operating system type.+expectedValueVarEmptyString :: Maybe Bool+expectedValueVarEmptyString+ | os == "mingw32" = Nothing+ | otherwise = Just True
test/Hadolint/Formatter/SarifSpec.hs view
@@ -1,11 +1,10 @@ module Hadolint.Formatter.SarifSpec (spec) where +import Data.Aeson import Helpers import Hadolint ( CheckFailure (..), DLSeverity (..),- Result(..),- printResults, OutputFormat (..), getShortVersion, )@@ -15,18 +14,200 @@ spec :: SpecWith () spec = do let ?noColor = True+ let version = String "2.1.0"+ schema = String "http://json.schemastore.org/sarif-2.1.0"+ defSrcLang = String "dockerfile"+ tool =+ Object+ [ "driver" .=+ Object+ [ "name" .= String "Hadolint",+ "fullName" .= String "Haskell Dockerfile Linter",+ "downloadUri" .=+ String "https://github.com/hadolint/hadolint",+ "version" .= getShortVersion,+ "shortDescription" .=+ Object+ [ "text" .= String "Dockerfile linter, validate inline\+ \ bash, written in Haskell"+ ]+ ]+ ] describe "Formatter: Sarif" $ do it "print empty results" $ do let checkFails = []- expectation = "{\"runs\":[{\"defaultSourceLanguage\":\"dockerfi\- \le\",\"results\":[],\"tool\":{\"driver\":{\"full\- \Name\":\"Haskell Dockerfile Linter\",\"downloadU\- \ri\":\"https://github.com/hadolint/hadolint\",\"\- \shortDescription\":{\"text\":\"Dockerfile linter\- \, validate inline bash, written in Haskell\"},\"\- \name\":\"Hadolint\",\"version\":\""- ++ getShortVersion- ++ "\"}}}],\"version\":\"2.1.0\",\"$schema\- \\":\"http://json.schemastore.org/sarif-2.1.0\"}"- assertFormatter Sarif checkFails expectation+ expectation =+ Object+ [ "version" .= version,+ "$schema" .= schema,+ "runs" .=+ Array+ [ Object+ [ "tool" .= tool,+ "results" .= Array [],+ "defaultSourceLanguage" .= defSrcLang+ ]+ ]+ ]+ assertFormatterJson Sarif checkFails expectation++ it "print one failed rule" $ do+ let checkFails =+ [ CheckFailure+ { code = "DL2001",+ severity = DLWarningC,+ message = "test",+ line = 1+ }+ ]+ expectation =+ Object+ [ "version" .= version,+ "$schema" .= schema,+ "runs" .=+ Array+ [ Object+ [ "tool" .= tool,+ "results" .=+ Array+ [ Object+ [ "level" .= String "warning",+ "locations" .=+ Array+ [ Object+ [ "physicalLocation" .=+ Object+ [ "artifactLocation" .=+ Object+ [ "uri" .=+ String "<string>"+ ],+ "region" .=+ Object+ [ "startLine" .=+ Number 1.0,+ "endLine" .=+ Number 1.0,+ "startColumn" .=+ Number 1.0,+ "endColumn" .=+ Number 1.0,+ "sourceLanguage" .=+ String "dockerfile"+ ]+ ]+ ]+ ],+ "message" .=+ Object+ [ "text" .= String "test"+ ],+ "ruleId" .= String "DL2001"+ ]+ ],+ "defaultSourceLanguage" .= defSrcLang+ ]+ ]+ ]+ assertFormatterJson Sarif checkFails expectation++ it "print multiple failed rules" $ do+ let checkFails =+ [ CheckFailure+ { code = "DL2001",+ severity = DLWarningC,+ message = "test",+ line = 1+ },+ CheckFailure+ { code = "DL2003",+ severity = DLInfoC,+ message = "test 2",+ line = 3+ }+ ]+ expectation =+ Object+ [ "version" .= version,+ "$schema" .= schema,+ "runs" .=+ Array+ [ Object+ [ "tool" .= tool,+ "results" .=+ Array+ [ Object+ [ "level" .= String "warning",+ "locations" .=+ Array+ [ Object+ [ "physicalLocation" .=+ Object+ [ "artifactLocation" .=+ Object+ [ "uri" .=+ String "<string>"+ ],+ "region" .=+ Object+ [ "startLine" .=+ Number 1.0,+ "endLine" .=+ Number 1.0,+ "startColumn" .=+ Number 1.0,+ "endColumn" .=+ Number 1.0,+ "sourceLanguage" .=+ String "dockerfile"+ ]+ ]+ ]+ ],+ "message" .=+ Object+ [ "text" .= String "test"+ ],+ "ruleId" .= String "DL2001"+ ],+ Object+ [ "level" .= String "note",+ "locations" .=+ Array+ [ Object+ [ "physicalLocation" .=+ Object+ [ "artifactLocation" .=+ Object+ [ "uri" .=+ String "<string>"+ ],+ "region" .=+ Object+ [ "startLine" .=+ Number 3.0,+ "endLine" .=+ Number 3.0,+ "startColumn" .=+ Number 1.0,+ "endColumn" .=+ Number 1.0,+ "sourceLanguage" .=+ String "dockerfile"+ ]+ ]+ ]+ ],+ "message" .=+ Object+ [ "text" .= String "test 2"+ ],+ "ruleId" .= String "DL2003"+ ]+ ],+ "defaultSourceLanguage" .= defSrcLang+ ]+ ]+ ]+ assertFormatterJson Sarif checkFails expectation
+ test/Hadolint/Rule/DL1001Spec.hs view
@@ -0,0 +1,41 @@+module Hadolint.Rule.DL1001Spec (spec) where++import Data.Default+import Data.Text as Text+import Helpers+import Test.Hspec+++spec :: SpecWith ()+spec = do+ let ?config = def++ describe "DL1001 - Please don't use inline ignore pragma." $ do+ it "catches inline ignore pragma" $ do+ let file =+ [ "# hadolint ignore=DL3003",+ "RUN foo bar"+ ]+ in do+ ruleCatches "DL1001" $ Text.unlines file+ it "does not catch other pragma" $ do+ let file =+ [ "# hadolint shell=powershell",+ "RUN foo bar"+ ]+ in do+ ruleCatchesNot "DL1001" $ Text.unlines file+ it "does not catch other comment" $ do+ let file =+ [ "# foobar",+ "RUN foo bar"+ ]+ in do+ ruleCatchesNot "DL1001" $ Text.unlines file+ it "does not catch when inline ignore pragma is absent" $ do+ let file =+ [ "FROM debian",+ "RUN foo bar"+ ]+ in do+ ruleCatchesNot "DL1001" $ Text.unlines file
test/Hadolint/Rule/DL3007Spec.hs view
@@ -20,5 +20,10 @@ "DL3007" "FROM hub.docker.io/debian@sha256:\ \7959ed6f7e35f8b1aaa06d1d8259d4ee25aa85a086d5c125480c333183f9deeb"+ it "explicit tagged and SHA" $+ ruleCatchesNot+ "DL3007"+ "FROM hub.docker.io/debian:latest@sha256:\+ \7959ed6f7e35f8b1aaa06d1d8259d4ee25aa85a086d5c125480c333183f9deeb" it "explicit tagged with name" $ ruleCatchesNot "DL3007" "FROM debian:jessie AS builder"
test/Hadolint/Rule/DL3021Spec.hs view
@@ -13,3 +13,5 @@ it "no warn on 2 args" $ ruleCatchesNot "DL3021" "COPY foo bar" it "warn on 3 args" $ ruleCatches "DL3021" "COPY foo bar baz" it "no warn on 3 args" $ ruleCatchesNot "DL3021" "COPY foo bar baz/"+ it "warn on 3 args with quotes" $ ruleCatches "DL3021" "COPY foo bar \"baz\""+ it "no warn on 3 args with quotes" $ ruleCatchesNot "DL3021" "COPY foo bar \"baz/\""
test/Hadolint/Rule/DL3025Spec.hs view
@@ -36,3 +36,13 @@ "CMD [ \"foo\", \"bar\" ]" ] in ruleCatchesNot "DL3025" $ Text.unlines dockerFile++ -- regression: deal with broken long strings in exec format+ it "don't warn on CMD JSON notation with broken long strings" $+ let dockerFile =+ [ "CMD [ \"/bin/sh\", \"-c\", \\",+ " \"echo foo && \\",+ " echo bar\" \\",+ " ]"+ ]+ in ruleCatchesNot "DL3025" $ Text.unlines dockerFile
test/Hadolint/Rule/DL3026Spec.hs view
@@ -60,3 +60,29 @@ let ?config = def { allowedRegistries = ["random.com"] } ruleCatchesNot "DL3026" $ Text.unlines dockerFile++ it "warn on non-allowed wildcard registry" $ do+ let dockerFile =+ [ "FROM x.com/debian"+ ]+ let ?config = def { allowedRegistries = ["*.random.com"] }++ ruleCatches "DL3026" $ Text.unlines dockerFile++ it "does not warn on allowed wildcard registries" $ do+ let dockerFile =+ [ "FROM foo.random.com/debian"+ ]+ let ?config = def { allowedRegistries = ["x.com", "*.random.com"] }++ ruleCatchesNot "DL3026" $ Text.unlines dockerFile++ it "does not warn on * registry" $ do+ let dockerFile =+ [ "FROM ubuntu:18.04 AS builder1",+ "FROM zemanlx/ubuntu:18.04 AS builder2",+ "FROM docker.io/zemanlx/ubuntu:18.04 AS builder3"+ ]+ let ?config = def { allowedRegistries = ["*"] }++ ruleCatchesNot "DL3026" $ Text.unlines dockerFile
test/Hadolint/Rule/DL3029Spec.hs view
@@ -12,3 +12,4 @@ describe "DL3029 - Do not use --platform flag with FROM." $ do it "explicit platform flag" $ ruleCatches "DL3029" "FROM --platform=linux debian:jessie" it "no platform flag" $ ruleCatchesNot "DL3029" "FROM debian:jessie"+ it "allow platform $BUILDPLATFORM flag" $ ruleCatchesNot "DL3029" "FROM --platform=$BUILDPLATFORM debian:jessie"
test/Hadolint/Rule/DL3038Spec.hs view
@@ -12,9 +12,13 @@ describe "DL3038 - Use the `-y` switch to avoid manual input `dnf install -y <package>`" $ do it "not ok without dnf non-interactive flag" $ do ruleCatches "DL3038" "RUN dnf install httpd-2.4.24 && dnf clean all"+ ruleCatches "DL3038" "RUN microdnf install httpd-2.4.24 && microdnf clean all" onBuildRuleCatches "DL3038" "RUN dnf install httpd-2.4.24 && dnf clean all"+ onBuildRuleCatches "DL3038" "RUN microdnf install httpd-2.4.24 && microdnf clean all" it "ok with dnf non-interactive flag" $ do ruleCatchesNot "DL3038" "RUN dnf install -y httpd-2.4.24 && dnf clean all"+ ruleCatchesNot "DL3038" "RUN microdnf install -y httpd-2.4.24 && microdnf clean all" ruleCatchesNot "DL3038" "RUN notdnf install httpd" onBuildRuleCatchesNot "DL3038" "RUN dnf install -y httpd-2.4.24 && dnf clean all"+ onBuildRuleCatchesNot "DL3038" "RUN microdnf install -y httpd-2.4.24 && microdnf clean all" onBuildRuleCatchesNot "DL3038" "RUN notdnf install httpd"
test/Hadolint/Rule/DL3040Spec.hs view
@@ -12,9 +12,14 @@ describe "DL3040 - `dnf clean all` missing after dnf command." $ do it "no ok without dnf clean all" $ do ruleCatches "DL3040" "RUN dnf install -y mariadb-10.4"+ ruleCatches "DL3040" "RUN microdnf install -y mariadb-10.4" onBuildRuleCatches "DL3040" "RUN dnf install -y mariadb-10.4"+ onBuildRuleCatches "DL3040" "RUN dnf install -y mariadb-10.4 && microdnf clean all"+ onBuildRuleCatches "DL3040" "RUN microdnf install -y mariadb-10.4" it "ok with dnf clean all" $ do ruleCatchesNot "DL3040" "RUN dnf install -y mariadb-10.4 && dnf clean all"+ ruleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && microdnf clean all" ruleCatchesNot "DL3040" "RUN notdnf install mariadb" onBuildRuleCatchesNot "DL3040" "RUN dnf install -y mariadb-10.4 && dnf clean all"+ onBuildRuleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && microdnf clean all" onBuildRuleCatchesNot "DL3040" "RUN notdnf install mariadb"
test/Hadolint/Rule/DL3041Spec.hs view
@@ -12,17 +12,23 @@ describe "DL3041 - Specify version with `dnf install -y <package>-<version>`" $ do it "not ok without dnf version pinning" $ do 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 "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" ruleCatchesNot "DL3041" "RUN notdnf install tomcat" 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 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" it "ok with dnf version pinning - modules" $ do ruleCatchesNot "DL3041" "RUN dnf module install -y tomcat:9 && dnf clean all"+ ruleCatchesNot "DL3041" "RUN microdnf module install -y tomcat:9 && microdnf clean all" ruleCatchesNot "DL3041" "RUN notdnf module install tomcat" onBuildRuleCatchesNot "DL3041" "RUN dnf module install -y tomcat:9 && dnf clean all"+ onBuildRuleCatchesNot "DL3041" "RUN microdnf module install -y tomcat:9 && microdnf clean all" onBuildRuleCatchesNot "DL3041" "RUN notdnf module install tomcat"
+ test/Hadolint/Rule/DL3061Spec.hs view
@@ -0,0 +1,27 @@+module Hadolint.Rule.DL3061Spec (spec) where++import Data.Default+import Helpers+import Test.Hspec+++spec :: SpecWith ()+spec = do+ let ?config = def++ describe "DL3061 - Invalid instruction order. Dockerfile must begin with\+ \ `FROM`, `ARG` or comment." $ do+ it "warn: label before from" $ do+ ruleCatches "DL3061" "LABEL foo=bar\nFROM foo"+ onBuildRuleCatches "DL3061" "LABEL foo=bar\nFROM foo"++ it "don't warn: from before label" $ do+ ruleCatchesNot "DL3061" "FROM foo\nLABEL foo=bar"+ onBuildRuleCatchesNot "DL3061" "FROM foo\nLABEL foo=bar"++ it "don't warn: ARG then FROM then LABEL" $ do+ ruleCatchesNot "DL3061" "ARG A=B\nFROM foo\nLABEL foo=bar"+ onBuildRuleCatchesNot "DL3061" "ARG A=B\nFROM foo\nLABEL foo=bar"++ it "don't warn: FROM then ARG then RUN" $ do+ ruleCatchesNot "DL3061" "FROM foo\nARG A=B\nRUN echo bla"
test/Helpers.hs view
@@ -1,6 +1,8 @@ module Helpers where import Control.Monad (unless, when)+import qualified Data.ByteString.Lazy.Char8 as BSC+import Data.Aeson hiding (Result) import Hadolint (Configuration (..), OutputFormat (..), printResults) import Hadolint.Formatter.Format (Result (..)) import Hadolint.Formatter.TTY (formatCheck)@@ -136,3 +138,16 @@ (cap, _) <- capture (printResults formatter ?noColor (Just "<string>") results) cap `shouldBe` expectation++assertFormatterJson+ :: (HasCallStack, ?noColor :: Bool) =>+ OutputFormat ->+ [CheckFailure] ->+ Value ->+ Assertion+assertFormatterJson formatter failures expectation = do+ let results =+ NonEmpty.fromList [ Result "<string>" mempty (Seq.fromList failures) ]+ (cap, _) <- capture+ (printResults formatter ?noColor (Just "<string>") results)+ decode (BSC.pack cap) `shouldBe` Just expectation
test/RegressionSpec.hs view
@@ -6,9 +6,11 @@ import Test.HUnit hiding (Label) import Test.Hspec + spec :: SpecWith () spec = do let ?config = def -- default implicit parameter running the checkers+ describe "Regression Tests" $ do it "Comments with backslashes at the end are just comments" $ let dockerFile =@@ -21,12 +23,16 @@ "RUN echo \"kaka\" | sed 's/a/o/g' >> /root/afile" ] in ruleCatches "DL4006" $ Text.unlines dockerFile+ it "`ARG` can correctly unset variables" $ let dockerFile =- [ "ARG A_WITHOUT_EQ",- "ARG A_WITH_EQ=",- "RUN echo bla"- ]+ Text.unlines+ [ "FROM alpine:3", -- to satisfy DL3061+ "ARG A_WITHOUT_EQ",+ "ARG A_WITH_EQ=",+ "HEALTHCHECK NONE", -- to satisfy DL3057, even though it is ignored by default+ "RUN echo bla"+ ] in assertChecks- (Text.unlines dockerFile)- (assertBool "No Warnings or Errors should be triggered" . null)+ dockerFile+ (assertBool "No Warnings or Errors should be triggered," . null)