hadolint 1.17.3 → 1.17.6
raw patch · 8 files changed
+118/−28 lines, 8 filesdep ~ShellCheckdep ~language-docker
Dependency ranges changed: ShellCheck, language-docker
Files
- README.md +16/−4
- hadolint.cabal +13/−8
- src/Hadolint/Config.hs +2/−1
- src/Hadolint/Formatter/Format.hs +3/−3
- src/Hadolint/Rules.hs +31/−8
- src/Hadolint/Shell.hs +2/−1
- test/ConfigSpec.hs +1/−1
- test/Spec.hs +50/−2
README.md view
@@ -59,11 +59,12 @@ docker pull hadolint/hadolint ``` -If you need a Docker container with shell access, use the Debian variant of the-Docker image:+If you need a Docker container with shell access, use the Debian or Alpine+variants of the Docker image: ```bash docker pull hadolint/hadolint:latest-debian+docker pull hadolint/hadolint:latest-alpine ``` You can also build `hadolint` locally. You need [Haskell][] and the [stack][]@@ -142,6 +143,10 @@ or to your editor to lint your `Dockerfile` as you write it. See our [Integration][] docs. +- [Code Review Platform Integrations][]+- [Continuous Integrations][]+- [Editor Integrations][]+ ## Rules An incomplete list of implemented rules. Click on the error code to get more@@ -210,7 +215,7 @@ | [SC1086](https://github.com/koalaman/shellcheck/wiki/SC1086) | Don't use `$` on the iterator name in for loops. | | [SC1087](https://github.com/koalaman/shellcheck/wiki/SC1087) | Braces are required when expanding arrays, as in `${array[idx]}`. | | [SC1095](https://github.com/koalaman/shellcheck/wiki/SC1095) | You need a space or linefeed between the function name and body. |-| [SC1097](https://github.com/koalaman/shellcheck/wiki/SC1097) | Unexpected `==`. For assignment, use `=`. For comparison, use `[/[[`. |+| [SC1097](https://github.com/koalaman/shellcheck/wiki/SC1097) | Unexpected `==`. For assignment, use `=`. For comparison, use `[ .. ]` or `[[ .. ]]`. | | [SC1098](https://github.com/koalaman/shellcheck/wiki/SC1098) | Quote/escape special characters when using `eval`, e.g. `eval "a=(b)"`. | | [SC1099](https://github.com/koalaman/shellcheck/wiki/SC1099) | You need a space before the `#`. | | [SC2002](https://github.com/koalaman/shellcheck/wiki/SC2002) | Useless cat. Consider <code>cmd < file | ..</code> or <code>cmd file | ..</code> instead. |@@ -252,8 +257,12 @@ ```bash # start the repl stack repl+# overload strings to be able to use Text+:set -XOverloadedStrings+# import parser library+import Language.Docker # parse instruction and look at AST representation-parseString "FROM debian:jessie"+parseText "FROM debian:jessie" ``` ### Tests@@ -296,6 +305,9 @@ [haskell]: https://www.haskell.org/platform/ [stack]: http://docs.haskellstack.org/en/stable/install_and_upgrade.html [integration]: docs/INTEGRATION.md+[code review platform integrations]: docs/INTEGRATION.md#code-review+[continuous integrations]: docs/INTEGRATION.md#continuous-integration+[editor integrations]: docs/INTEGRATION.md#editors [create an issue]: https://github.com/hadolint/hadolint/issues/new [dockerfile reference]: http://docs.docker.com/engine/reference/builder/ [syntax.hs]: https://www.stackage.org/haddock/nightly-2018-01-07/language-docker-2.0.1/Language-Docker-Syntax.html
hadolint.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 1f42c246369026b5b251c024286a6e3e3a9b7d1af38cefdeffe03b0cadad4473+-- hash: d5c1e516f33de671a88bcd54c65c02b7b9a6f1dcb29f0dab9e7f1d38ba37c336 name: hadolint-version: 1.17.3+version: 1.17.6 synopsis: Dockerfile Linter JavaScript API description: A smarter Dockerfile linter that helps you build best practice Docker images. category: Development@@ -25,6 +25,11 @@ type: git location: git@github.com:hadolint/hadolint.git +flag static+ description: Use static linking for the hadolint executable+ manual: True+ default: False+ library exposed-modules: Hadolint@@ -45,14 +50,14 @@ ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path build-depends: HsYAML- , ShellCheck >=0.7.0+ , ShellCheck >=0.7.1 , aeson , base >=4.8 && <5 , bytestring , containers , directory >=1.3.0 , filepath- , language-docker >=8.0.2 && <9+ , language-docker >=8.1.0 && <9 , megaparsec >=7.0 , mtl , split >=0.2@@ -72,11 +77,11 @@ , containers , gitrev >=1.3.1 , hadolint- , language-docker >=8.0.2 && <9+ , language-docker >=8.1.0 && <9 , megaparsec >=7.0 , optparse-applicative >=0.14.0 , text- if !(os(osx))+ if flag(static) && !(os(osx)) ld-options: -static -pthread default-language: Haskell2010 @@ -92,13 +97,13 @@ build-depends: HUnit >=1.2 , HsYAML- , ShellCheck >=0.7.0+ , ShellCheck >=0.7.1 , aeson , base >=4.8 && <5 , bytestring >=0.10 , hadolint , hspec- , language-docker >=8.0.2 && <9+ , language-docker >=8.1.0 && <9 , megaparsec >=7.0 , split >=0.2 , text
src/Hadolint/Config.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-} module Hadolint.Config (applyConfig, ConfigFile(..)) where @@ -54,7 +55,7 @@ parseAndApply configFile = do contents <- Bytes.readFile configFile case Yaml.decode1Strict contents of- Left err -> return $ Left (formatError err configFile)+ Left (_, err) -> return $ Left (formatError err configFile) Right (ConfigFile ignore trusted) -> return (Right (override ignore trusted)) -- | Applies the configuration found in the file to the passed Lint.LintOptions override ignore trusted = applyTrusted trusted . applyIgnore ignore $ o
src/Hadolint/Formatter/Format.hs view
@@ -18,7 +18,7 @@ import Data.Sequence (Seq) import Hadolint.Rules import ShellCheck.Interface-import Text.Megaparsec (Stream(..))+import Text.Megaparsec (Stream(..), pstateSourcePos) import Text.Megaparsec.Error import Text.Megaparsec.Pos (SourcePos, sourcePosPretty) @@ -68,5 +68,5 @@ errorPosition :: Stream s => ParseErrorBundle s e -> Text.Megaparsec.Pos.SourcePos errorPosition (ParseErrorBundle e s) =- let (pos, _, _) = reachOffset (errorOffset (NE.head e)) s- in pos+ let (_, posState) = reachOffset (errorOffset (NE.head e)) s+ in pstateSourcePos posState
src/Hadolint/Rules.hs view
@@ -445,7 +445,7 @@ \install <package>=<version>`" check (Run args) = argumentsRule (all versionFixed . aptGetPackages) args check _ = True- versionFixed package = "=" `Text.isInfixOf` package+ versionFixed package = "=" `Text.isInfixOf` package || ("/" `Text.isInfixOf` package || ".deb" `Text.isSuffixOf` package) aptGetPackages :: Shell.ParsedShell -> [Text.Text] aptGetPackages args =@@ -521,7 +521,7 @@ , arg /= "add" ] where- dropTarget = Shell.dropFlagArg ["t", "virtual", "repository"]+ dropTarget = Shell.dropFlagArg ["t", "virtual", "repository", "X"] apkAddNoCache :: Rule apkAddNoCache = instructionRule code severity message check@@ -596,10 +596,28 @@ relevantInstall cmd = ["install"] `isInfixOf` Shell.getArgs cmd && not (["--requirement"] `isInfixOf` Shell.getArgs cmd || ["-r"] `isInfixOf` Shell.getArgs cmd || ["."] `isInfixOf` Shell.getArgs cmd)- hasBuildConstraint = Shell.hasFlag "constraint"+ hasBuildConstraint cmd = Shell.hasFlag "constraint" cmd || Shell.hasFlag "c" cmd packages cmd = stripInstallPrefix $- Shell.getArgsNoFlags $ Shell.dropFlagArg ["i", "index-url", "extra-index-url"] cmd+ Shell.getArgsNoFlags $ Shell.dropFlagArg+ [ "abi"+ , "b", "build"+ , "e", "editable"+ , "extra-index-url"+ , "f", "find-links"+ , "i", "index-url"+ , "implementation"+ , "no-binary"+ , "only-binary"+ , "platform"+ , "prefix"+ , "progress-bar"+ , "python-version"+ , "root"+ , "src"+ , "t", "target"+ , "upgrade-strategy"+ ] cmd versionFixed package = hasVersionSymbol package || isVersionedGit package isVersionedGit package = "git+http" `Text.isInfixOf` package && "@" `Text.isInfixOf` package versionSymbols = ["==", ">=", "<=", ">", "<", "!=", "~=", "==="]@@ -633,12 +651,17 @@ isNpmInstall = Shell.cmdHasArgs "npm" ["install"] installIsFirst cmd = ["install"] `isPrefixOf` Shell.getArgsNoFlags cmd packages cmd = stripInstallPrefix (Shell.getArgsNoFlags cmd)- versionFixed package =- if hasGitPrefix package- then isVersionedGit package- else hasVersionSymbol package+ versionFixed package+ | hasGitPrefix package = isVersionedGit package+ | hasTarballSuffix package = True+ | isFolder package = True+ | otherwise = hasVersionSymbol package gitPrefixes = ["git://", "git+ssh://", "git+http://", "git+https://"] hasGitPrefix package = or [p `Text.isPrefixOf` package | p <- gitPrefixes]+ tarballSuffixes = [".tar", ".tar.gz", ".tgz"]+ hasTarballSuffix package = or [p `Text.isSuffixOf` package | p <- tarballSuffixes]+ pathPrefixes = ["/", "./", "../", "~/"]+ isFolder package = or [p `Text.isPrefixOf` package | p <- pathPrefixes] isVersionedGit package = "#" `Text.isInfixOf` package hasVersionSymbol package = "@" `Text.isInfixOf` dropScope package where
src/Hadolint/Shell.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE PatternSynonyms #-} module Hadolint.Shell where @@ -12,7 +13,7 @@ import qualified Data.Text as Text import Data.Text (Text) import qualified ShellCheck.AST-import ShellCheck.AST (Id(..), Token(..))+import ShellCheck.AST (Id(..), Token(..), pattern T_SimpleCommand, pattern T_Pipe) import qualified ShellCheck.ASTLib import ShellCheck.Checker import ShellCheck.Interface
test/ConfigSpec.hs view
@@ -44,7 +44,7 @@ assertConfig :: HasCallStack => ConfigFile -> Bytes.ByteString -> Assertion assertConfig config s = case Yaml.decode1Strict s of- Left err ->+ Left (_, err) -> assertFailure err Right result -> checkResult result
test/Spec.hs view
@@ -371,6 +371,15 @@ in do ruleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile onBuildRuleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile+ it "apk add with repository (-X) without equal sign" $+ let dockerFile =+ [ "RUN apk add --no-cache \\"+ , "-X https://nl.alpinelinux.org/alpine/edge/testing \\"+ , "flow=0.78.0-r0"+ ]+ in do+ ruleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile+ onBuildRuleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile -- describe "EXPOSE rules" $ do it "invalid port" $ ruleCatches invalidPort "EXPOSE 80000"@@ -407,9 +416,21 @@ it "pip version pinned with === operator" $ do ruleCatchesNot pipVersionPinned "RUN pip install MySQL_python===1.2.2" onBuildRuleCatchesNot pipVersionPinned "RUN pip install MySQL_python===1.2.2"- it "pip version pinned with flag" $ do+ it "pip version pinned with flag --ignore-installed" $ do ruleCatchesNot pipVersionPinned "RUN pip install --ignore-installed MySQL_python==1.2.2" onBuildRuleCatchesNot pipVersionPinned "RUN pip install --ignore-installed MySQL_python==1.2.2"+ it "pip version pinned with flag --build" $ do+ ruleCatchesNot pipVersionPinned "RUN pip3 install --build /opt/yamllint yamllint==1.20.0"+ onBuildRuleCatchesNot pipVersionPinned "RUN pip3 install --build /opt/yamllint yamllint==1.20.0"+ it "pip version pinned with flag --prefix" $ do+ ruleCatchesNot pipVersionPinned "RUN pip3 install --prefix /opt/yamllint yamllint==1.20.0"+ onBuildRuleCatchesNot pipVersionPinned "RUN pip3 install --prefix /opt/yamllint yamllint==1.20.0"+ it "pip version pinned with flag --root" $ do+ ruleCatchesNot pipVersionPinned "RUN pip3 install --root /opt/yamllint yamllint==1.20.0"+ onBuildRuleCatchesNot pipVersionPinned "RUN pip3 install --root /opt/yamllint yamllint==1.20.0"+ it "pip version pinned with flag --target" $ do+ ruleCatchesNot pipVersionPinned "RUN pip3 install --target /opt/yamllint yamllint==1.20.0"+ onBuildRuleCatchesNot pipVersionPinned "RUN pip3 install --target /opt/yamllint yamllint==1.20.0" it "pip version pinned with python -m" $ do ruleCatchesNot pipVersionPinned "RUN python -m pip install example==1.2.2" onBuildRuleCatchesNot pipVersionPinned "RUN python -m pip install example==1.2.2"@@ -470,9 +491,12 @@ it "pip install no cache dir" $ do ruleCatchesNot pipVersionPinned "RUN pip install MySQL_python==1.2.2 --no-cache-dir" onBuildRuleCatchesNot pipVersionPinned "RUN pip install MySQL_python==1.2.2 --no-cache-dir"- it "pip install constraints file" $ do+ it "pip install constraints file - long version argument" $ do ruleCatchesNot pipVersionPinned "RUN pip install pykafka --constraint http://foo.bar.baz" onBuildRuleCatchesNot pipVersionPinned "RUN pip install pykafka --constraint http://foo.bar.baz"+ it "pip install constraints file - short version argument" $ do+ ruleCatchesNot pipVersionPinned "RUN pip install pykafka -c http://foo.bar.baz"+ onBuildRuleCatchesNot pipVersionPinned "RUN pip install pykafka -c http://foo.bar.baz" -- describe "npm pinning" $ do it "version pinned in package.json" $ do@@ -496,6 +520,27 @@ it "version pinned with -g" $ do ruleCatchesNot npmVersionPinned "RUN npm install -g express@\"4.1.1\"" onBuildRuleCatchesNot npmVersionPinned "RUN npm install -g express@\"4.1.1\""+ it "version does not have to be pinned for tarball suffix .tar" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install package-v1.2.3.tar"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install package-v1.2.3.tar"+ it "version does not have to be pinned for tarball suffix .tar.gz" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install package-v1.2.3.tar.gz"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install package-v1.2.3.tar.gz"+ it "version does not have to be pinned for tarball suffix .tgz" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install package-v1.2.3.tgz"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install package-v1.2.3.tgz"+ it "version does not have to be pinned for folder - absolute path" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install /folder"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install /folder"+ it "version does not have to be pinned for folder - relative path from current folder" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install ./folder"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install ./folder"+ it "version does not have to be pinned for folder - relative path to parent folder" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install ../folder"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install ../folder"+ it "version does not have to be pinned for folder - relative path from home" $ do+ ruleCatchesNot npmVersionPinned "RUN npm install ~/folder"+ onBuildRuleCatchesNot npmVersionPinned "RUN npm install ~/folder" it "commit pinned for git+ssh" $ do ruleCatchesNot npmVersionPinned@@ -725,6 +770,9 @@ it "apt-get version" $ do ruleCatchesNot aptGetVersionPinned "RUN apt-get install -y python=1.2.2" onBuildRuleCatchesNot aptGetVersionPinned "RUN apt-get install -y python=1.2.2"+ it "apt-get version" $ do+ ruleCatchesNot aptGetVersionPinned "RUN apt-get install ./wkhtmltox_0.12.5-1.bionic_amd64.deb"+ onBuildRuleCatchesNot aptGetVersionPinned "RUN apt-get install ./wkhtmltox_0.12.5-1.bionic_amd64.deb" it "apt-get pinned" $ do ruleCatchesNot aptGetVersionPinned