module Hadolint.Rule.DL3049 (rule) where
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Sequence as Seq
import qualified Data.Text as Text
import Hadolint.Rule
import Language.Docker.Syntax
rule :: LabelSchema -> Rule args
rule :: forall args. LabelSchema -> Rule args
rule LabelSchema
labelschema = forall a. Monoid a => [a] -> a
mconcat forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall args. Text -> Rule args
missingLabelRule (forall k a. Map k a -> [k]
Map.keys LabelSchema
labelschema)
{-# INLINEABLE rule #-}
data StageID = StageID
{ StageID -> BaseImage
name :: BaseImage,
StageID -> Linenumber
line :: Linenumber
} deriving (StageID -> StageID -> Bool
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
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
Ord, Linenumber -> StageID -> ShowS
[StageID] -> ShowS
StageID -> String
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)
data Acc
= Acc StageID (Set.Set StageID) (Set.Set StageID) (Set.Set StageID)
| Empty
deriving (Linenumber -> Acc -> ShowS
[Acc] -> ShowS
Acc -> String
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)
missingLabelRule :: LabelName -> Rule args
missingLabelRule :: forall args. Text -> Rule args
missingLabelRule Text
label = forall a args.
(Linenumber -> State a -> Instruction args -> State a)
-> State a -> (State a -> Seq CheckFailure) -> Rule args
veryCustomRule forall {args}.
Linenumber -> State Acc -> Instruction args -> State Acc
check (forall a. a -> State a
emptyState Acc
Empty) State Acc -> Seq CheckFailure
markFailure
where
code :: RuleCode
code = RuleCode
"DL3049"
severity :: DLSeverity
severity = DLSeverity
DLInfoC
message :: Text
message = Text
"Label `" forall a. Semigroup a => a -> a -> a
<> Text
label forall a. Semigroup a => a -> a -> a
<> Text
"` is missing."
check :: Linenumber -> State Acc -> Instruction args -> State Acc
check Linenumber
line State Acc
state (From BaseImage
img) =
State Acc
state forall a b. a -> (a -> b) -> b
|> forall a. (a -> a) -> State a -> State a
modify (StageID -> Acc -> Acc
currentStage (BaseImage -> Linenumber -> StageID
StageID BaseImage
img Linenumber
line))
check Linenumber
_ State Acc
state (Copy (CopyArgs NonEmpty SourcePath
_ TargetPath
_) (CopyFlags Chown
_ Chmod
_ Link
_ (CopySource Text
src))) =
State Acc
state forall a b. a -> (a -> b) -> b
|> forall a. (a -> a) -> State a -> State a
modify (Text -> Acc -> Acc
markSilentByAlias Text
src)
check Linenumber
_ State Acc
state (Label Pairs
pairs)
| Text
label forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst Pairs
pairs =
State Acc
state
forall a b. a -> (a -> b) -> b
|> forall a. (a -> a) -> State a -> State a
modify (Text -> Acc -> Acc
markSilentByAlias (State Acc -> Text
getCurrentStageName State Acc
state))
forall a b. a -> (a -> b) -> b
|> forall a. (a -> a) -> State a -> State a
modify Acc -> Acc
markGood
| Bool
otherwise = State Acc
state
check Linenumber
_ State Acc
state Instruction args
_ = State Acc
state
markFailure :: State Acc -> Failures
markFailure :: State Acc -> Seq CheckFailure
markFailure (State Seq CheckFailure
fails (Acc StageID
_ Set StageID
_ Set StageID
_ Set StageID
b)) = forall a b. (a -> b -> a) -> a -> Set b -> a
Set.foldl' forall a. Seq a -> a -> Seq a
(Seq.|>) Seq CheckFailure
fails (forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map StageID -> CheckFailure
markFail Set StageID
b)
markFailure State Acc
st = forall a. State a -> Seq CheckFailure
failures State Acc
st
markFail :: StageID -> CheckFailure
markFail (StageID BaseImage
_ Linenumber
line) = CheckFailure {Linenumber
Text
RuleCode
DLSeverity
line :: Linenumber
message :: Text
severity :: DLSeverity
code :: RuleCode
line :: Linenumber
message :: Text
severity :: DLSeverity
code :: RuleCode
..}
currentStage :: StageID -> Acc -> Acc
currentStage :: StageID -> Acc -> Acc
currentStage StageID
stageid Acc
Empty = StageID -> Set StageID -> Set StageID -> Set StageID -> Acc
Acc StageID
stageid forall a. Set a
Set.empty forall a. Set a
Set.empty (forall a. a -> Set a
Set.singleton StageID
stageid)
currentStage StageID
stageid (Acc StageID
_ Set StageID
g Set StageID
s Set StageID
b)
| Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall a. Set a -> Bool
Set.null (forall a. (a -> Bool) -> Set a -> Set a
Set.filter (StageID -> StageID -> Bool
predicate StageID
stageid) Set StageID
g) =
StageID -> Set StageID -> Set StageID -> Set StageID -> Acc
Acc StageID
stageid (Set StageID
g forall a b. a -> (a -> b) -> b
|> forall a. Ord a => a -> Set a -> Set a
Set.insert StageID
stageid) Set StageID
s Set StageID
b
| Bool
otherwise = StageID -> Set StageID -> Set StageID -> Set StageID -> Acc
Acc StageID
stageid Set StageID
g Set StageID
s (Set StageID
b forall a b. a -> (a -> b) -> b
|> forall a. Ord a => a -> Set a -> Set a
Set.insert StageID
stageid)
where
predicate :: StageID -> StageID -> Bool
predicate (StageID BaseImage
_ Linenumber
_) (StageID BaseImage {$sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias
alias = Maybe ImageAlias
Nothing} Linenumber
_) = Bool
False
predicate (StageID BaseImage {Image
$sel:image:BaseImage :: BaseImage -> Image
image :: Image
image} Linenumber
_) (StageID BaseImage {$sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias
alias = Just ImageAlias
als} Linenumber
_) =
ImageAlias -> Text
unImageAlias ImageAlias
als forall a. Eq a => a -> a -> Bool
== Image -> Text
imageName Image
image
markGood :: Acc -> Acc
markGood :: Acc -> Acc
markGood Acc
Empty = Acc
Empty
markGood (Acc StageID
stageid Set StageID
good Set StageID
silent Set StageID
bad) =
StageID -> Set StageID -> Set StageID -> Set StageID -> Acc
Acc StageID
stageid (Set StageID
good forall a b. a -> (a -> b) -> b
|> forall a. Ord a => a -> Set a -> Set a
Set.insert StageID
stageid) (Set StageID
silent forall a b. a -> (a -> b) -> b
|> forall a. Ord a => a -> Set a -> Set a
Set.delete StageID
stageid) (Set StageID
bad forall a b. a -> (a -> b) -> b
|> forall a. Ord a => a -> Set a -> Set a
Set.delete StageID
stageid)
markSilentByAlias :: Text.Text -> Acc -> Acc
markSilentByAlias :: Text -> Acc -> Acc
markSilentByAlias Text
_ Acc
Empty = Acc
Empty
markSilentByAlias Text
silentname (Acc StageID
stageid Set StageID
good Set StageID
silent Set StageID
bad) =
StageID -> Set StageID -> Set StageID -> Set StageID -> Acc
Acc StageID
stageid Set StageID
good (Set StageID
silent forall a b. a -> (a -> b) -> b
|> forall a. Ord a => Set a -> Set a -> Set a
Set.union Set StageID
stages) (Set StageID
bad forall a b. a -> (a -> b) -> b
|> forall a. Ord a => Set a -> Set a -> Set a
remove Set StageID
stages)
where
stages :: Set StageID
stages = forall a. (a -> Bool) -> Set a -> Set a
Set.filter StageID -> Bool
byName Set StageID
bad
byName :: StageID -> Bool
byName (StageID BaseImage {$sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias
alias = Maybe ImageAlias
Nothing} Linenumber
_) = Bool
False
byName (StageID BaseImage {$sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias
alias = Just ImageAlias
als} Linenumber
_) = ImageAlias -> Text
unImageAlias ImageAlias
als forall a. Eq a => a -> a -> Bool
== Text
silentname
remove :: Set a -> Set a -> Set a
remove Set a
set Set a
fromThis = forall a. Ord a => Set a -> Set a -> Set a
Set.difference Set a
fromThis Set a
set
getCurrentStageName :: State Acc -> Text.Text
getCurrentStageName :: State Acc -> Text
getCurrentStageName (State Seq CheckFailure
_ (Acc (StageID BaseImage {Image
image :: Image
$sel:image:BaseImage :: BaseImage -> Image
image, $sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias
alias = Maybe ImageAlias
Nothing} Linenumber
_) Set StageID
_ Set StageID
_ Set StageID
_)) = Image -> Text
imageName Image
image
getCurrentStageName (State Seq CheckFailure
_ (Acc (StageID BaseImage {$sel:alias:BaseImage :: BaseImage -> Maybe ImageAlias
alias = Just ImageAlias
als} Linenumber
_) Set StageID
_ Set StageID
_ Set StageID
_)) = ImageAlias -> Text
unImageAlias ImageAlias
als
getCurrentStageName State Acc
_ = Text
""