hadolint-2.0.0: src/Hadolint/Rule/DL3002.hs
module Hadolint.Rule.DL3002 (rule) where
import qualified Data.IntMap.Strict as Map
import qualified Data.Sequence as Seq
import qualified Data.Text as Text
import Hadolint.Rule
import Language.Docker.Syntax (Instruction (..), Linenumber)
type StageLine = Linenumber
type UserLine = Linenumber
data Acc
= Acc StageLine (Map.IntMap UserLine)
| Empty
deriving (Show)
rule :: Rule args
rule = veryCustomRule check (emptyState Empty) markFailures
where
code = "DL3002"
severity = DLWarningC
message = "Last USER should not be root"
check line st (From _) = st |> modify (rememberStage line)
check line st (User user)
| not (isRoot user) = st |> modify forgetStage
| otherwise = st |> modify (rememberLine line)
check _ st _ = st
isRoot user =
Text.isPrefixOf "root:" user || Text.isPrefixOf "0:" user || user == "root" || user == "0"
markFailures (State fails (Acc _ st)) = Map.foldl' (Seq.|>) fails (fmap makeFail st)
markFailures st = failures st
makeFail line = CheckFailure {..}
{-# INLINEABLE rule #-}
rememberStage :: StageLine -> Acc -> Acc
rememberStage from (Acc _ m) = Acc from m
rememberStage from Empty = Acc from Map.empty
forgetStage :: Acc -> Acc
forgetStage (Acc from m) = Acc from (m |> Map.delete from)
forgetStage Empty = Empty
rememberLine :: StageLine -> Acc -> Acc
rememberLine line (Acc from m) = Acc from (m |> Map.insert from line)
rememberLine _ Empty = Empty