packages feed

heni-0.1.0.0: src/Test/Heni/Command.hs

-- | Portable commands and validated budgets. Commands run without shell expansion.
module Test.Heni.Command
  ( CommandId,
    mkCommandId,
    commandIdText,
    StageBudget,
    mkStageBudget,
    budgetMicroseconds,
    Stage (..),
    ProcessOutcome (..),
    OutputPolicy (..),
    Command (..),
    validateCommand,
  )
where

import Data.List (isPrefixOf)
import Data.Set qualified as Set
import Test.Heni.Internal.Model

-- | Validate launch-independent constraints. Environment names must be unique.
validateCommand :: Command -> Either ConfigError ()
validateCommand Command {executable, arguments, sensitiveArguments, environment, output = OutputPolicy {limitBytes}}
  | null executable || '\0' `elem` executable = bad "executable" "expected an executable without NUL"
  | "./" `isPrefixOf` executable && invalidWorkspaceExecutable = bad "executable" "workspace executable must be a contained relative path"
  | any (elem '\0') arguments = bad "arguments" "NUL in argument"
  | any (\i -> i < 0 || i >= length arguments) (Set.toList sensitiveArguments) = bad "sensitiveArguments" "argument index is out of range"
  | limitBytes <= 0 = bad "output.limitBytes" "expected a positive output limit"
  | any (\(k, v) -> null k || any (`elem` k) ['=', '\0'] || '\0' `elem` v) environment = bad "environment" "invalid environment entry"
  | length (map fst environment) /= length (unique (map fst environment)) = bad "environment" "duplicate environment key"
  | otherwise = Right ()
  where
    invalidWorkspaceExecutable = case mkRelativeTarget (drop 2 executable) of Left _ -> True; Right _ -> False
    bad f m = Left (ConfigError f m)
    unique [] = []
    unique (x : xs) = x : unique (filter (/= x) xs)