module Hadolint.Rule.DL3057 (rule) where import qualified Data.Sequence as Seq import qualified Data.Set as Set import qualified Data.Text as Text import Hadolint.Rule import Language.Docker.Syntax data StageID = StageID { StageID -> Text name :: Text.Text, StageID -> Linenumber line :: Linenumber } deriving (Linenumber -> StageID -> ShowS [StageID] -> ShowS StageID -> String (Linenumber -> StageID -> ShowS) -> (StageID -> String) -> ([StageID] -> ShowS) -> Show StageID forall a. (Linenumber -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a showList :: [StageID] -> ShowS $cshowList :: [StageID] -> ShowS show :: StageID -> String $cshow :: StageID -> String showsPrec :: Linenumber -> StageID -> ShowS $cshowsPrec :: Linenumber -> StageID -> ShowS Show, StageID -> StageID -> Bool (StageID -> StageID -> Bool) -> (StageID -> StageID -> Bool) -> Eq StageID forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a /= :: StageID -> StageID -> Bool $c/= :: StageID -> StageID -> Bool == :: StageID -> StageID -> Bool $c== :: StageID -> StageID -> Bool Eq, Eq StageID Eq StageID -> (StageID -> StageID -> Ordering) -> (StageID -> StageID -> Bool) -> (StageID -> StageID -> Bool) -> (StageID -> StageID -> Bool) -> (StageID -> StageID -> Bool) -> (StageID -> StageID -> StageID) -> (StageID -> StageID -> StageID) -> Ord StageID StageID -> StageID -> Bool StageID -> StageID -> Ordering StageID -> StageID -> StageID forall a. Eq a -> (a -> a -> Ordering) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> a) -> (a -> a -> a) -> Ord a min :: StageID -> StageID -> StageID $cmin :: StageID -> StageID -> StageID max :: StageID -> StageID -> StageID $cmax :: StageID -> StageID -> StageID >= :: StageID -> StageID -> Bool $c>= :: StageID -> StageID -> Bool > :: StageID -> StageID -> Bool $c> :: StageID -> StageID -> Bool <= :: StageID -> StageID -> Bool $c<= :: StageID -> StageID -> Bool < :: StageID -> StageID -> Bool $c< :: StageID -> StageID -> Bool compare :: StageID -> StageID -> Ordering $ccompare :: StageID -> StageID -> Ordering $cp1Ord :: Eq StageID Ord) data Acc = Acc StageID (Set.Set StageID) (Set.Set StageID) | Empty deriving (Linenumber -> Acc -> ShowS [Acc] -> ShowS Acc -> String (Linenumber -> Acc -> ShowS) -> (Acc -> String) -> ([Acc] -> ShowS) -> Show Acc forall a. (Linenumber -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a showList :: [Acc] -> ShowS $cshowList :: [Acc] -> ShowS show :: Acc -> String $cshow :: Acc -> String showsPrec :: Linenumber -> Acc -> ShowS $cshowsPrec :: Linenumber -> Acc -> ShowS Show) rule :: Rule args rule :: Rule args rule = (Linenumber -> State Acc -> Instruction args -> State Acc) -> State Acc -> (State Acc -> Failures) -> Rule args forall a args. (Linenumber -> State a -> Instruction args -> State a) -> State a -> (State a -> Failures) -> Rule args veryCustomRule Linenumber -> State Acc -> Instruction args -> State Acc forall args. Linenumber -> State Acc -> Instruction args -> State Acc check (Acc -> State Acc forall a. a -> State a emptyState Acc Empty) State Acc -> Failures markFailures where code :: RuleCode code = RuleCode "DL3057" severity :: DLSeverity severity = DLSeverity DLIgnoreC message :: Text message = Text "`HEALTHCHECK` instruction missing." check :: Linenumber -> State Acc -> Instruction args -> State Acc check Linenumber line State Acc state (From BaseImage {Image $sel:image:BaseImage :: BaseImage -> Image image :: Image image, $sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias alias = Just ImageAlias als}) = State Acc state State Acc -> (State Acc -> State Acc) -> State Acc forall a b. a -> (a -> b) -> b |> (Acc -> Acc) -> State Acc -> State Acc forall a. (a -> a) -> State a -> State a modify (Text -> StageID -> Acc -> Acc currentStage (Image -> Text imageName Image image) (Text -> Linenumber -> StageID StageID (ImageAlias -> Text unImageAlias ImageAlias als) Linenumber line)) check Linenumber line State Acc state (From BaseImage {Image image :: Image $sel:image:BaseImage :: BaseImage -> Image image, $sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias alias = Maybe ImageAlias Nothing}) = State Acc state State Acc -> (State Acc -> State Acc) -> State Acc forall a b. a -> (a -> b) -> b |> (Acc -> Acc) -> State Acc -> State Acc forall a. (a -> a) -> State a -> State a modify (Text -> StageID -> Acc -> Acc currentStage (Image -> Text imageName Image image) (Text -> Linenumber -> StageID StageID (Image -> Text imageName Image image) Linenumber line)) check Linenumber _ State Acc state (Healthcheck Check args _) = State Acc state State Acc -> (State Acc -> State Acc) -> State Acc forall a b. a -> (a -> b) -> b |> (Acc -> Acc) -> State Acc -> State Acc forall a. (a -> a) -> State a -> State a modify Acc -> Acc goodStage check Linenumber _ State Acc state Instruction args _ = State Acc state markFailures :: State Acc -> Failures markFailures :: State Acc -> Failures markFailures (State Failures fails (Acc StageID _ Set StageID _ Set StageID b)) = (Failures -> CheckFailure -> Failures) -> Failures -> Set CheckFailure -> Failures forall a b. (a -> b -> a) -> a -> Set b -> a Set.foldl' Failures -> CheckFailure -> Failures forall a. Seq a -> a -> Seq a (Seq.|>) Failures fails ((StageID -> CheckFailure) -> Set StageID -> Set CheckFailure forall b a. Ord b => (a -> b) -> Set a -> Set b Set.map StageID -> CheckFailure makeFail Set StageID b) markFailures State Acc st = State Acc -> Failures forall a. State a -> Failures failures State Acc st makeFail :: StageID -> CheckFailure makeFail (StageID Text _ Linenumber line) = CheckFailure :: RuleCode -> DLSeverity -> Text -> Linenumber -> CheckFailure CheckFailure {Linenumber Text RuleCode DLSeverity line :: Linenumber message :: Text severity :: DLSeverity code :: RuleCode line :: Linenumber message :: Text severity :: DLSeverity code :: RuleCode ..} {-# INLINEABLE rule #-} currentStage :: Text.Text -> StageID -> Acc -> Acc currentStage :: Text -> StageID -> Acc -> Acc currentStage Text src StageID stageid (Acc StageID _ Set StageID g Set StageID b) | Bool -> Bool not (Bool -> Bool) -> Bool -> Bool forall a b. (a -> b) -> a -> b $ Set StageID -> Bool forall a. Set a -> Bool Set.null ((StageID -> Bool) -> Set StageID -> Set StageID forall a. (a -> Bool) -> Set a -> Set a Set.filter (Text -> StageID -> Bool predicate Text src) Set StageID g) = StageID -> Set StageID -> Set StageID -> Acc Acc StageID stageid (Set StageID g Set StageID -> (Set StageID -> Set StageID) -> Set StageID forall a b. a -> (a -> b) -> b |> StageID -> Set StageID -> Set StageID forall a. Ord a => a -> Set a -> Set a Set.insert StageID stageid) Set StageID b | Bool otherwise = StageID -> Set StageID -> Set StageID -> Acc Acc StageID stageid Set StageID g (Set StageID b Set StageID -> (Set StageID -> Set StageID) -> Set StageID forall a b. a -> (a -> b) -> b |> StageID -> Set StageID -> Set StageID forall a. Ord a => a -> Set a -> Set a Set.insert StageID stageid) where predicate :: Text -> StageID -> Bool predicate Text n0 StageID {name :: StageID -> Text name = Text n1} = Text n1 Text -> Text -> Bool forall a. Eq a => a -> a -> Bool == Text n0 currentStage Text _ StageID stageid Acc Empty = StageID -> Set StageID -> Set StageID -> Acc Acc StageID stageid Set StageID forall a. Set a Set.empty (StageID -> Set StageID forall a. a -> Set a Set.singleton StageID stageid) goodStage :: Acc -> Acc goodStage :: Acc -> Acc goodStage (Acc StageID stageid Set StageID g Set StageID b) = StageID -> Set StageID -> Set StageID -> Acc Acc StageID stageid (Set StageID g Set StageID -> (Set StageID -> Set StageID) -> Set StageID forall a b. a -> (a -> b) -> b |> StageID -> Set StageID -> Set StageID forall a. Ord a => a -> Set a -> Set a Set.insert StageID stageid) (Set StageID b Set StageID -> (Set StageID -> Set StageID) -> Set StageID forall a b. a -> (a -> b) -> b |> StageID -> Set StageID -> Set StageID forall a. Ord a => a -> Set a -> Set a Set.delete StageID stageid) goodStage Acc Empty = Acc Empty