{-# 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)