set -eu
usage() {
printf '%s\n' \
'usage: action-baseline validate <sync> <no-cache> <encrypted-cache> <key-available> <cache> <schemas> <baseline> <mode> <advisory> <path> <config> <output-dir>' \
' action-baseline validate-config <config> <encrypted-cache> <no-cache>' \
' action-baseline sync <binary> <cache> <config> <schemas>' >&2
exit 2
}
validate_boolean() {
name=$1
value=$2
case "$value" in
true|false) ;;
*)
printf '%s must be true or false, got: %s\n' "$name" "$value" >&2
exit 1
;;
esac
}
validate_single_line() {
name=$1
value=$2
newline='
'
carriage_return=$(printf '\r')
case "$value" in
*"$newline"*|*"$carriage_return"*)
printf '%s must not contain CR or LF characters\n' "$name" >&2
exit 1
;;
esac
}
command=${1-}
case "$command" in
validate)
[ "$#" -eq 13 ] || usage
sync=$2
no_cache=$3
encrypted_cache=$4
key_available=$5
cache=$6
schemas=$7
baseline=$8
mode=$9
advisory=${10}
path=${11}
config=${12}
output_dir=${13}
validate_boolean sync "$sync"
validate_boolean no-cache "$no_cache"
validate_boolean encrypted-cache "$encrypted_cache"
validate_boolean key-available "$key_available"
validate_boolean advisory "$advisory"
validate_single_line cache "$cache"
validate_single_line schemas "$schemas"
validate_single_line baseline "$baseline"
validate_single_line mode "$mode"
validate_single_line path "$path"
validate_single_line config "$config"
validate_single_line output-dir "$output_dir"
case "$mode" in
auto)
if [ -z "$path" ] && [ "$sync" = true ]; then
mode='sync-only'
elif [ -f "$path" ]; then
mode=lint
elif [ -d "$path" ]; then
mode=lint-chain
else
printf 'path does not exist or is not a file or directory: %s\n' \
"$path" >&2
exit 1
fi
;;
lint)
[ -f "$path" ] || {
printf 'lint path does not exist or is not a file: %s\n' "$path" >&2
exit 1
}
;;
sync-only)
[ "$sync" = true ] && [ -z "$path" ] || {
printf '%s\n' \
'sync-only requires sync to be true and path to be empty' >&2
exit 1
}
;;
lint-chain)
[ -d "$path" ] || {
printf 'lint-chain path does not exist or is not a directory: %s\n' \
"$path" >&2
exit 1
}
;;
*)
printf 'mode must be lint or lint-chain, got: %s\n' "$mode" >&2
exit 1
;;
esac
[ -n "$output_dir" ] || {
printf '%s\n' 'output-dir must not be empty' >&2
exit 1
}
case "$output_dir" in
/*|[A-Za-z]:[\\/]*|*\\*)
printf '%s\n' 'output-dir must be a relative path inside the workspace' >&2
exit 1
;;
.|..|./*|../*|*/.|*/..|*/./*|*/../*|*//*|*/)
printf '%s\n' \
'output-dir must not contain empty, dot, or parent path segments' >&2
exit 1
;;
esac
old_ifs=$IFS
IFS=/
set -f
set -- $output_dir
set +f
IFS=$old_ifs
for segment do
case "$segment" in
''|.|..)
printf '%s\n' \
'output-dir must not contain empty, dot, or parent path segments' >&2
exit 1
;;
esac
done
output_cursor=.
old_ifs=$IFS
IFS=/
set -f
set -- $output_dir
set +f
IFS=$old_ifs
for segment do
output_cursor="$output_cursor/$segment"
if [ -L "$output_cursor" ]; then
printf 'output-dir must not traverse a symlink: %s\n' \
"$output_cursor" >&2
exit 1
fi
done
if [ "$no_cache" = true ] && {
[ "$sync" = true ] || [ -n "$cache" ] || [ -n "$schemas" ];
}; then
printf '%s\n' \
'no-cache cannot be combined with cache, sync, or schemas' >&2
exit 1
fi
if [ -n "$schemas" ] && [ "$sync" != true ]; then
printf '%s\n' 'schemas requires sync to be true' >&2
exit 1
fi
if [ "$no_cache" != true ] && [ "$encrypted_cache" = true ] && \
[ "$key_available" != true ]; then
printf '%s\n' \
'encrypted-cache requires SAFE_MIGRATE_CACHE_KEY; use no-cache only for an explicit degraded analysis' >&2
exit 1
fi
[ -n "$baseline" ] || {
printf '%s\n' 'baseline must not be empty' >&2
exit 1
}
case "$baseline" in
.|..)
printf '%s\n' 'baseline must be a name, not a path segment' >&2
exit 1
;;
esac
case "$baseline" in
*[!A-Za-z0-9._-]*)
printf '%s\n' \
'baseline may contain only letters, digits, dot, underscore, and hyphen' >&2
exit 1
;;
esac
[ "${#baseline}" -le 100 ] || {
printf '%s\n' 'baseline must be at most 100 characters' >&2
exit 1
}
printf '%s\n' "$mode"
;;
validate-config)
[ "$#" -eq 4 ] || usage
config=$2
encrypted_cache=$3
no_cache=$4
validate_boolean encrypted-cache "$encrypted_cache"
validate_boolean no-cache "$no_cache"
validate_single_line config "$config"
if [ ! -f "$config" ]; then
printf 'explicit config does not exist or is not a file: %s\n' \
"$config" >&2
exit 1
fi
encryption_true_pattern="^[[:space:]]*(cache_encryption|\"cache_encryption\"|'cache_encryption')[[:space:]]*=[[:space:]]*true([[:space:]]*(#.*)?)?$"
if [ "$no_cache" != true ] && [ "$encrypted_cache" = true ] && \
! grep -Eq -- "$encryption_true_pattern" "$config"; then
printf '%s\n' \
'encrypted-cache requires cache_encryption = true in the explicit config' >&2
exit 1
fi
if [ "$no_cache" != true ] && [ "$encrypted_cache" != true ] && \
grep -Eq -- "$encryption_true_pattern" "$config"; then
printf '%s\n' \
'explicit config enables cache encryption; set encrypted-cache to true' >&2
exit 1
fi
;;
sync)
[ "$#" -eq 5 ] || usage
binary=$2
cache=$3
config=$4
schemas=$5
validate_single_line cache "$cache"
validate_single_line config "$config"
validate_single_line schemas "$schemas"
set -- "$binary" sync --out "$cache" --config "$config"
if [ -n "$schemas" ]; then
set -- "$@" --schemas "$schemas"
fi
"$@"
;;
*)
usage
;;
esac