packages feed

hadolint-2.15.0: src/Hadolint/Rule/DL3026.hs

module Hadolint.Rule.DL3026 (rule) where

import qualified Data.Maybe as Maybe
import qualified Data.Set as Set
import Data.String ( IsString(..) )
import Data.Text (Text, pack, unpack, drop, dropEnd, isSuffixOf, isPrefixOf)
import Hadolint.Rule
import Language.Docker.Syntax

rule :: Set.Set Registry -> Rule args
rule allowed = customRule check (emptyState Set.empty)
  where
    code = "DL3026"
    severity = DLErrorC
    message = "Use only an allowed registry in the FROM image"

    check line st (From BaseImage {image, alias}) =
      let newState = st |> modify (Set.insert alias)
       in if doCheck (state st) image
            then newState
            else newState |> addFail CheckFailure {..}
    check line st (Copy _ (CopyFlags _ _ _ _ (CopySource src) _)) =
      let img = fromString ( Data.Text.unpack src )
       in if doCheck (state st) img
            then st
            else st |> addFail CheckFailure {..}
    check line st (Run (RunArgs _ (RunFlags m _ _))) =
       if null $ Set.filter (not . checkMount st) m
         then st
         else st |> addFail CheckFailure {..}
    check _ st _ = st

    checkMount st (CacheMount (CacheOpts _ _ _ _ fi _ _ _ _)) =
      let img = fromString $ unpack $ Maybe.fromMaybe "scratch" fi
       in doCheck (state st) img
    checkMount st (BindMount (BindOpts _ _ fi _ _)) =
      let img = fromString $ unpack $ Maybe.fromMaybe "scratch" fi
       in doCheck (state st) img
    checkMount _ _ = True

    doCheck st img = Set.member (toImageAlias img) st || Set.null allowed || isAllowed img

    toImageAlias = Just . ImageAlias . imageName
    isAllowed Image {registryName = Just registry} = isRegistryAllowed (unRegistry registry)
    isAllowed Image {registryName = Nothing, imageName} =
      imageName == "scratch"
        || isRegistryAllowed "docker.io"
        || isRegistryAllowed "hub.docker.com"

    isRegistryAllowed registry = any (\p -> matchRegistry (unRegistry p) registry) allowed
{-# INLINEABLE rule #-}

matchRegistry :: Text -> Text -> Bool
matchRegistry allow registry
  | allow == star = True
  | star `isPrefixOf` allow = Data.Text.drop 1 allow `isSuffixOf` registry
  | star `isSuffixOf` allow = Data.Text.dropEnd 1 allow `isPrefixOf` registry
  | otherwise = registry == allow
  where
      star = pack "*"