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 :: Rule ParsedShell rule = Rule ParsedShell dl3062 Rule ParsedShell -> Rule ParsedShell -> Rule ParsedShell forall a. Semigroup a => a -> a -> a <> Rule ParsedShell -> Rule ParsedShell forall args. Rule args -> Rule args onbuild Rule ParsedShell dl3062 {-# INLINEABLE rule #-} dl3062 :: Rule Shell.ParsedShell dl3062 :: Rule ParsedShell dl3062 = RuleCode -> DLSeverity -> Text -> (Instruction ParsedShell -> Bool) -> Rule ParsedShell forall args. RuleCode -> DLSeverity -> Text -> (Instruction args -> Bool) -> Rule args simpleRule RuleCode code DLSeverity severity Text message Instruction ParsedShell -> Bool check where code :: RuleCode code = RuleCode "DL3062" severity :: DLSeverity severity = DLSeverity DLWarningC message :: Text message = Text "Pin versions in go. Instead of `go install <package>` use `go install <package>@<version>`" check :: Instruction ParsedShell -> Bool check (Run (RunArgs Arguments ParsedShell args RunFlags _)) = (ParsedShell -> Bool) -> Arguments ParsedShell -> Bool forall a b. (a -> b) -> Arguments a -> b foldArguments ((Text -> Bool) -> [Text] -> Bool forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool all Text -> Bool checkGoPackageVersion ([Text] -> Bool) -> (ParsedShell -> [Text]) -> ParsedShell -> Bool forall b c a. (b -> c) -> (a -> b) -> a -> c . ParsedShell -> [Text] getGoPackage) Arguments ParsedShell args check Instruction ParsedShell _ = Bool True {-# INLINEABLE dl3062 #-} goCommands :: [Text.Text] goCommands :: [Text] goCommands = [Text "install", Text "get", Text "run"] isGoCommand :: Shell.Command -> Bool isGoCommand :: Command -> Bool isGoCommand = [Text] -> [Text] -> Command -> Bool Shell.cmdsHaveArgs [Text "go"] [Text] goCommands getGoPackage :: Shell.ParsedShell -> [Text.Text] getGoPackage :: ParsedShell -> [Text] getGoPackage ParsedShell args = [ Text arg | Command cmd <- ParsedShell -> [Command] Shell.presentCommands ParsedShell args, Command -> Bool isGoCommand Command cmd, Text arg <- Command -> [Text] Shell.getArgsNoFlags Command cmd, Text arg Text -> [Text] -> Bool forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool `notElem` [Text] goCommands ] hasVersionSymbol :: Text.Text -> Bool hasVersionSymbol :: Text -> Bool hasVersionSymbol Text package = Text "@" Text -> Text -> Bool `Text.isInfixOf` Text package isTagsVersion :: Text.Text -> Bool isTagsVersion :: Text -> Bool isTagsVersion Text package = [Bool] -> Bool forall (t :: * -> *). Foldable t => t Bool -> Bool or [(Text "@" Text -> Text -> Text forall a. Semigroup a => a -> a -> a <> Text tag) Text -> Text -> Bool `Text.isSuffixOf` Text package | Text tag <- [Text "latest", Text "none"]] checkGoPackageVersion :: Text.Text -> Bool checkGoPackageVersion :: Text -> Bool checkGoPackageVersion Text package = Text -> Bool hasVersionSymbol Text package Bool -> Bool -> Bool && Bool -> Bool not (Text -> Bool isTagsVersion Text package)