diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -472,7 +472,7 @@
 <!--lint disable maximum-line-length-->
 
 | 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. |
@@ -532,6 +532,7 @@
 | [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.                                                                     |
+| [DL3062](https://github.com/hadolint/hadolint/wiki/DL3061)   | Warning          | Pin versions in go install. Instead of `go install <package>` use `go install <package>@<version>`                                                  |
 | [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.                                                                                                                  |
@@ -559,7 +560,7 @@
 | [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 `[ .. ]` 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 `#`.                                                                                                                    |
+| [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 &#124; ..</code> or <code>cmd file &#124; ..</code> instead.                                                 |
 | [SC2015](https://github.com/koalaman/shellcheck/wiki/SC2015) |                  | Note that <code>A && B &#124;&#124; C</code> is not if-then-else. C may run when A is true.                                                         |
 | [SC2026](https://github.com/koalaman/shellcheck/wiki/SC2026) |                  | This word is outside of quotes. Did you intend to 'nest '"'single quotes'"' instead'?                                                               |
diff --git a/hadolint.cabal b/hadolint.cabal
--- a/hadolint.cabal
+++ b/hadolint.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               hadolint
-version:            2.13.1
+version:            2.14.0
 synopsis:           Dockerfile Linter JavaScript API
 description:
   A smarter Dockerfile linter that helps you build best practice Docker images.
@@ -101,6 +101,7 @@
     Hadolint.Rule.DL3059
     Hadolint.Rule.DL3060
     Hadolint.Rule.DL3061
+    Hadolint.Rule.DL3062
     Hadolint.Rule.DL4000
     Hadolint.Rule.DL4001
     Hadolint.Rule.DL4003
@@ -109,6 +110,7 @@
     Hadolint.Rule.DL4006
     Hadolint.Rule.Shellcheck
     Hadolint.Shell
+    Hadolint.Utils
 
   other-modules:      Paths_hadolint
   autogen-modules:    Paths_hadolint
@@ -147,12 +149,11 @@
     , foldl                 >=1.4.18   && <1.5
     , gitrev                >=1.3.1    && <1.4
     , HsYAML                >=0.2.1    && <0.3
-    , ilist                 >=0.3.1    && <0.4
-    , language-docker       >=14.0.1   && <15
+    , language-docker       >=15.0.0   && <16
     , megaparsec            >=9.0.0    && <9.8
     , mtl                   >=2.3.1    && <2.4
     , network-uri           >=2.6.4    && <2.7
-    , optparse-applicative  >=0.19.0   && <0.20
+    , optparse-applicative  >=0.18.1   && <0.20
     , parallel              >=3.2.2    && <3.3
     , parsec                >=3.1.18   && <3.2
     , prettyprinter         >=1.7.1    && <1.8
@@ -196,7 +197,7 @@
     , containers            >=0.7       && <0.8
     , data-default          >=0.8.0     && <0.9
     , hadolint
-    , language-docker       >=14.0.1    && <15
+    , language-docker
     , megaparsec            >=9.7.0     && <9.8
     , optparse-applicative  >=0.19.0    && <0.20
     , prettyprinter         >=1.7.1     && <1.8
@@ -277,6 +278,7 @@
     Hadolint.Rule.DL3059Spec
     Hadolint.Rule.DL3060Spec
     Hadolint.Rule.DL3061Spec
+    Hadolint.Rule.DL3062Spec
     Hadolint.Rule.DL4000Spec
     Hadolint.Rule.DL4001Spec
     Hadolint.Rule.DL4003Spec
diff --git a/src/Hadolint/Process.hs b/src/Hadolint/Process.hs
--- a/src/Hadolint/Process.hs
+++ b/src/Hadolint/Process.hs
@@ -68,6 +68,7 @@
 import qualified Hadolint.Rule.DL3059
 import qualified Hadolint.Rule.DL3060
 import qualified Hadolint.Rule.DL3061
+import qualified Hadolint.Rule.DL3062
 import qualified Hadolint.Rule.DL4000
 import qualified Hadolint.Rule.DL4001
 import qualified Hadolint.Rule.DL4003
@@ -172,6 +173,7 @@
     <> Hadolint.Rule.DL3059.rule
     <> Hadolint.Rule.DL3060.rule
     <> Hadolint.Rule.DL3061.rule
+    <> Hadolint.Rule.DL3062.rule
     <> Hadolint.Rule.DL4000.rule
     <> Hadolint.Rule.DL4001.rule
     <> Hadolint.Rule.DL4003.rule
diff --git a/src/Hadolint/Rule/DL3009.hs b/src/Hadolint/Rule/DL3009.hs
--- a/src/Hadolint/Rule/DL3009.hs
+++ b/src/Hadolint/Rule/DL3009.hs
@@ -3,9 +3,9 @@
 import Hadolint.Rule
 import Language.Docker.Syntax
 import qualified Data.Map.Strict as Map
-import qualified Data.Set as Set
 import qualified Data.Text as Text
 import qualified Hadolint.Shell as Shell
+import qualified Hadolint.Utils as Utils
 
 
 data Acc
@@ -36,9 +36,9 @@
           if foldArguments disabledDockerClean args
           then st |> modify rememberDockerClean
           else st
-      | hasCacheDirectory "/var/lib/apt/lists" flags = st
-      | hasCacheDirectory "/var/lib/apt" flags
-        && hasCacheDirectory "/var/cache/apt" flags = st
+      | Utils.hasCacheOrTmpfsMountWith "/var/lib/apt/lists" flags = st
+      | Utils.hasCacheOrTmpfsMountWith "/var/lib/apt" flags
+        && Utils.hasCacheOrTmpfsMountWith "/var/cache/apt" flags = st
       | otherwise = st |> modify (rememberLine line)
     check _ st _ = st
 
@@ -99,14 +99,6 @@
             ["\'Binary::apt::APT::Keep-Downloaded-Packages \"true\";\'"]
         )
         (Shell.presentCommands args)
-
-hasCacheDirectory :: Text.Text -> RunFlags -> Bool
-hasCacheDirectory dir RunFlags { mount } =
-  not ( null $ Set.filter (isCacheMount dir) mount)
-
-isCacheMount :: Text.Text -> RunMount -> Bool
-isCacheMount dir (CacheMount CacheOpts {cTarget = TargetPath {unTargetPath = t}}) = dir `Text.isPrefixOf` t
-isCacheMount _ _ = False
 
 -- | Even though dockerfiles without a FROM are not valid, we still want to provide some feedback for this rule
 -- so we pretend there is a base image at the start of the file if there is none
diff --git a/src/Hadolint/Rule/DL3019.hs b/src/Hadolint/Rule/DL3019.hs
--- a/src/Hadolint/Rule/DL3019.hs
+++ b/src/Hadolint/Rule/DL3019.hs
@@ -3,9 +3,8 @@
 import Hadolint.Rule
 import Hadolint.Shell (ParsedShell)
 import Language.Docker.Syntax
-import qualified Data.Set as Set
-import qualified Data.Text as Text
 import qualified Hadolint.Shell as Shell
+import qualified Hadolint.Utils as Utils
 
 
 rule :: Rule ParsedShell
@@ -20,22 +19,12 @@
     message =
       "Use the `--no-cache` switch to avoid the need to use `--update` and \
       \remove `/var/cache/apk/*` when done installing packages"
-    check (Run (RunArgs args flags)) = hasCacheMount flags
-      || foldArguments (Shell.noCommands forgotCacheOption) args
+    check (Run (RunArgs args flags))
+      | Utils.hasCacheOrTmpfsMountWith "/var/cache/apk" flags = True
+      | foldArguments (Shell.noCommands forgotCacheOption) args = True
+      | otherwise = False
     check _ = True
 {-# INLINEABLE dl3019 #-}
-
-hasCacheMount :: RunFlags -> Bool
-hasCacheMount RunFlags { mount } =
-  not (null $ Set.filter isCacheMount mount)
-
-isCacheMount :: RunMount -> Bool
-isCacheMount (CacheMount CacheOpts { cTarget = t })= isVarCacheApk t
-isCacheMount _ = False
-
-isVarCacheApk :: TargetPath -> Bool
-isVarCacheApk TargetPath { unTargetPath = p }
-  = Text.dropWhileEnd (=='/') p == "/var/cache/apk"
 
 forgotCacheOption :: Shell.Command -> Bool
 forgotCacheOption cmd = Shell.cmdHasArgs "apk" ["add"] cmd
diff --git a/src/Hadolint/Rule/DL3033.hs b/src/Hadolint/Rule/DL3033.hs
--- a/src/Hadolint/Rule/DL3033.hs
+++ b/src/Hadolint/Rule/DL3033.hs
@@ -4,6 +4,7 @@
 import Hadolint.Rule
 import qualified Hadolint.Shell as Shell
 import Language.Docker.Syntax
+import Data.Char (isDigit, isAsciiUpper, isAsciiLower)
 
 
 rule :: Rule Shell.ParsedShell
@@ -32,8 +33,30 @@
   ]
 
 packageVersionFixed :: Text.Text -> Bool
-packageVersionFixed package =
-  "-" `Text.isInfixOf` package || ".rpm" `Text.isSuffixOf` package
+packageVersionFixed package
+  | length parts <= 1 = False  -- No dashes, definitively no version
+  | ".rpm" `Text.isSuffixOf` package = True  -- rpm files always have a version
+  | otherwise = isVersionLike $ drop 1 parts
+  where
+    parts = Text.splitOn "-" package
+
+isVersionLike :: [Text.Text] -> Bool
+isVersionLike parts =
+  case parts of
+    [] -> False  -- No parts after splitting by hyphen
+    _ -> all partIsValid parts && any partStartsWithDigit parts
+  where
+    partIsValid part = Text.all isVersionChar part
+    partStartsWithDigit part = case Text.uncons part of
+                                 Just (c, _) -> isDigit c
+                                 Nothing -> False -- Empty Text
+
+isVersionChar :: Char -> Bool
+isVersionChar c =
+  isDigit c
+    || isAsciiUpper c
+    || isAsciiLower c
+    || c `elem` ['.', '~', '^', '_', ':', '+']
 
 yumModules :: Shell.ParsedShell -> [Text.Text]
 yumModules args =
diff --git a/src/Hadolint/Rule/DL3036.hs b/src/Hadolint/Rule/DL3036.hs
--- a/src/Hadolint/Rule/DL3036.hs
+++ b/src/Hadolint/Rule/DL3036.hs
@@ -2,6 +2,7 @@
 
 import Hadolint.Rule
 import qualified Hadolint.Shell as Shell
+import qualified Hadolint.Utils as Utils
 import Language.Docker.Syntax
 
 
@@ -16,11 +17,12 @@
     severity = DLWarningC
     message = "`zypper clean` missing after zypper use."
 
-    check (Run (RunArgs args _)) =
-      foldArguments (Shell.noCommands zypperInstall) args
-        || ( foldArguments (Shell.anyCommands zypperInstall) args
-               && foldArguments (Shell.anyCommands zypperClean) args
-           )
+    check (Run (RunArgs args flags))
+      | foldArguments (Shell.noCommands zypperInstall) args = True
+      | Utils.hasCacheOrTmpfsMountWith "/var/cache/zypp" flags = True
+      | foldArguments (Shell.anyCommands zypperInstall) args
+          && foldArguments (Shell.anyCommands zypperClean) args = True
+      | otherwise = False
     check _ = True
 
     zypperInstall = Shell.cmdHasArgs "zypper" ["install", "in"]
diff --git a/src/Hadolint/Rule/DL3040.hs b/src/Hadolint/Rule/DL3040.hs
--- a/src/Hadolint/Rule/DL3040.hs
+++ b/src/Hadolint/Rule/DL3040.hs
@@ -2,6 +2,7 @@
 
 import Hadolint.Rule
 import qualified Hadolint.Shell as Shell
+import qualified Hadolint.Utils as Utils
 import Language.Docker.Syntax
 
 
@@ -16,7 +17,11 @@
     severity = DLWarningC
     message = "`dnf clean all` missing after dnf command."
 
-    check (Run (RunArgs args _)) = all (checkMissingClean args) dnfCmds
+    check (Run (RunArgs args flags))
+      | all (checkMissingClean args) dnfCmds = True
+      | Utils.hasCacheOrTmpfsMountWith "/var/cache/libdnf5" flags = True
+      | Utils.hasCacheOrTmpfsMountWith ".cache/libdnf5" flags = True
+      | otherwise = False
     check _ = True
 
     checkMissingClean args cmdName =
@@ -26,7 +31,7 @@
            )
 
     dnfInstall cmdName = Shell.cmdHasArgs cmdName ["install"]
-    dnfClean cmdName args = Shell.cmdHasArgs cmdName ["clean", "all"] args 
-      || Shell.cmdHasArgs "rm" ["-rf", "/var/cache/yum/*"] args
+    dnfClean cmdName args = Shell.cmdHasArgs cmdName ["clean", "all"] args
+      || Shell.cmdHasArgs "rm" ["-rf", "/var/cache/libdnf5*"] args
     dnfCmds = ["dnf", "microdnf"]
 {-# INLINEABLE dl3040 #-}
diff --git a/src/Hadolint/Rule/DL3041.hs b/src/Hadolint/Rule/DL3041.hs
--- a/src/Hadolint/Rule/DL3041.hs
+++ b/src/Hadolint/Rule/DL3041.hs
@@ -54,7 +54,11 @@
                                  Nothing -> False -- Empty Text
 
 isVersionChar :: Char -> Bool
-isVersionChar c = isDigit c || isAsciiUpper c || isAsciiLower c || c `elem` ['.', '~', '^', '_']
+isVersionChar c =
+  isDigit c
+    || isAsciiUpper c
+    || isAsciiLower c
+    || c `elem` ['.', '~', '^', '_', ':', '+']
 
 dnfModules :: Shell.ParsedShell -> [Text.Text]
 dnfModules args =
diff --git a/src/Hadolint/Rule/DL3042.hs b/src/Hadolint/Rule/DL3042.hs
--- a/src/Hadolint/Rule/DL3042.hs
+++ b/src/Hadolint/Rule/DL3042.hs
@@ -4,12 +4,12 @@
 import Data.Map.Strict (Map)
 import qualified Data.Map.Strict as Map
 import Data.Maybe (fromMaybe, isNothing, isJust, fromJust)
-import Data.Set (Set)
 import qualified Data.Set as Set
 import Data.Text (Text)
 import qualified Data.Text as Text
 import Hadolint.Rule
 import qualified Hadolint.Shell as Shell
+import qualified Hadolint.Utils as Utils
 import Language.Docker.Syntax
 
 
@@ -38,10 +38,11 @@
               \ Use `pip install --no-cache-dir <package>`"
     check _ st (From from) = st |> modify (rememberStage from)
     check _ st (Env pairs) = st |> modify (registerEnv pairs)
-    check line st (Run (RunArgs args _))
+    check line st (Run (RunArgs args flags))
       | Acc s ncm <- state st, Just True <- Map.lookup s ncm = st
       | foldArguments pipNoCacheDirIsSet args = st
       | foldArguments (Shell.noCommands forgotNoCacheDir) args = st
+      | Utils.hasCacheOrTmpfsMountWith ".cache/pip" flags = st
       | otherwise = st |> addFail CheckFailure {..}
     check _ st _ = st
 {-# INLINEABLE dl3042 #-}
@@ -119,5 +120,5 @@
     isJust val && fromJust val `notElem` truthy = False
   | otherwise = True
 
-truthy :: Set Text
+truthy :: Set.Set Text
 truthy = Set.fromList ["1", "true", "True", "TRUE", "on", "On", "ON", "yes", "Yes", "YES"]
diff --git a/src/Hadolint/Rule/DL3044.hs b/src/Hadolint/Rule/DL3044.hs
--- a/src/Hadolint/Rule/DL3044.hs
+++ b/src/Hadolint/Rule/DL3044.hs
@@ -1,6 +1,5 @@
 module Hadolint.Rule.DL3044 (rule) where
 
-import Data.List.Index (indexed)
 import qualified Data.Set as Set
 import qualified Data.Text as Text
 import Hadolint.Rule
@@ -28,9 +27,12 @@
 listOfReferences :: Pairs -> [Text.Text]
 listOfReferences prs =
   [ var
-    | (idx, (var, _)) <- indexed prs,
-      var `isSubstringOfAny` map (snd . snd) (filter ((/= idx) . fst) (indexed prs))
+    | (idx, (var, _)) <- enum prs,
+      var `isSubstringOfAny` map (snd . snd) (filter ((/= idx) . fst) (enum prs))
   ]
+  where
+    enum :: Pairs -> [(Integer, (Text.Text, Text.Text))]
+    enum = zip [0..]
 
 -- | is a reference of a variable substring of any text?
 -- matches ${var_name} and $var_name, but not $var_nameblafoo
diff --git a/src/Hadolint/Rule/DL3060.hs b/src/Hadolint/Rule/DL3060.hs
--- a/src/Hadolint/Rule/DL3060.hs
+++ b/src/Hadolint/Rule/DL3060.hs
@@ -4,8 +4,8 @@
 import qualified Data.Text as Text
 import Hadolint.Rule
 import qualified Hadolint.Shell as Shell
+import qualified Hadolint.Utils as Utils
 import Language.Docker.Syntax
-import Data.Set
 
 data Acc
   = Acc
@@ -16,22 +16,6 @@
   | Empty
   deriving (Show)
 
--- check if a RunMount is a CacheMount
-isCacheMount :: RunMount -> Bool
-isCacheMount (CacheMount _) = True
-isCacheMount _ = False
-
--- Set of RunMounts must contain at least one CacheMount
-
-containsOneCacheMount :: Set RunMount -> Bool
-containsOneCacheMount = Data.Set.foldl foldable False
-  where 
-    foldable a b = a || isCacheMount b
-
--- do not flag this as a problem if using a cacheMount
-cacheMount :: RunFlags -> Bool
-cacheMount RunFlags {mount} = containsOneCacheMount mount
-
 rule :: Rule Shell.ParsedShell
 rule = dl3060 <> onbuild dl3060
 {-# INLINEABLE rule #-}
@@ -48,7 +32,7 @@
     check line st (Run (RunArgs args flags))
       | foldArguments (Shell.anyCommands yarnInstall) args
           && foldArguments (Shell.noCommands yarnCacheClean) args
-          && not (cacheMount flags) =
+          && not (Utils.hasCacheOrTmpfsMountWith ".cache/yarn" flags) =
         st |> modify (rememberLine line)
       | otherwise = st
     check _ st _ = st
diff --git a/src/Hadolint/Rule/DL3062.hs b/src/Hadolint/Rule/DL3062.hs
new file mode 100644
--- /dev/null
+++ b/src/Hadolint/Rule/DL3062.hs
@@ -0,0 +1,46 @@
+module Hadolint.Rule.DL3062 (rule) where
+
+import Data.Text qualified as Text
+import Hadolint.Rule
+import Hadolint.Shell qualified as Shell
+import Language.Docker.Syntax
+
+rule :: Rule Shell.ParsedShell
+rule = dl3062 <> onbuild dl3062
+{-# INLINEABLE rule #-}
+
+dl3062 :: Rule Shell.ParsedShell
+dl3062 = simpleRule code severity message check
+  where
+    code = "DL3062"
+    severity = DLWarningC
+    message = "Pin versions in go. Instead of `go install <package>` use `go install <package>@<version>`"
+
+    check (Run (RunArgs args _)) = foldArguments (all checkGoPackageVersion . getGoPackage) args
+    check _ = True
+{-# INLINEABLE dl3062 #-}
+
+goCommands :: [Text.Text]
+goCommands = ["install", "get", "run"]
+
+isGoCommand :: Shell.Command -> Bool
+isGoCommand = Shell.cmdsHaveArgs ["go"] goCommands
+
+getGoPackage :: Shell.ParsedShell -> [Text.Text]
+getGoPackage args =
+  [ arg
+    | cmd <- Shell.presentCommands args,
+      isGoCommand cmd,
+      arg <- Shell.getArgsNoFlags cmd,
+      arg `notElem` goCommands
+  ]
+
+hasVersionSymbol :: Text.Text -> Bool
+hasVersionSymbol package = "@" `Text.isInfixOf` package
+
+isTagsVersion :: Text.Text -> Bool
+isTagsVersion package =
+  or [("@" <> tag) `Text.isSuffixOf` package | tag <- ["latest", "none"]]
+
+checkGoPackageVersion :: Text.Text -> Bool
+checkGoPackageVersion package = hasVersionSymbol package && not (isTagsVersion package)
diff --git a/src/Hadolint/Shell.hs b/src/Hadolint/Shell.hs
--- a/src/Hadolint/Shell.hs
+++ b/src/Hadolint/Shell.hs
@@ -162,9 +162,7 @@
 findCommandNames script = map name (presentCommands script)
 
 cmdHasArgs :: Text.Text -> [Text.Text] -> Command -> Bool
-cmdHasArgs expectedName expectedArgs (Command n args _)
-  | expectedName /= n = False
-  | otherwise = not $ null [arg | CmdPart arg _ <- args, arg `elem` expectedArgs]
+cmdHasArgs expectedName = cmdsHaveArgs [expectedName]
 
 cmdsHaveArgs :: [Text.Text] -> [Text.Text] -> Command -> Bool
 cmdsHaveArgs expectedNames expectedArgs (Command n args _)
@@ -204,7 +202,7 @@
     notAFlagId pId = pId `notElem` map partId (flags args)
 
 hasFlag :: Text.Text -> Command -> Bool
-hasFlag flag Command {flags} = not $ null [f | CmdPart f _ <- flags, f == flag]
+hasFlag flag cmd = countFlag flag cmd > 0
 
 countFlag :: Text.Text -> Command -> Int
 countFlag flag Command {flags} = length [ f | CmdPart f _ <- flags, f == flag ]
diff --git a/src/Hadolint/Utils.hs b/src/Hadolint/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Hadolint/Utils.hs
@@ -0,0 +1,31 @@
+module Hadolint.Utils
+  ( hasCacheOrTmpfsMount,
+    hasCacheOrTmpfsMountWith
+  )
+where
+
+import qualified Data.Text as Text
+import qualified Data.Set as Set
+import Language.Docker.Syntax
+
+
+-- Returns true if the given RunFlags contain a mount of type cache or tmpfs at
+-- a location that contains the path fragment `frag`.
+hasCacheOrTmpfsMountWith :: Text.Text -> RunFlags -> Bool
+hasCacheOrTmpfsMountWith frag RunFlags { mount } =
+  not ( null $ Set.filter (isCacheOrTmpfsMountWith frag) mount)
+
+isCacheOrTmpfsMountWith :: Text.Text -> RunMount -> Bool
+isCacheOrTmpfsMountWith frag (CacheMount CacheOpts {cTarget = TargetPath {unTargetPath = t}}) = frag `Text.isInfixOf` t
+isCacheOrTmpfsMountWith frag (TmpfsMount TmpOpts {tTarget = TargetPath {unTargetPath = t}}) = frag `Text.isInfixOf` t
+isCacheOrTmpfsMountWith _ _ = False
+
+-- Returns true if the given RunFlags contain a mount of type cache or tmpfs
+hasCacheOrTmpfsMount :: RunFlags -> Bool
+hasCacheOrTmpfsMount RunFlags { mount } =
+  not ( null $ Set.filter isCacheOrTmpfsMount mount)
+
+isCacheOrTmpfsMount :: RunMount -> Bool
+isCacheOrTmpfsMount (CacheMount _) = True
+isCacheOrTmpfsMount (TmpfsMount _) = True
+isCacheOrTmpfsMount _ = False
diff --git a/test/Hadolint/Rule/DL3009Spec.hs b/test/Hadolint/Rule/DL3009Spec.hs
--- a/test/Hadolint/Rule/DL3009Spec.hs
+++ b/test/Hadolint/Rule/DL3009Spec.hs
@@ -132,6 +132,50 @@
             ruleCatches "DL3009" $ Text.unlines dockerFile
             onBuildRuleCatches "DL3009" $ Text.unlines dockerFile
 
+    it "don't warn: tmpfs mount to apt cache and lists directory" $
+      let dockerFile =
+            [ "RUN \\",
+              "  --mount=type=tmpfs,target=/var/cache/apt \\",
+              "  --mount=type=tmpfs,target=/var/lib/apt \\",
+              "  apt-get update"
+            ]
+       in do
+            ruleCatchesNot "DL3009" $ Text.unlines dockerFile
+            onBuildRuleCatchesNot "DL3009" $ Text.unlines dockerFile
+
+    it "don't warn: tmpfs mount to apt cache and cache mount to lists directory" $
+      let dockerFile =
+            [ "RUN \\",
+              "  --mount=type=tmpfs,target=/var/cache/apt \\",
+              "  --mount=type=cache,target=/var/lib/apt \\",
+              "  apt-get update"
+            ]
+       in do
+            ruleCatchesNot "DL3009" $ Text.unlines dockerFile
+            onBuildRuleCatchesNot "DL3009" $ Text.unlines dockerFile
+
+    it "don't warn: cache mount to apt cache and tmpfs mount to lists directory" $
+      let dockerFile =
+            [ "RUN \\",
+              "  --mount=type=cache,target=/var/cache/apt \\",
+              "  --mount=type=tmpfs,target=/var/lib/apt \\",
+              "  apt-get update"
+            ]
+       in do
+            ruleCatchesNot "DL3009" $ Text.unlines dockerFile
+            onBuildRuleCatchesNot "DL3009" $ Text.unlines dockerFile
+
+    it "don't warn: cache mount to apt cache and lists directory" $
+      let dockerFile =
+            [ "RUN \\",
+              "  --mount=type=cache,target=/var/cache/apt \\",
+              "  --mount=type=cache,target=/var/lib/apt \\",
+              "  apt-get update"
+            ]
+       in do
+            ruleCatchesNot "DL3009" $ Text.unlines dockerFile
+            onBuildRuleCatchesNot "DL3009" $ Text.unlines dockerFile
+
     it "apt no cleanup" $
       let dockerFile =
             [ "FROM scratch",
diff --git a/test/Hadolint/Rule/DL3019Spec.hs b/test/Hadolint/Rule/DL3019Spec.hs
--- a/test/Hadolint/Rule/DL3019Spec.hs
+++ b/test/Hadolint/Rule/DL3019Spec.hs
@@ -10,18 +10,44 @@
   let ?config = def
 
   describe "DL3019 - Use the --no-cache switch." $ do
-    it "apk add with --no-cache" $ do
-      ruleCatches "DL3019" "RUN apk add flex=2.6.4-r1"
-      onBuildRuleCatches "DL3019" "RUN apk add flex=2.6.4-r1"
-    it "apk add without --no-cache" $ do
-      ruleCatchesNot "DL3019" "RUN apk add --no-cache flex=2.6.4-r1"
-      onBuildRuleCatchesNot "DL3019" "RUN apk add --no-cache flex=2.6.4-r1"
-    it "don't warn: apk add with BuildKit cache mount" $ do
-      ruleCatchesNot "DL3019" "RUN --mount=type=cache,target=/var/cache/apk apk add -U curl=7.77.0"
-      onBuildRuleCatchesNot "DL3019" "RUN --mount=type=cache,target=/var/cache/apk apk add -U curl=7.77.0"
-    it "don't warn: apk add with BuildKit cache mount in wrong dir and --no-cache" $ do
-      ruleCatchesNot "DL3019" "RUN --mount=type=cache,target=/var/cache/foo apk add --no-cache -U curl=7.77.0"
-      onBuildRuleCatchesNot "DL3019" "RUN --mount=type=cache,target=/var/cache/foo apk add --no-cache -U curl=7.77.0"
-    it "warn: apk add with BuildKit cache mount to wrong dir" $ do
-      ruleCatches "DL3019" "RUN --mount=type=cache,target=/var/cache/foo apk add -U curl=7.77.0"
-      onBuildRuleCatches "DL3019" "RUN --mount=type=cache,target=/var/cache/foo apk add -U curl=7.77.0"
+    it "warn: apk add without --no-cache" $
+      let line = "RUN apk add flex=2.6.4-r1"
+      in do
+        ruleCatches "DL3019" line
+        onBuildRuleCatches "DL3019" line
+
+    it "don't warn: apk add with --no-cache" $
+      let line = "RUN apk add --no-cache flex=2.6.4-r1"
+      in do
+        ruleCatchesNot "DL3019" line
+        onBuildRuleCatchesNot "DL3019" line
+
+    it "don't warn: apk add with BuildKit cache mount" $
+      let line = "RUN --mount=type=cache,target=/var/cache/apk apk add -U curl=7.77.0"
+      in do
+        ruleCatchesNot "DL3019" line
+        onBuildRuleCatchesNot "DL3019" line
+
+    it "don't warn: apk add with BuildKit tmpfs mount" $
+      let line = "RUN --mount=type=tmpfs,target=/var/cache/apk apk add -U curl=7.77.0"
+      in do
+        ruleCatchesNot "DL3019" line
+        onBuildRuleCatchesNot "DL3019" line
+
+    it "don't warn: apk add with BuildKit cache mount in wrong dir and --no-cache" $
+      let line = "RUN --mount=type=cache,target=/var/cache/foo apk add --no-cache -U curl=7.77.0"
+      in do
+        ruleCatchesNot "DL3019" line
+        onBuildRuleCatchesNot "DL3019" line
+
+    it "warn: apk add with BuildKit cache mount to wrong dir" $
+      let line = "RUN --mount=type=cache,target=/var/cache/foo apk add -U curl=7.77.0"
+      in do
+        ruleCatches "DL3019" line
+        onBuildRuleCatches "DL3019" line
+
+    it "warn: apk add with BuildKit tmpfs mount to wrong dir" $
+      let line = "RUN --mount=type=tmpfs,target=/var/cache/foo apk add -U curl=7.77.0"
+      in do
+        ruleCatches "DL3019" line
+        onBuildRuleCatches "DL3019" line
diff --git a/test/Hadolint/Rule/DL3033Spec.hs b/test/Hadolint/Rule/DL3033Spec.hs
--- a/test/Hadolint/Rule/DL3033Spec.hs
+++ b/test/Hadolint/Rule/DL3033Spec.hs
@@ -13,14 +13,29 @@
     it "not ok without yum version pinning" $ do
       ruleCatches "DL3033" "RUN yum install -y tomcat && yum clean all"
       onBuildRuleCatches "DL3033" "RUN yum install -y tomcat && yum clean all"
+
     it "ok with yum version pinning" $ do
       ruleCatchesNot "DL3033" "RUN yum install -y tomcat-9.2 && yum clean all"
       ruleCatchesNot "DL3033" "RUN bash -c `# not even a yum command`"
       onBuildRuleCatchesNot "DL3033" "RUN yum install -y tomcat-9.2 && yum clean all"
       onBuildRuleCatchesNot "DL3033" "RUN bash -c `# not even a yum command`"
+
+    it "ok with yum version pinning - version contains epoch" $ do
+      ruleCatchesNot "DL3033" "RUN yum install -y openssl-1:1.1.1k"
+      onBuildRuleCatchesNot "DL3033" "RUN yum install -y openssl-1:1.1.1k"
+
+    it "ok with yum version pinning - package name contains `-`" $ do
+      ruleCatchesNot "DL3033" "RUN yum install -y rpm-sign-4.16.1.3"
+      onBuildRuleCatchesNot "DL3033" "RUN yum install -y rpm-sign-4.16.1.3"
+
+    it "ok with yum version pinning - package name contains `-` and `+`" $ do
+      ruleCatchesNot "DL3033" "RUN yum install -y gcc-c++-1.1.1"
+      onBuildRuleCatchesNot "DL3033" "RUN yum install -y gcc-c++-1.1.1"
+
     it "not ok without yum version pinning - modules" $ do
       ruleCatches "DL3033" "RUN yum module install -y tomcat && yum clean all"
       onBuildRuleCatches "DL3033" "RUN yum module install -y tomcat && yum clean all"
+
     it "ok with yum version pinning - modules" $ do
       ruleCatchesNot "DL3033" "RUN yum module install -y tomcat:9 && yum clean all"
       ruleCatchesNot "DL3033" "RUN bash -c `# not even a yum command`"
diff --git a/test/Hadolint/Rule/DL3036Spec.hs b/test/Hadolint/Rule/DL3036Spec.hs
--- a/test/Hadolint/Rule/DL3036Spec.hs
+++ b/test/Hadolint/Rule/DL3036Spec.hs
@@ -10,11 +10,25 @@
   let ?config = def
 
   describe "DL3036 - `zypper clean` missing after zypper use." $ do
+
     it "not ok without zypper clean" $ do
       ruleCatches "DL3036" "RUN zypper install -y mariadb=10.4"
       onBuildRuleCatches "DL3036" "RUN zypper install -y mariadb=10.4"
+
     it "ok with zypper clean" $ do
       ruleCatchesNot "DL3036" "RUN zypper install -y mariadb=10.4 && zypper clean"
       ruleCatchesNot "DL3036" "RUN zypper install -y mariadb=10.4 && zypper cc"
       onBuildRuleCatchesNot "DL3036" "RUN zypper install -y mariadb=10.4 && zypper clean"
       onBuildRuleCatchesNot "DL3036" "RUN zypper install -y mariadb=10.4 && zypper cc"
+
+    it "ok when mount type cache is used" $
+      let line = "RUN --mount=type=cache,target=/var/cache/zypp zypper install -y mariadb"
+      in do
+        ruleCatchesNot "DL3036" line
+        onBuildRuleCatchesNot "DL3036" line
+
+    it "ok when mount type tmpfs is used" $
+      let line = "RUN --mount=type=tmpfs,target=/var/cache/zypp zypper install -y mariadb"
+      in do
+        ruleCatchesNot "DL3036" line
+        onBuildRuleCatchesNot "DL3036" line
diff --git a/test/Hadolint/Rule/DL3040Spec.hs b/test/Hadolint/Rule/DL3040Spec.hs
--- a/test/Hadolint/Rule/DL3040Spec.hs
+++ b/test/Hadolint/Rule/DL3040Spec.hs
@@ -24,7 +24,18 @@
       onBuildRuleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && microdnf clean all"
       onBuildRuleCatchesNot "DL3040" "RUN notdnf install mariadb"
     it "ok with rm /var/cache/yum" $ do
-      ruleCatchesNot "DL3040" "RUN dnf install -y mariadb-10.4 && rm -rf /var/cache/yum/*"
-      ruleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && rm -rf /var/cache/yum/*"
-      onBuildRuleCatchesNot "DL3040" "RUN dnf install -y mariadb-10.4 && rm -rf /var/cache/yum/*"
-      onBuildRuleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && rm -rf /var/cache/yum/*"
+      ruleCatchesNot "DL3040" "RUN dnf install -y mariadb-10.4 && rm -rf /var/cache/libdnf5"
+      ruleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && rm -rf /var/cache/libdnf5"
+      onBuildRuleCatchesNot "DL3040" "RUN dnf install -y mariadb-10.4 && rm -rf /var/cache/libdnf5"
+      onBuildRuleCatchesNot "DL3040" "RUN microdnf install -y mariadb-10.4 && rm -rf /var/cache/libdnf5"
+
+    it "ok with cache mount at /var/cache/yum" $ do
+      ruleCatchesNot "DL3040" "RUN --mount=type=cache,target=/var/cache/libdnf5 dnf install -y mariadb-10.4"
+      ruleCatchesNot "DL3040" "RUN --mount=type=cache,target=/var/cache/libdnf5 microdnf install -y mariadb-10.4"
+      onBuildRuleCatchesNot "DL3040" "RUN --mount=type=cache,target=/var/cache/libdnf5 dnf install -y mariadb-10.4"
+      onBuildRuleCatchesNot "DL3040" "RUN --mount=type=cache,target=/var/cache/libdnf5 microdnf install -y mariadb-10.4"
+    it "ok with tmpfs mount at /var/cache/yum" $ do
+      ruleCatchesNot "DL3040" "RUN --mount=type=tmpfs,target=/var/cache/libdnf5 dnf install -y mariadb-10.4"
+      ruleCatchesNot "DL3040" "RUN --mount=type=tmpfs,target=/var/cache/libdnf5 microdnf install -y mariadb-10.4"
+      onBuildRuleCatchesNot "DL3040" "RUN --mount=type=tmpfs,target=/var/cache/libdnf5 dnf install -y mariadb-10.4"
+      onBuildRuleCatchesNot "DL3040" "RUN --mount=type=tmpfs,target=/var/cache/libdnf5 microdnf install -y mariadb-10.4"
diff --git a/test/Hadolint/Rule/DL3041Spec.hs b/test/Hadolint/Rule/DL3041Spec.hs
--- a/test/Hadolint/Rule/DL3041Spec.hs
+++ b/test/Hadolint/Rule/DL3041Spec.hs
@@ -10,32 +10,54 @@
   let ?config = def
 
   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 "not ok without dnf version pinning - package name with `-`" $ do
       ruleCatches "DL3041" "RUN dnf install -y rpm-sign && dnf clean all"
       ruleCatches "DL3041" "RUN microdnf install -y rpm-sign && microdnf clean all"
       onBuildRuleCatches "DL3041" "RUN dnf install -y rpm-sign && 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"
+
+    it "ok with version pinning if command is not `dnf` or `microdnf`" $ do
+      ruleCatchesNot "DL3041" "RUN notdnf install openssl-1:1.1.1k"
+      onBuildRuleCatchesNot "DL3041" "RUN notdnf install openssl-1:1.1.1k"
+
+    it "ok without version pinning if command is not `dnf` or `microdnf`" $ do
+      ruleCatchesNot "DL3041" "RUN notdnf install tomcat"
       onBuildRuleCatchesNot "DL3041" "RUN notdnf install tomcat"
+
     it "ok with dnf version pinning - package name with `-`" $ do
       ruleCatchesNot "DL3041" "RUN dnf install -y rpm-sign-4.16.1.3 && dnf clean all"
       ruleCatchesNot "DL3041" "RUN microdnf install -y rpm-sign-4.16.1.3 && microdnf clean all"
-      ruleCatchesNot "DL3041" "RUN notdnf install rpm-sign"
       onBuildRuleCatchesNot "DL3041" "RUN dnf install -y rpm-sign-4.16.1.3 && dnf clean all"
       onBuildRuleCatchesNot "DL3041" "RUN microdnf install -y rpm-sign-4.16.1.3 && microdnf clean all"
-      onBuildRuleCatchesNot "DL3041" "RUN notdnf install rpm-sign"
+
+    it "ok with dnf version pinning - package name with `-` and `+`" $ do
+      ruleCatchesNot "DL3041" "RUN dnf install -y gcc-c++-1.1.1"
+      ruleCatchesNot "DL3041" "RUN microdnf install -y gcc-c++-1.1.1"
+      onBuildRuleCatchesNot "DL3041" "RUN dnf install -y gcc-c++-1.1.1"
+      onBuildRuleCatchesNot "DL3041" "RUN microdnf install -y gcc-c++-1.1.1"
+
+    it "ok with dnf version pinning - package version with epoch" $ do
+      ruleCatchesNot "DL3041" "RUN dnf install -y openssl-1:1.1.1k"
+      ruleCatchesNot "DL3041" "RUN microdnf install -y openssl-1:1.1.1k"
+      onBuildRuleCatchesNot "DL3041" "RUN dnf install -y openssl-1:1.1.1k"
+      onBuildRuleCatchesNot "DL3041" "RUN microdnf install -y openssl-1:1.1.1k"
+
     it "not ok without dnf version pinning - modules" $ 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"
diff --git a/test/Hadolint/Rule/DL3042Spec.hs b/test/Hadolint/Rule/DL3042Spec.hs
--- a/test/Hadolint/Rule/DL3042Spec.hs
+++ b/test/Hadolint/Rule/DL3042Spec.hs
@@ -86,3 +86,15 @@
             ]
        in do
         ruleCatches "DL3042" dockerFile
+
+    it "ok with cache mount in cache dir" $
+      let line = "RUN --mount=type=cache,target=/root/.cache/pip pip install foobar"
+      in do
+        ruleCatchesNot "DL3042" line
+        onBuildRuleCatchesNot "DL3042" line
+
+    it "ok with tmpfs mount in cache dir" $
+      let line = "RUN --mount=type=tmpfs,target=/root/.cache/pip pip install foobar"
+      in do
+        ruleCatchesNot "DL3042" line
+        onBuildRuleCatchesNot "DL3042" line
diff --git a/test/Hadolint/Rule/DL3060Spec.hs b/test/Hadolint/Rule/DL3060Spec.hs
--- a/test/Hadolint/Rule/DL3060Spec.hs
+++ b/test/Hadolint/Rule/DL3060Spec.hs
@@ -21,6 +21,30 @@
       ruleCatchesNot "DL3060" "RUN yarn install bar && yarn cache clean"
       onBuildRuleCatchesNot "DL3060" "RUN yarn install bar && yarn cache clean"
 
+    it "ok when cache mount is used" $
+      let line = "RUN --mount=type=cache,target=/root/.cache/yarn yarn install foobar"
+      in do
+        ruleCatchesNot "DL3060" line
+        onBuildRuleCatchesNot "DL3060" line
+
+    it "ok when tmpfs mount is used" $
+      let line = "RUN --mount=type=tmpfs,target=/root/.cache/yarn yarn install foobar"
+      in do
+        ruleCatchesNot "DL3060" line
+        onBuildRuleCatchesNot "DL3060" line
+
+    it "not ok when cache mount is in wrong location" $
+      let line = "RUN --mount=type=cache,target=/var/lib/foobar yarn install foobar"
+      in do
+        ruleCatches "DL3060" line
+        onBuildRuleCatches "DL3060" line
+
+    it "not ok when tmpfs mount is in wrong location" $
+      let line = "RUN --mount=type=tmpfs,target=/var/lib/foobar yarn install foobar"
+      in do
+        ruleCatches "DL3060" line
+        onBuildRuleCatches "DL3060" line
+
     it "not ok when yarn install is in last stage w/o yarn clean" $
       let dockerFile =
             Text.unlines
diff --git a/test/Hadolint/Rule/DL3062Spec.hs b/test/Hadolint/Rule/DL3062Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Hadolint/Rule/DL3062Spec.hs
@@ -0,0 +1,41 @@
+module Hadolint.Rule.DL3062Spec (spec) where
+
+import Data.Default
+import Helpers
+import Test.Hspec
+
+spec :: SpecWith ()
+spec = do
+  let ?config = def
+
+  describe "DL3062 - Pin versions in go install." $ do
+    describe "go install" $ do
+      it "go version not pinned" $ do
+        ruleCatches "DL3062" "RUN go install example.com/pkg"
+        onBuildRuleCatches "DL3062" "RUN go install example.com/pkg"
+      it "go version pinned as latest" $ do
+        ruleCatches "DL3062" "RUN go install example.com/pkg@latest"
+        onBuildRuleCatches "DL3062" "RUN go install example.com/pkg@latest"
+      it "go version pinned" $ do
+        ruleCatchesNot "DL3062" "RUN go install example.com/pkg@v1.2.3"
+        onBuildRuleCatchesNot "DL3062" "RUN go install example.com/pkg@v1.2.3"
+    describe "go get" $ do
+      it "go version not pinned" $ do
+        ruleCatches "DL3062" "RUN go get example.com/pkg"
+        onBuildRuleCatches "DL3062" "RUN go get example.com/pkg"
+      it "go version pinned as latest" $ do
+        ruleCatches "DL3062" "RUN go get example.com/pkg@latest"
+        onBuildRuleCatches "DL3062" "RUN go get example.com/pkg@latest"
+      it "go version pinned" $ do
+        ruleCatchesNot "DL3062" "RUN go get example.com/pkg@v1.2.3"
+        onBuildRuleCatchesNot "DL3062" "RUN go get example.com/pkg@v1.2.3"
+    describe "go run" $ do
+      it "go version not pinned" $ do
+        ruleCatches "DL3062" "RUN go run example.com/pkg"
+        onBuildRuleCatches "DL3062" "RUN go run example.com/pkg"
+      it "go version pinned as latest" $ do
+        ruleCatches "DL3062" "RUN go run example.com/pkg@latest"
+        onBuildRuleCatches "DL3062" "RUN go run example.com/pkg@latest"
+      it "go version pinned" $ do
+        ruleCatchesNot "DL3062" "RUN go run example.com/pkg@v1.2.3"
+        onBuildRuleCatchesNot "DL3062" "RUN go run example.com/pkg@v1.2.3"
