diff --git a/tests/test_validate_command_access.sh b/tests/test_validate_command_access.sh new file mode 100755 index 0000000..b5893f8 --- /dev/null +++ b/tests/test_validate_command_access.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -e + +cat >access.yml < 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 +}