module Hadolint.Rule.DL3022 (rule) where import Data.Set qualified as Set import Data.Text qualified as Text import Data.Text.Read qualified as Read import Hadolint.Rule import Language.Docker.Syntax data Acc = Acc {Acc -> Int count :: Int, Acc -> Set Text names :: Set.Set Text.Text} | Empty deriving (Acc -> Acc -> Bool (Acc -> Acc -> Bool) -> (Acc -> Acc -> Bool) -> Eq Acc forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: Acc -> Acc -> Bool == :: Acc -> Acc -> Bool $c/= :: Acc -> Acc -> Bool /= :: Acc -> Acc -> Bool Eq) rule :: Rule args rule :: forall args. Rule args rule = (Int -> State Acc -> Instruction args -> State Acc) -> State Acc -> Rule args forall a args. (Int -> State a -> Instruction args -> State a) -> State a -> Rule args customRule Int -> State Acc -> Instruction args -> State Acc forall {args}. Int -> State Acc -> Instruction args -> State Acc check (Acc -> State Acc forall a. a -> State a emptyState Acc Empty) where code :: RuleCode code = RuleCode "DL3022" severity :: DLSeverity severity = DLSeverity DLWarningC message :: Text message = Text "`COPY --from` should reference a previously defined `FROM` alias" check :: Int -> State Acc -> Instruction args -> State Acc check Int _ State Acc st (From BaseImage {alias :: BaseImage -> Maybe ImageAlias alias = Just (ImageAlias Text als)}) = State Acc st 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 -> Acc -> Acc incAndAddName Text als) check Int _ State Acc st (From BaseImage {}) = State Acc st 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 incCount check Int line State Acc st (Copy (CopyArgs NonEmpty SourcePath _ TargetPath _) (CopyFlags Chown _ Chmod _ Link _ (CopySource Text s) [Exclude] _)) | Text ":" Text -> Text -> Bool `Text.isInfixOf` Text -> Text dropQuotes Text s = State Acc st | Text -> Acc -> Bool isMember Text s (State Acc -> Acc forall a. State a -> a state State Acc st) = State Acc st | Bool otherwise = case Reader Int forall a. Integral a => Reader a Read.decimal Text s of Right (Int v, Text _) | Int v Int -> Int -> Bool forall a. Ord a => a -> a -> Bool < Acc -> Int nameCount (State Acc -> Acc forall a. State a -> a state State Acc st) -> State Acc st Either String (Int, Text) _ -> State Acc st State Acc -> (State Acc -> State Acc) -> State Acc forall a b. a -> (a -> b) -> b |> CheckFailure -> State Acc -> State Acc forall a. CheckFailure -> State a -> State a addFail CheckFailure {Int Text RuleCode DLSeverity code :: RuleCode severity :: DLSeverity message :: Text line :: Int line :: Int message :: Text severity :: DLSeverity code :: RuleCode ..} check Int _ State Acc st Instruction args _ = State Acc st {-# INLINEABLE rule #-} incAndAddName :: Text.Text -> Acc -> Acc incAndAddName :: Text -> Acc -> Acc incAndAddName Text s Acc Empty = Acc {count :: Int count = Int 1, names :: Set Text names = Text -> Set Text forall a. a -> Set a Set.singleton Text s} incAndAddName Text s Acc {Int count :: Acc -> Int count :: Int count, Set Text names :: Acc -> Set Text names :: Set Text names} = Acc {count :: Int count = Int count Int -> Int -> Int forall a. Num a => a -> a -> a + Int 1, names :: Set Text names = Text -> Set Text -> Set Text forall a. Ord a => a -> Set a -> Set a Set.insert Text s Set Text names} incCount :: Acc -> Acc incCount :: Acc -> Acc incCount Acc Empty = Acc {count :: Int count = Int 1, names :: Set Text names = Set Text forall a. Set a Set.empty} incCount Acc {Int count :: Acc -> Int count :: Int count, Set Text names :: Acc -> Set Text names :: Set Text names} = Acc {count :: Int count = Int count Int -> Int -> Int forall a. Num a => a -> a -> a + Int 1, names :: Set Text names = Set Text names} isMember :: Text.Text -> Acc -> Bool isMember :: Text -> Acc -> Bool isMember Text _ Acc Empty = Bool False isMember Text s Acc {Set Text names :: Acc -> Set Text names :: Set Text names} = Text -> Set Text -> Bool forall a. Ord a => a -> Set a -> Bool Set.member Text s Set Text names nameCount :: Acc -> Int nameCount :: Acc -> Int nameCount Acc Empty = Int 0 nameCount Acc {Int count :: Acc -> Int count :: Int count} = Int count