module Stackctl.AutoSSO ( AutoSSOOption , defaultAutoSSOOption , HasAutoSSOOption (..) , autoSSOOption , envAutoSSOOption , handleAutoSSO ) where import Stackctl.Prelude import Amazonka.SSO (_UnauthorizedException) import Data.Semigroup (Last (..)) import qualified Env import Options.Applicative import Stackctl.AWS.Core as AWS (formatServiceError) import Stackctl.Prompt import System.Process.Typed import UnliftIO.Exception.Lens (catching) data AutoSSOOption = AutoSSOAlways | AutoSSOAsk | AutoSSONever deriving (Semigroup) via Last AutoSSOOption defaultAutoSSOOption :: AutoSSOOption defaultAutoSSOOption = AutoSSOAsk readAutoSSO :: String -> Either String AutoSSOOption readAutoSSO = \case "always" -> Right AutoSSOAlways "ask" -> Right AutoSSOAsk "never" -> Right AutoSSONever x -> Left $ "Invalid choice for auto-sso: " <> x <> ", must be always|ask|never" class HasAutoSSOOption env where autoSSOOptionL :: Lens' env AutoSSOOption autoSSOOption :: Parser AutoSSOOption autoSSOOption = option (eitherReader readAutoSSO) $ mconcat [long "auto-sso", help autoSSOHelp, metavar "WHEN"] envAutoSSOOption :: Env.Parser Env.Error AutoSSOOption envAutoSSOOption = Env.var (first Env.UnreadError . readAutoSSO) "AUTO_SSO" $ Env.help autoSSOHelp autoSSOHelp :: IsString a => a autoSSOHelp = "Automatically run aws-sso-login if necessary?" handleAutoSSO :: ( MonadUnliftIO m , MonadReader env m , MonadLogger m , HasLogger env , HasAutoSSOOption options ) => options -> m a -> m a handleAutoSSO options f = do catching _UnauthorizedException f $ \ex -> do case options ^. autoSSOOptionL of AutoSSOAlways -> do logWarn $ ssoErrorMessage ex logInfo "Running `aws sso login' automatically" AutoSSOAsk -> do logWarn $ ssoErrorMessage ex promptOrExit "Run `aws sso login'" AutoSSONever -> do logError $ ssoErrorMessage ex exitFailure runProcess_ $ proc "aws" ["sso", "login"] f where ssoErrorMessage ex = "AWS SSO authorization error" :# [ "message" .= formatServiceError ex , "hint" .= ("Run `aws sso login' and try again" :: Text) ]