hadolint 1.15.0 → 1.16.1
raw patch · 5 files changed
+91/−24 lines, 5 filesdep ~ShellCheckdep ~language-docker
Dependency ranges changed: ShellCheck, language-docker
Files
- README.md +8/−1
- hadolint.cabal +8/−8
- src/Hadolint/Rules.hs +12/−8
- src/Hadolint/Shell.hs +11/−7
- test/Spec.hs +52/−0
README.md view
@@ -47,6 +47,12 @@ brew install hadolint ``` +On Windows you can use [scoop](https://github.com/lukesampson/scoop) to install `hadolint`.++```batch+scoop install hadolint+```+ As shown before, `hadolint` is available as a Docker container: ```bash@@ -157,8 +163,8 @@ | [DL3003](https://github.com/hadolint/hadolint/wiki/DL3003) | Use WORKDIR to switch to a directory. | | [DL3004](https://github.com/hadolint/hadolint/wiki/DL3004) | Do not use sudo as it leads to unpredictable behavior. Use a tool like gosu to enforce root. | | [DL3005](https://github.com/hadolint/hadolint/wiki/DL3005) | Do not use apt-get upgrade or dist-upgrade. |-| [DL3007](https://github.com/hadolint/hadolint/wiki/DL3007) | Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag. | | [DL3006](https://github.com/hadolint/hadolint/wiki/DL3006) | Always tag the version of an image explicitly. |+| [DL3007](https://github.com/hadolint/hadolint/wiki/DL3007) | Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag. | | [DL3008](https://github.com/hadolint/hadolint/wiki/DL3008) | Pin versions in apt-get install. | | [DL3009](https://github.com/hadolint/hadolint/wiki/DL3009) | Delete the apt-get lists after installing something. | | [DL3010](https://github.com/hadolint/hadolint/wiki/DL3010) | Use ADD for extracting archives into an image. |@@ -210,6 +216,7 @@ | [SC2026](https://github.com/koalaman/shellcheck/wiki/SC2026) | This word is outside of quotes. Did you intend to 'nest '"'single quotes'"' instead'? | | [SC2028](https://github.com/koalaman/shellcheck/wiki/SC2028) | `echo` won't expand escape sequences. Consider `printf`. | | [SC2035](https://github.com/koalaman/shellcheck/wiki/SC2035) | Use `./*glob*` or `-- *glob*` so names with dashes won't become options. |+| [SC2039](https://github.com/koalaman/shellcheck/wiki/SC2039) | In POSIX sh, something is undefined. | | [SC2046](https://github.com/koalaman/shellcheck/wiki/SC2046) | Quote this to prevent word splitting | | [SC2086](https://github.com/koalaman/shellcheck/wiki/SC2086) | Double quote to prevent globbing and word splitting. | | [SC2140](https://github.com/koalaman/shellcheck/wiki/SC2140) | Word is in the form `"A"B"C"` (B indicated). Did you mean `"ABC"` or `"A\"B\"C"`? |
hadolint.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.0.+-- This file has been generated from package.yaml by hpack version 0.31.1. -- -- see: https://github.com/sol/hpack ----- hash: 87e6b48cec5e99eb4cf60b8c1d95138858601ec3516c35a5f36c2ff74e2d7f0e+-- hash: 450fbbc893f6ece618b57a9693451fcde7e0a9421d0fdf71f2adef88f01cd080 name: hadolint-version: 1.15.0+version: 1.16.1 synopsis: Dockerfile Linter JavaScript API description: A smarter Dockerfile linter that helps you build best practice Docker images. category: Development@@ -44,14 +44,14 @@ src ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path build-depends:- ShellCheck >=0.5.0+ ShellCheck >=0.6.0 , aeson , base >=4.8 && <5 , bytestring , containers , directory >=1.3.0 , filepath- , language-docker >=8.0.0 && <9+ , language-docker >=8.0.1 && <9 , megaparsec >=7.0 , mtl , split >=0.2@@ -72,7 +72,7 @@ , containers , gitrev >=1.3.1 , hadolint- , language-docker >=8.0.0 && <9+ , language-docker >=8.0.1 && <9 , megaparsec >=7.0 , optparse-applicative >=0.14.0 , text@@ -90,13 +90,13 @@ ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -optP-Wno-nonportable-include-path build-depends: HUnit >=1.2- , ShellCheck >=0.5.0+ , ShellCheck >=0.6.0 , aeson , base >=4.8 && <5 , bytestring >=0.10 , hadolint , hspec- , language-docker >=8.0.0 && <9+ , language-docker >=8.0.1 && <9 , megaparsec >=7.0 , split >=0.2 , text
src/Hadolint/Rules.hs view
@@ -258,11 +258,15 @@ check st _ (Run (ArgumentsText script)) = (st, doCheck st script) check st _ _ = (st, []) doCheck opts script = nub [commentMetadata c | c <- Shell.shellcheck opts script]- -- | Converts ShellCheck errors into our own errors type- commentMetadata :: ShellCheck.Interface.Comment -> Metadata- commentMetadata (ShellCheck.Interface.Comment severity code message) =- Metadata (Text.pack ("SC" ++ show code)) severity (Text.pack message) +-- | Converts ShellCheck errors into our own errors type+commentMetadata :: ShellCheck.Interface.PositionedComment -> Metadata+commentMetadata c = Metadata (Text.pack ("SC" ++ show (code c))) (severity c) (Text.pack (message c))+ where+ severity pc = ShellCheck.Interface.cSeverity $ ShellCheck.Interface.pcComment pc+ code pc = ShellCheck.Interface.cCode $ ShellCheck.Interface.pcComment pc+ message pc = ShellCheck.Interface.cMessage $ ShellCheck.Interface.pcComment pc+ absoluteWorkdir :: Rule absoluteWorkdir = instructionRule code severity message check where@@ -443,8 +447,8 @@ aptGetPackages args = [ arg | cmd <- dropTarget <$> Shell.findCommands args- , arg <- Shell.getArgsNoFlags cmd , Shell.cmdHasArgs "apt-get" ["install"] cmd+ , arg <- Shell.getArgsNoFlags cmd , arg /= "install" ] where@@ -508,12 +512,12 @@ apkAddPackages args = [ arg | cmd <- dropTarget <$> Shell.findCommands args- , arg <- Shell.getArgsNoFlags cmd , Shell.cmdHasArgs "apk" ["add"] cmd+ , arg <- Shell.getArgsNoFlags cmd , arg /= "add" ] where- dropTarget = Shell.dropFlagArg ["t", "virtual"]+ dropTarget = Shell.dropFlagArg ["t", "virtual", "repository"] apkAddNoCache :: Rule apkAddNoCache = instructionRule code severity message check@@ -576,7 +580,7 @@ ["install"] `isInfixOf` Shell.getAllArgs cmd && not (["-r"] `isInfixOf` Shell.getAllArgs cmd || ["."] `isInfixOf` Shell.getAllArgs cmd) hasBuildConstraint = Shell.hasFlag "constraint"- packages cmd = stripInstallPrefix (Shell.getArgsNoFlags cmd)+ packages cmd = stripInstallPrefix $ Shell.getArgsNoFlags $ Shell.dropFlagArg ["i", "index-url", "extra-index-url"] cmd versionFixed package = hasVersionSymbol package || isVersionedGit package isVersionedGit package = "git+http" `isInfixOf` package && "@" `isInfixOf` package versionSymbols = ["==", ">=", "<=", ">", "<", "!=", "~=", "==="]
src/Hadolint/Shell.hs view
@@ -47,19 +47,23 @@ setShell :: Text.Text -> ShellOpts -> ShellOpts setShell s (ShellOpts _ v) = ShellOpts s v -shellcheck :: ShellOpts -> ParsedShell -> [Comment]+shellcheck :: ShellOpts -> ParsedShell -> [PositionedComment] shellcheck (ShellOpts sh env) (ParsedShell txt _) = if "pwsh" `Text.isPrefixOf` sh then [] -- Do no run for powershell- else map comment runShellCheck+ else runShellCheck where runShellCheck = crComments $ runIdentity $ checkScript si spec- comment (PositionedComment _ _ c) = c si = mockedSystemInterface [("", "")]- spec = CheckSpec filename script sourced exclusions Nothing+ spec = emptyCheckSpec {+ csFilename = "", -- filename can be ommited because we only want the parse results back+ csScript = script,+ csCheckSourced = False,+ csExcludedWarnings = exclusions,+ csShellTypeOverride = Nothing,+ csMinSeverity = StyleC+ } script = "#!" ++ extractShell sh ++ "\n" ++ printVars ++ Text.unpack txt- filename = "" -- filename can be ommited because we only want the parse results back- sourced = False exclusions = [ 2187 -- exclude the warning about the ash shell not being supported ]@@ -79,7 +83,7 @@ runIdentity $ ShellCheck.Parser.parseScript (mockedSystemInterface [("", "")])- ParseSpec+ newParseSpec { psFilename = "" -- There is no filename , psScript = "#!/bin/bash\n" ++ Text.unpack txt , psCheckSourced = False
test/Spec.hs view
@@ -309,6 +309,24 @@ in do ruleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile onBuildRuleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile+ it "apk add with repository without equal sign" $+ let dockerFile =+ [ "RUN apk add --no-cache \\"+ , "--repository https://nl.alpinelinux.org/alpine/edge/testing \\"+ , "flow=0.78.0-r0"+ ]+ in do+ ruleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile+ onBuildRuleCatchesNot apkAddVersionPinned $ Text.unlines dockerFile+ it "apk add with repository with equal sign" $+ let dockerFile =+ [ "RUN apk add --no-cache \\"+ , "--repository=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"@@ -381,6 +399,27 @@ onBuildRuleCatchesNot pipVersionPinned "RUN pip install MySQL_python==1.2.2 --disable-pip-version-check"+ it "pip install --index-url" $ do+ ruleCatchesNot+ pipVersionPinned+ "RUN pip install --index-url https://eg.com/foo foobar==1.0.0"+ onBuildRuleCatchesNot+ pipVersionPinned+ "RUN pip install --index-url https://eg.com/foo foobar==1.0.0"+ it "pip install index-url with -i flag" $ do+ ruleCatchesNot+ pipVersionPinned+ "RUN pip install --index-url https://eg.com/foo foobar==1.0.0"+ onBuildRuleCatchesNot+ pipVersionPinned+ "RUN pip install --index-url https://eg.com/foo foobar==1.0.0"+ it "pip install --index-url with --extra-index-url" $ do+ ruleCatchesNot+ pipVersionPinned+ "RUN pip install --index-url https://eg.com/foo --extra-index-url https://ex-eg.io/foo foobar==1.0.0"+ onBuildRuleCatchesNot+ pipVersionPinned+ "RUN pip install --index-url https://eg.com/foo --extra-index-url https://ex-eg.io/foo foobar==1.0.0" 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"@@ -991,6 +1030,19 @@ , "FROM builder1 AS builder2" ] in ruleCatchesNot (registryIsAllowed ["random.com"]) $ Text.unlines dockerFile+ --+ describe "Regression Tests" $+ it "Comments with backslashes at the end are just comments" $+ let dockerFile =+ [ "FROM alpine:3.6"+ , "# The following comment makes hadolint still complain about DL4006"+ , "# \\"+ , "# should solve DL4006"+ , "SHELL [\"/bin/sh\", \"-o\", \"pipefail\", \"-c\"]"+ , "# RUN with pipe. causes DL4006, but should be fixed by above SHELL"+ , "RUN echo \"kaka\" | sed 's/a/o/g' >> /root/afile"+ ]+ in ruleCatches usePipefail $ Text.unlines dockerFile assertChecks :: HasCallStack => Rule -> Text.Text -> ([RuleCheck] -> IO a) -> IO a assertChecks rule s makeAssertions =