module Hadolint.Rule.DL3064 (rule) where

import qualified Data.Text as Text
import Hadolint.Rule
import Hadolint.Shell (ParsedShell)
import Language.Docker.Syntax


rule :: Rule ParsedShell
rule :: Rule ParsedShell
rule = Rule ParsedShell
dl3064 Rule ParsedShell -> Rule ParsedShell -> Rule ParsedShell
forall a. Semigroup a => a -> a -> a
<> Rule ParsedShell -> Rule ParsedShell
forall args. Rule args -> Rule args
onbuild Rule ParsedShell
dl3064
{-# INLINEABLE rule #-}

dl3064 :: Rule ParsedShell
dl3064 :: Rule ParsedShell
dl3064 = RuleCode
-> DLSeverity
-> Text
-> (Instruction ParsedShell -> Bool)
-> Rule ParsedShell
forall args.
RuleCode
-> DLSeverity -> Text -> (Instruction args -> Bool) -> Rule args
simpleRule RuleCode
code DLSeverity
severity Text
message Instruction ParsedShell -> Bool
forall {args}. Instruction args -> Bool
check
  where
    code :: RuleCode
code = RuleCode
"DL3064"
    severity :: DLSeverity
severity = DLSeverity
DLWarningC
    message :: Text
message = Text
"Potentially sensitive data should not be used in the `ARG` or `ENV` commands"

    check :: Instruction args -> Bool
check (Arg Text
name Maybe Text
_) =
      Text -> Text
Text.toUpper Text
name Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Text]
knownSensitiveNames
        Bool -> Bool -> Bool
&& (Text -> Bool) -> [Text] -> Bool
forall a. (a -> Bool) -> [a] -> Bool
none (Text -> Text -> Bool
`Text.isInfixOf` Text -> Text
Text.toLower Text
name) [Text]
suspiciousSubstrings
    check (Env Pairs
pairs) =
      ((Text, Text) -> Bool) -> Pairs -> Bool
forall a. (a -> Bool) -> [a] -> Bool
none (\(Text, Text)
s -> (Text -> Text
Text.toUpper (Text -> Text) -> ((Text, Text) -> Text) -> (Text, Text) -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text, Text) -> Text
forall a b. (a, b) -> a
fst) (Text, Text)
s Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
knownSensitiveNames) Pairs
pairs
        Bool -> Bool -> Bool
&& (Text -> Bool) -> [Text] -> Bool
forall a. (a -> Bool) -> [a] -> Bool
none (\Text
s -> ((Text, Text) -> Bool) -> Pairs -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((Text
s Text -> Text -> Bool
`Text.isInfixOf`) (Text -> Bool) -> ((Text, Text) -> Text) -> (Text, Text) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
Text.toLower (Text -> Text) -> ((Text, Text) -> Text) -> (Text, Text) -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text, Text) -> Text
forall a b. (a, b) -> a
fst) Pairs
pairs) [Text]
suspiciousSubstrings
    check Instruction args
_ = Bool
True
{-# INLINEABLE dl3064 #-}

none :: (a -> Bool) -> [a] -> Bool
none :: forall a. (a -> Bool) -> [a] -> Bool
none a -> Bool
p [a]
xs = Bool -> Bool
not ( (a -> Bool) -> [a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any a -> Bool
p [a]
xs )

knownSensitiveNames :: [Text.Text]
knownSensitiveNames :: [Text]
knownSensitiveNames =
  [
    Text
"ACCESS_TOKEN",
    Text
"APPLICATION_KEY",
    Text
"APP_SECRET",
    Text
"AUTH_TOKEN",
    Text
"AWS_ACCESS_KEY_ID",
    Text
"AWS_SECRET_ACCESS_KEY",
    Text
"BITTREX_API_KEY",
    Text
"BITTREX_API_SECRET",
    Text
"CF_PASSWORD",
    Text
"CF_USERNAME",
    Text
"CIRCLE_TOKEN",
    Text
"CI_DEPLOY_PASSWORD",
    Text
"CI_DEPLOY_USER",
    Text
"DOCKERHUB_PASSWORD",
    Text
"DOCKER_EMAIL",
    Text
"DOCKER_PASSWORD",
    Text
"DOCKER_USERNAME",
    Text
"FACEBOOK_ACCESS_TOKEN",
    Text
"FACEBOOK_APP_ID",
    Text
"FACEBOOK_APP_SECRET",
    Text
"FIREBASE_API_TOKEN",
    Text
"FIREBASE_TOKEN",
    Text
"FOSSA_API_KEY",
    Text
"GH_ENTERPRISE_TOKEN",
    Text
"GH_TOKEN",
    Text
"GITHUB_ENTERPRISE_TOKEN",
    Text
"GITHUB_TOKEN",
    Text
"HEROKU_API_KEY",
    Text
"HEROKU_API_USER",
    Text
"NPM_AUTH_TOKEN",
    Text
"NPM_TOKEN",
    Text
"OKTA_AUTHN_GROUPID",
    Text
"OKTA_CLIENT_ORGURL",
    Text
"OKTA_CLIENT_TOKEN",
    Text
"OKTA_OAUTH2_CLIENTID",
    Text
"OKTA_OAUTH2_CLIENTSECRET",
    Text
"OPENAI_API_KEY",
    Text
"OS_PASSWORD",
    Text
"OS_USERNAME",
    Text
"POSTGRES_PASSWORD",
    Text
"SLACK_TOKEN",
    Text
"STRIPE_API_KEY",
    Text
"STRIPE_DEVICE_NAME",
    Text
"TRAVIS_OS_NAME",
    Text
"TRAVIS_SECURE_ENV_VARS",
    Text
"TRAVIS_SUDO",
    Text
"VAULT_CLIENT_KEY",
    Text
"VAULT_TOKEN"
  ]

suspiciousSubstrings :: [Text.Text]
suspiciousSubstrings :: [Text]
suspiciousSubstrings =
  [
    Text
"api_key",
    Text
"client_key",
    Text
"password",
    Text
"private",
    Text
"secret",
    Text
"token",
    Text
"username"
  ]