#!/usr/bin/env bash validate_command() { local PERSON="$1" local cmd="$2" shift 2 local tokens=("$@") local yaml="access.yml" # Check if fixedArgsCommands. exists local is_fixed is_fixed="$(yq e ".\"$PERSON\".fixedArgsCommands | has(\"$cmd\")" "$yaml")" # Check if multiArgsCommands. exists local is_multi is_multi="$(yq e ".\"$PERSON\".multiArgsCommands | has(\"$cmd\")" "$yaml")" if [[ "$is_fixed" != "true" && "$is_multi" != "true" ]]; then echo "ERROR: Command '$cmd' not allowed for $PERSON" >&2 return 1 fi # Exclude flags from positional args local args=() for tok in "${tokens[@]}"; do [[ "$tok" == -* ]] && continue args+=("$tok") done if [[ "$is_fixed" == "true" ]]; then mapfile -t allowed < <(yq e ".\"$PERSON\".fixedArgsCommands.\"$cmd\"[]" "$yaml" 2>/dev/null) local n_allowed="${#allowed[@]}" if [[ $n_allowed -eq 0 ]]; then # zero-arg command if [[ ${#args[@]} -ne 0 ]]; then echo "ERROR: Command '$cmd' takes no arguments" >&2 return 1 fi else # depth is 1: only one of the allowed choices must be present if [[ ${#args[@]} -ne 1 ]]; then echo "ERROR: Command '$cmd' requires exactly 1 argument: (${allowed[*]})" >&2 return 1 fi local found=0 for want in "${allowed[@]}"; do [[ "${args[0]}" == "$want" ]] && found=1 && break done if [[ $found -eq 0 ]]; then echo "ERROR: Invalid argument '${args[0]}' for '$cmd'; allowed: (${allowed[*]})" >&2 return 1 fi fi return 0 fi if [[ "$is_multi" == "true" ]]; then mapfile -t allowed < <(yq e ".\"$PERSON\".multiArgsCommands.\"$cmd\"[]" "$yaml" 2>/dev/null) local n_allowed="${#allowed[@]}" if [[ ${#args[@]} -lt 1 || ${#args[@]} -gt $n_allowed ]]; then echo "ERROR: Command '$cmd' requires 1 to $n_allowed arguments: (${allowed[*]})" >&2 return 1 fi # Order doesn't matter, but all must be unique and from allowed. # Build a set of allowed args. declare -A allowed_set=() for want in "${allowed[@]}"; do allowed_set["$want"]=1; done declare -A seen=() for a in "${args[@]}"; do [[ -z "${allowed_set[$a]}" ]] && { echo "ERROR: Invalid argument '$a' for '$cmd'; allowed: (${allowed[*]})" >&2 return 1 } [[ -n "${seen[$a]}" ]] && { echo "ERROR: Duplicate argument '$a' for '$cmd'" >&2 return 1 } seen["$a"]=1 done return 0 fi }