{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE OverloadedStrings #-} module Ecluse.Config.Types ( Url (..), mkUrl, unUrl, QueueBackend (..), parseQueueBackend, renderQueueBackend, CredentialBackend (..), parseCredentialBackend, renderCredentialBackend, MirrorCredentialProvider (..), parseMirrorCredentialProvider, renderMirrorCredentialProvider, MountConfig (..), AppConfig (..), MountRegistries (..), MirrorTarget (..), Mount (..), MountMap, Config (..), ConfigError (..), renderConfigError, ) where import Data.IP (IPRange) import Data.Text qualified as T import Data.Time (NominalDiffTime) import Ecluse.Config.Rule (PolicyError, RulePatch, renderPolicyError) import Ecluse.Core.Credential (Secret) import Ecluse.Core.Ecosystem (Ecosystem) import Ecluse.Core.Package (Scope) import Ecluse.Core.Package.Integrity (MinIntegrity, MinTrustedIntegrity) import Ecluse.Core.Rules.Types (PrecededRule) import Ecluse.Core.Security.Egress (RegistryUrl) import Ecluse.Core.Wire (WireVocab (..), parseWire, renderWire) import Ecluse.Log (LogFormat) import Ecluse.Telemetry (TelemetrySwitch) newtype Url = Url Text deriving stock (Url -> Url -> Bool (Url -> Url -> Bool) -> (Url -> Url -> Bool) -> Eq Url forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: Url -> Url -> Bool == :: Url -> Url -> Bool $c/= :: Url -> Url -> Bool /= :: Url -> Url -> Bool Eq, Eq Url Eq Url => (Url -> Url -> Ordering) -> (Url -> Url -> Bool) -> (Url -> Url -> Bool) -> (Url -> Url -> Bool) -> (Url -> Url -> Bool) -> (Url -> Url -> Url) -> (Url -> Url -> Url) -> Ord Url Url -> Url -> Bool Url -> Url -> Ordering Url -> Url -> Url 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 $ccompare :: Url -> Url -> Ordering compare :: Url -> Url -> Ordering $c< :: Url -> Url -> Bool < :: Url -> Url -> Bool $c<= :: Url -> Url -> Bool <= :: Url -> Url -> Bool $c> :: Url -> Url -> Bool > :: Url -> Url -> Bool $c>= :: Url -> Url -> Bool >= :: Url -> Url -> Bool $cmax :: Url -> Url -> Url max :: Url -> Url -> Url $cmin :: Url -> Url -> Url min :: Url -> Url -> Url Ord, Int -> Url -> ShowS [Url] -> ShowS Url -> String (Int -> Url -> ShowS) -> (Url -> String) -> ([Url] -> ShowS) -> Show Url forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> Url -> ShowS showsPrec :: Int -> Url -> ShowS $cshow :: Url -> String show :: Url -> String $cshowList :: [Url] -> ShowS showList :: [Url] -> ShowS Show) mkUrl :: Text -> Either Text Url mkUrl :: Text -> Either Text Url mkUrl Text raw = let trimmed :: Text trimmed = Text -> Text T.strip Text raw in if Text -> Bool T.null Text trimmed then Text -> Either Text Url forall a b. a -> Either a b Left Text "expected a non-empty URL" else Url -> Either Text Url forall a b. b -> Either a b Right (Text -> Url Url Text trimmed) unUrl :: Url -> Text unUrl :: Url -> Text unUrl (Url Text u) = Text u data QueueBackend = SqsQueue | PubSubQueue | MemoryQueue deriving stock (QueueBackend -> QueueBackend -> Bool (QueueBackend -> QueueBackend -> Bool) -> (QueueBackend -> QueueBackend -> Bool) -> Eq QueueBackend forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: QueueBackend -> QueueBackend -> Bool == :: QueueBackend -> QueueBackend -> Bool $c/= :: QueueBackend -> QueueBackend -> Bool /= :: QueueBackend -> QueueBackend -> Bool Eq, Int -> QueueBackend -> ShowS [QueueBackend] -> ShowS QueueBackend -> String (Int -> QueueBackend -> ShowS) -> (QueueBackend -> String) -> ([QueueBackend] -> ShowS) -> Show QueueBackend forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> QueueBackend -> ShowS showsPrec :: Int -> QueueBackend -> ShowS $cshow :: QueueBackend -> String show :: QueueBackend -> String $cshowList :: [QueueBackend] -> ShowS showList :: [QueueBackend] -> ShowS Show) instance WireVocab QueueBackend where wireKind :: Text wireKind = Text "queue provider" wireTable :: NonEmpty (QueueBackend, Text) wireTable = (QueueBackend SqsQueue, Text "sqs") (QueueBackend, Text) -> [(QueueBackend, Text)] -> NonEmpty (QueueBackend, Text) forall a. a -> [a] -> NonEmpty a :| [ (QueueBackend PubSubQueue, Text "pubsub") , (QueueBackend MemoryQueue, Text "memory") ] parseQueueBackend :: Text -> Either Text QueueBackend parseQueueBackend :: Text -> Either Text QueueBackend parseQueueBackend = Text -> Either Text QueueBackend forall a. WireVocab a => Text -> Either Text a parseWire renderQueueBackend :: QueueBackend -> Text renderQueueBackend :: QueueBackend -> Text renderQueueBackend = QueueBackend -> Text forall a. (Eq a, WireVocab a) => a -> Text renderWire data CredentialBackend = CodeArtifactCredential | StaticCredential | AdcCredential deriving stock (CredentialBackend -> CredentialBackend -> Bool (CredentialBackend -> CredentialBackend -> Bool) -> (CredentialBackend -> CredentialBackend -> Bool) -> Eq CredentialBackend forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: CredentialBackend -> CredentialBackend -> Bool == :: CredentialBackend -> CredentialBackend -> Bool $c/= :: CredentialBackend -> CredentialBackend -> Bool /= :: CredentialBackend -> CredentialBackend -> Bool Eq, Eq CredentialBackend Eq CredentialBackend => (CredentialBackend -> CredentialBackend -> Ordering) -> (CredentialBackend -> CredentialBackend -> Bool) -> (CredentialBackend -> CredentialBackend -> Bool) -> (CredentialBackend -> CredentialBackend -> Bool) -> (CredentialBackend -> CredentialBackend -> Bool) -> (CredentialBackend -> CredentialBackend -> CredentialBackend) -> (CredentialBackend -> CredentialBackend -> CredentialBackend) -> Ord CredentialBackend CredentialBackend -> CredentialBackend -> Bool CredentialBackend -> CredentialBackend -> Ordering CredentialBackend -> CredentialBackend -> CredentialBackend 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 $ccompare :: CredentialBackend -> CredentialBackend -> Ordering compare :: CredentialBackend -> CredentialBackend -> Ordering $c< :: CredentialBackend -> CredentialBackend -> Bool < :: CredentialBackend -> CredentialBackend -> Bool $c<= :: CredentialBackend -> CredentialBackend -> Bool <= :: CredentialBackend -> CredentialBackend -> Bool $c> :: CredentialBackend -> CredentialBackend -> Bool > :: CredentialBackend -> CredentialBackend -> Bool $c>= :: CredentialBackend -> CredentialBackend -> Bool >= :: CredentialBackend -> CredentialBackend -> Bool $cmax :: CredentialBackend -> CredentialBackend -> CredentialBackend max :: CredentialBackend -> CredentialBackend -> CredentialBackend $cmin :: CredentialBackend -> CredentialBackend -> CredentialBackend min :: CredentialBackend -> CredentialBackend -> CredentialBackend Ord, Int -> CredentialBackend -> ShowS [CredentialBackend] -> ShowS CredentialBackend -> String (Int -> CredentialBackend -> ShowS) -> (CredentialBackend -> String) -> ([CredentialBackend] -> ShowS) -> Show CredentialBackend forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> CredentialBackend -> ShowS showsPrec :: Int -> CredentialBackend -> ShowS $cshow :: CredentialBackend -> String show :: CredentialBackend -> String $cshowList :: [CredentialBackend] -> ShowS showList :: [CredentialBackend] -> ShowS Show) instance WireVocab CredentialBackend where wireKind :: Text wireKind = Text "credential provider" wireTable :: NonEmpty (CredentialBackend, Text) wireTable = (CredentialBackend CodeArtifactCredential, Text "codeartifact") (CredentialBackend, Text) -> [(CredentialBackend, Text)] -> NonEmpty (CredentialBackend, Text) forall a. a -> [a] -> NonEmpty a :| [ (CredentialBackend StaticCredential, Text "static") , (CredentialBackend AdcCredential, Text "adc") ] parseCredentialBackend :: Text -> Either Text CredentialBackend parseCredentialBackend :: Text -> Either Text CredentialBackend parseCredentialBackend = Text -> Either Text CredentialBackend forall a. WireVocab a => Text -> Either Text a parseWire renderCredentialBackend :: CredentialBackend -> Text renderCredentialBackend :: CredentialBackend -> Text renderCredentialBackend = CredentialBackend -> Text forall a. (Eq a, WireVocab a) => a -> Text renderWire newtype MirrorCredentialProvider = MirrorCredentialProvider CredentialBackend deriving stock (MirrorCredentialProvider -> MirrorCredentialProvider -> Bool (MirrorCredentialProvider -> MirrorCredentialProvider -> Bool) -> (MirrorCredentialProvider -> MirrorCredentialProvider -> Bool) -> Eq MirrorCredentialProvider forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: MirrorCredentialProvider -> MirrorCredentialProvider -> Bool == :: MirrorCredentialProvider -> MirrorCredentialProvider -> Bool $c/= :: MirrorCredentialProvider -> MirrorCredentialProvider -> Bool /= :: MirrorCredentialProvider -> MirrorCredentialProvider -> Bool Eq) instance WireVocab MirrorCredentialProvider where wireKind :: Text wireKind = Text "mirror-target credential provider" wireTable :: NonEmpty (MirrorCredentialProvider, Text) wireTable = (CredentialBackend -> MirrorCredentialProvider MirrorCredentialProvider CredentialBackend StaticCredential, Text "static") (MirrorCredentialProvider, Text) -> [(MirrorCredentialProvider, Text)] -> NonEmpty (MirrorCredentialProvider, Text) forall a. a -> [a] -> NonEmpty a :| [ (CredentialBackend -> MirrorCredentialProvider MirrorCredentialProvider CredentialBackend CodeArtifactCredential, Text "codeartifact") , (CredentialBackend -> MirrorCredentialProvider MirrorCredentialProvider CredentialBackend AdcCredential, Text "gcp-artifact-registry") ] parseMirrorCredentialProvider :: Text -> Either Text CredentialBackend parseMirrorCredentialProvider :: Text -> Either Text CredentialBackend parseMirrorCredentialProvider Text raw = (\(MirrorCredentialProvider CredentialBackend backend) -> CredentialBackend backend) (MirrorCredentialProvider -> CredentialBackend) -> Either Text MirrorCredentialProvider -> Either Text CredentialBackend forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Text -> Either Text MirrorCredentialProvider forall a. WireVocab a => Text -> Either Text a parseWire Text raw renderMirrorCredentialProvider :: CredentialBackend -> Text renderMirrorCredentialProvider :: CredentialBackend -> Text renderMirrorCredentialProvider = MirrorCredentialProvider -> Text forall a. (Eq a, WireVocab a) => a -> Text renderWire (MirrorCredentialProvider -> Text) -> (CredentialBackend -> MirrorCredentialProvider) -> CredentialBackend -> Text forall b c a. (b -> c) -> (a -> b) -> a -> c . CredentialBackend -> MirrorCredentialProvider MirrorCredentialProvider data MountConfig = MountConfig { MountConfig -> Maybe RegistryUrl mntPrivateUpstream :: Maybe RegistryUrl , MountConfig -> RegistryUrl mntPublicUpstream :: RegistryUrl , MountConfig -> Maybe RegistryUrl mntMirrorTarget :: Maybe RegistryUrl , MountConfig -> Maybe Secret mntMirrorTargetToken :: Maybe Secret , MountConfig -> CredentialBackend mntCredentialProvider :: CredentialBackend , MountConfig -> Bool mntRespectUpstreamTarballHost :: Bool , MountConfig -> Maybe Text mntMirrorCodeArtifactDomain :: Maybe Text , MountConfig -> Maybe Text mntMirrorCodeArtifactDomainOwner :: Maybe Text , MountConfig -> Maybe Text mntMirrorCodeArtifactRegion :: Maybe Text , MountConfig -> Maybe Natural mntMirrorCodeArtifactTokenDuration :: Maybe Natural , MountConfig -> Maybe RegistryUrl mntPublicationTarget :: Maybe RegistryUrl , MountConfig -> Maybe Secret mntPublicationTargetToken :: Maybe Secret , MountConfig -> [Scope] mntPublishScopes :: [Scope] , MountConfig -> RulePatch mntAdditionalRules :: RulePatch } deriving stock (MountConfig -> MountConfig -> Bool (MountConfig -> MountConfig -> Bool) -> (MountConfig -> MountConfig -> Bool) -> Eq MountConfig forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: MountConfig -> MountConfig -> Bool == :: MountConfig -> MountConfig -> Bool $c/= :: MountConfig -> MountConfig -> Bool /= :: MountConfig -> MountConfig -> Bool Eq, Int -> MountConfig -> ShowS [MountConfig] -> ShowS MountConfig -> String (Int -> MountConfig -> ShowS) -> (MountConfig -> String) -> ([MountConfig] -> ShowS) -> Show MountConfig forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> MountConfig -> ShowS showsPrec :: Int -> MountConfig -> ShowS $cshow :: MountConfig -> String show :: MountConfig -> String $cshowList :: [MountConfig] -> ShowS showList :: [MountConfig] -> ShowS Show) data AppConfig = AppConfig { AppConfig -> Int cfgPort :: Int , AppConfig -> Map Ecosystem MountConfig cfgMounts :: Map Ecosystem MountConfig , AppConfig -> QueueBackend cfgQueueBackend :: QueueBackend , AppConfig -> Maybe Url cfgQueueUrl :: Maybe Url , AppConfig -> Int cfgQueueMemoryMaxDepth :: Int , AppConfig -> Maybe Text cfgAwsRegion :: Maybe Text , AppConfig -> Maybe Text cfgAwsEndpointUrlSqs :: Maybe Text , AppConfig -> Maybe Text cfgAwsEndpointUrl :: Maybe Text , AppConfig -> Maybe Text cfgGoogleProject :: Maybe Text , AppConfig -> Maybe Secret cfgAuthToken :: Maybe Secret , AppConfig -> Maybe Text cfgHelpMessage :: Maybe Text , AppConfig -> NominalDiffTime cfgCveSyncInterval :: NominalDiffTime , AppConfig -> Int cfgShutdownDrainTimeout :: Int , AppConfig -> Maybe Int cfgCores :: Maybe Int , AppConfig -> Maybe Int cfgMaxHeapBytes :: Maybe Int , AppConfig -> Maybe Int cfgServeMaxInFlight :: Maybe Int , AppConfig -> Maybe Int cfgPublicConnectionsPerHost :: Maybe Int , AppConfig -> Maybe Int cfgPrivateConnectionsPerHost :: Maybe Int , AppConfig -> NominalDiffTime cfgCacheTtl :: NominalDiffTime , AppConfig -> Int cfgCacheMaxEntries :: Int , AppConfig -> Int cfgCacheMaxBytes :: Int , AppConfig -> Int cfgMaxResponseBytes :: Int , AppConfig -> Int cfgMaxVersionCount :: Int , AppConfig -> Int cfgMaxNestingDepth :: Int , AppConfig -> LogFormat cfgLogFormat :: LogFormat , AppConfig -> TelemetrySwitch cfgTelemetry :: TelemetrySwitch , AppConfig -> Maybe Url cfgPublicUrl :: Maybe Url , AppConfig -> MinIntegrity cfgMinPublicIntegrity :: MinIntegrity , AppConfig -> MinTrustedIntegrity cfgMinTrustedIntegrity :: MinTrustedIntegrity , AppConfig -> [IPRange] cfgAdditionalBlockedRanges :: [IPRange] , AppConfig -> String cfgOsvDataDir :: FilePath , AppConfig -> Text cfgOsvExportBaseUrl :: Text , AppConfig -> Maybe Text cfgVulnerabilityDatabaseBucket :: Maybe Text , AppConfig -> NominalDiffTime cfgCveDbPollInterval :: NominalDiffTime , AppConfig -> Int cfgMaxOsvDbBytes :: Int } deriving stock (AppConfig -> AppConfig -> Bool (AppConfig -> AppConfig -> Bool) -> (AppConfig -> AppConfig -> Bool) -> Eq AppConfig forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: AppConfig -> AppConfig -> Bool == :: AppConfig -> AppConfig -> Bool $c/= :: AppConfig -> AppConfig -> Bool /= :: AppConfig -> AppConfig -> Bool Eq, Int -> AppConfig -> ShowS [AppConfig] -> ShowS AppConfig -> String (Int -> AppConfig -> ShowS) -> (AppConfig -> String) -> ([AppConfig] -> ShowS) -> Show AppConfig forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> AppConfig -> ShowS showsPrec :: Int -> AppConfig -> ShowS $cshow :: AppConfig -> String show :: AppConfig -> String $cshowList :: [AppConfig] -> ShowS showList :: [AppConfig] -> ShowS Show) data MountRegistries = MountRegistries { MountRegistries -> RegistryUrl regPrivateUpstream :: RegistryUrl , MountRegistries -> RegistryUrl regPublicUpstream :: RegistryUrl , MountRegistries -> MirrorTarget regMirrorTarget :: MirrorTarget } deriving stock (MountRegistries -> MountRegistries -> Bool (MountRegistries -> MountRegistries -> Bool) -> (MountRegistries -> MountRegistries -> Bool) -> Eq MountRegistries forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: MountRegistries -> MountRegistries -> Bool == :: MountRegistries -> MountRegistries -> Bool $c/= :: MountRegistries -> MountRegistries -> Bool /= :: MountRegistries -> MountRegistries -> Bool Eq, Int -> MountRegistries -> ShowS [MountRegistries] -> ShowS MountRegistries -> String (Int -> MountRegistries -> ShowS) -> (MountRegistries -> String) -> ([MountRegistries] -> ShowS) -> Show MountRegistries forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> MountRegistries -> ShowS showsPrec :: Int -> MountRegistries -> ShowS $cshow :: MountRegistries -> String show :: MountRegistries -> String $cshowList :: [MountRegistries] -> ShowS showList :: [MountRegistries] -> ShowS Show) data MirrorTarget = MirrorTarget { MirrorTarget -> RegistryUrl mtUrl :: RegistryUrl , MirrorTarget -> CredentialBackend mtCredential :: CredentialBackend , MirrorTarget -> QueueBackend mtQueue :: QueueBackend } deriving stock (MirrorTarget -> MirrorTarget -> Bool (MirrorTarget -> MirrorTarget -> Bool) -> (MirrorTarget -> MirrorTarget -> Bool) -> Eq MirrorTarget forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: MirrorTarget -> MirrorTarget -> Bool == :: MirrorTarget -> MirrorTarget -> Bool $c/= :: MirrorTarget -> MirrorTarget -> Bool /= :: MirrorTarget -> MirrorTarget -> Bool Eq, Int -> MirrorTarget -> ShowS [MirrorTarget] -> ShowS MirrorTarget -> String (Int -> MirrorTarget -> ShowS) -> (MirrorTarget -> String) -> ([MirrorTarget] -> ShowS) -> Show MirrorTarget forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> MirrorTarget -> ShowS showsPrec :: Int -> MirrorTarget -> ShowS $cshow :: MirrorTarget -> String show :: MirrorTarget -> String $cshowList :: [MirrorTarget] -> ShowS showList :: [MirrorTarget] -> ShowS Show) data Mount = Mount { Mount -> Ecosystem mountEcosystem :: Ecosystem , Mount -> MountRegistries mountRegistries :: MountRegistries , Mount -> [PrecededRule] mountPolicy :: [PrecededRule] } deriving stock (Mount -> Mount -> Bool (Mount -> Mount -> Bool) -> (Mount -> Mount -> Bool) -> Eq Mount forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: Mount -> Mount -> Bool == :: Mount -> Mount -> Bool $c/= :: Mount -> Mount -> Bool /= :: Mount -> Mount -> Bool Eq, Int -> Mount -> ShowS [Mount] -> ShowS Mount -> String (Int -> Mount -> ShowS) -> (Mount -> String) -> ([Mount] -> ShowS) -> Show Mount forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> Mount -> ShowS showsPrec :: Int -> Mount -> ShowS $cshow :: Mount -> String show :: Mount -> String $cshowList :: [Mount] -> ShowS showList :: [Mount] -> ShowS Show) type MountMap = Map Ecosystem Mount data Config = Config { Config -> AppConfig configApp :: AppConfig , Config -> MountMap configMounts :: MountMap } deriving stock (Config -> Config -> Bool (Config -> Config -> Bool) -> (Config -> Config -> Bool) -> Eq Config forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: Config -> Config -> Bool == :: Config -> Config -> Bool $c/= :: Config -> Config -> Bool /= :: Config -> Config -> Bool Eq, Int -> Config -> ShowS [Config] -> ShowS Config -> String (Int -> Config -> ShowS) -> (Config -> String) -> ([Config] -> ShowS) -> Show Config forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> Config -> ShowS showsPrec :: Int -> Config -> ShowS $cshow :: Config -> String show :: Config -> String $cshowList :: [Config] -> ShowS showList :: [Config] -> ShowS Show) data ConfigError = ParseError Text | PolicyErrors [PolicyError] deriving stock (ConfigError -> ConfigError -> Bool (ConfigError -> ConfigError -> Bool) -> (ConfigError -> ConfigError -> Bool) -> Eq ConfigError forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: ConfigError -> ConfigError -> Bool == :: ConfigError -> ConfigError -> Bool $c/= :: ConfigError -> ConfigError -> Bool /= :: ConfigError -> ConfigError -> Bool Eq, Int -> ConfigError -> ShowS [ConfigError] -> ShowS ConfigError -> String (Int -> ConfigError -> ShowS) -> (ConfigError -> String) -> ([ConfigError] -> ShowS) -> Show ConfigError forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> ConfigError -> ShowS showsPrec :: Int -> ConfigError -> ShowS $cshow :: ConfigError -> String show :: ConfigError -> String $cshowList :: [ConfigError] -> ShowS showList :: [ConfigError] -> ShowS Show) renderConfigError :: ConfigError -> Text renderConfigError :: ConfigError -> Text renderConfigError (ParseError Text e) = Text e renderConfigError (PolicyErrors [PolicyError] es) = [Text] -> Text T.unlines ((PolicyError -> Text) -> [PolicyError] -> [Text] forall a b. (a -> b) -> [a] -> [b] map PolicyError -> Text renderPolicyError [PolicyError] es)