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 {count :: Int, names :: Set.Set Text.Text} | Empty deriving (Eq) rule :: Rule args rule = customRule check (emptyState Empty) where code = "DL3022" severity = DLWarningC message = "`COPY --from` should reference a previously defined `FROM` alias" check _ st (From BaseImage {alias = Just (ImageAlias als)}) = st |> modify (incAndAddName als) check _ st (From BaseImage {}) = st |> modify incCount check line st (Copy (CopyArgs _ _) (CopyFlags _ _ _ (CopySource s) _)) | ":" `Text.isInfixOf` dropQuotes s = st | isMember s (state st) = st | otherwise = case Read.decimal s of Right (v, _) | v < nameCount (state st) -> st _ -> st |> addFail CheckFailure {..} check _ st _ = st {-# INLINEABLE rule #-} incAndAddName :: Text.Text -> Acc -> Acc incAndAddName s Empty = Acc {count = 1, names = Set.singleton s} incAndAddName s Acc {count, names} = Acc {count = count + 1, names = Set.insert s names} incCount :: Acc -> Acc incCount Empty = Acc {count = 1, names = Set.empty} incCount Acc {count, names} = Acc {count = count + 1, names = names} isMember :: Text.Text -> Acc -> Bool isMember _ Empty = False isMember s Acc {names} = Set.member s names nameCount :: Acc -> Int nameCount Empty = 0 nameCount Acc {count} = count