fix: validate app name in app-scoped commands

This commit is contained in:
Jose Diaz-Gonzalez
2026-09-24 18:14:53 -04:00
parent 114c6115b9
commit a4484d354b
22 changed files with 213 additions and 35 deletions

View File

@@ -13,6 +13,8 @@ cmd-cleanup() {
APP="--global"
fi
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
docker_cleanup "$APP" "true"
}

View File

@@ -19,17 +19,16 @@ cmd-caddy-set() {
dokku_log_fail "Invalid key specified, valid keys include: image letsencrypt-email letsencrypt-server log-level polling-interval tls-internal"
fi
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then
if [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
verify_app_name "$APP"
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then
dokku_log_fail "The key '$KEY' can only be set globally"
fi
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
if [[ -n "$VALUE" ]]; then
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
fn-plugin-property-write "caddy" "$APP" "$KEY" "$VALUE"

View File

@@ -10,7 +10,7 @@ cmd-domains-disable() {
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1"
[[ "$APP" == "--all" ]] && verify_app_name "$APP"
[[ "$APP" == "--all" ]] || verify_app_name "$APP"
fn-domains-disable "$APP"
}

View File

@@ -10,7 +10,7 @@ cmd-domains-enable() {
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1"
[[ "$APP" == "--all" ]] && verify_app_name "$APP"
[[ "$APP" == "--all" ]] || verify_app_name "$APP"
fn-domains-enable "$APP"
}

View File

@@ -19,17 +19,16 @@ cmd-haproxy-set() {
dokku_log_fail "Invalid key specified, valid keys include: image log-level letsencrypt-email letsencrypt-server refresh-conf"
fi
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then
if [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
verify_app_name "$APP"
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then
dokku_log_fail "The key '$KEY' can only be set globally"
fi
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
if [[ -n "$VALUE" ]]; then
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
fn-plugin-property-write "haproxy" "$APP" "$KEY" "$VALUE"

View File

@@ -50,7 +50,7 @@ func main() {
args := flag.NewFlagSet("network:rebuild", flag.ExitOnError)
args.Parse(os.Args[2:])
appName := args.Arg(0)
err = network.BuildConfig(appName)
err = network.CommandRebuild(appName)
case "rebuildall":
args := flag.NewFlagSet("network:rebuildall", flag.ExitOnError)
args.Parse(os.Args[2:])

View File

@@ -148,6 +148,15 @@ func CommandList(format string, dokkuManaged bool) error {
return nil
}
// CommandRebuild rebuilds network settings for an app
func CommandRebuild(appName string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
return BuildConfig(appName)
}
// CommandRebuildall rebuilds network settings for all apps
func CommandRebuildall() error {
apps, err := common.DokkuApps()

View File

@@ -37,7 +37,7 @@ validate_nginx() {
verify_app_name "$APP"
nginx_vhosts_validate_single_func "$APP" "$FLAG"
else
for app in $(dokku_apps "false"); do
for app in $(dokku_apps); do
nginx_vhosts_validate_single_func "$app" "$FLAG"
done
fi

View File

@@ -18,13 +18,12 @@ cmd-nginx-set() {
dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-body-timeout, client-header-timeout, client-max-body-size, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, keepalive-timeout, lingering-timeout, nginx-conf-sigil-path, nginx-service-command, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout, proxy-keepalive, send-timeout, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl"
fi
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then
if [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
verify_app_name "$APP"
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
if [[ "$KEY" == "proxy-keepalive" ]] && [[ -n "$VALUE" ]]; then
if ! is_number "$VALUE"; then
dokku_log_fail "Invalid value for proxy-keepalive: must be an integer"

View File

@@ -19,17 +19,16 @@ cmd-openresty-set() {
dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, allowed-letsencrypt-domains-func-base64, bind-address-ipv4, bind-address-ipv6, client-body-timeout, client-header-timeout, client-max-body-size, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, image, keepalive-timeout, log-level, letsencrypt-email, letsencrypt-server, lingering-timeout, proxy-connect-timeout, proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout, send-timeout, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl"
fi
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then
if [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
verify_app_name "$APP"
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
if fn-in-array "$KEY" "${GLOBAL_ONLY_KEYS[@]}" && [[ "$APP" != "--global" ]]; then
dokku_log_fail "The key '$KEY' can only be set globally"
fi
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
if [[ -n "$VALUE" ]]; then
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
fn-plugin-property-write "openresty" "$APP" "$KEY" "$VALUE"

View File

@@ -121,6 +121,9 @@ func CommandRetire(appName string) error {
if appName == "" {
scheduler = common.GetGlobalScheduler()
} else {
if err := common.VerifyAppName(appName); err != nil {
return err
}
scheduler = common.GetAppScheduler(appName)
}

View File

@@ -269,6 +269,19 @@ cmd-run-stop() {
esac
done
if [[ -n "$CONTAINER_NAME" ]]; then
local CONTAINER_APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)"
if [[ -n "$APP" ]] && [[ "$APP" != "$CONTAINER_APP" ]]; then
dokku_log_fail "Specified app does not match app in container name"
fi
APP="$CONTAINER_APP"
fi
if [[ -z "$APP" ]]; then
dokku_log_fail "No container or app specified"
fi
verify_app_name "$APP"
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
plugn trigger scheduler-run-stop "$DOKKU_SCHEDULER" "$APP" "$CONTAINER_NAME"
}

View File

@@ -25,6 +25,21 @@ fn-scheduler-docker-local-stop-container() {
return 1
}
fn-scheduler-docker-local-stop-app-run-container() {
declare desc="stops a named run container belonging to an app"
declare APP="$1" CONTAINER_NAME="$2" DOCKER_STOP_TIMEOUT="$3"
local NAME
while IFS= read -r NAME; do
if [[ "$NAME" == "$CONTAINER_NAME" ]]; then
fn-scheduler-docker-local-stop-container "$CONTAINER_NAME" "$DOCKER_STOP_TIMEOUT"
return $?
fi
done < <("$DOCKER_BIN" container ls --filter "label=com.dokku.app-name=$APP" --filter "label=com.dokku.container-type=run" --format '{{ .Names }}')
dokku_log_warn "Specified container does not exist"
}
trigger-scheduler-docker-local-scheduler-run-stop() {
declare desc="stops an app run container"
declare trigger="scheduler-run-stop"
@@ -34,15 +49,21 @@ trigger-scheduler-docker-local-scheduler-run-stop() {
return
fi
if [[ -z "$APP" ]]; then
if [[ -z "$CONTAINER_NAME" ]]; then
dokku_log_fail "No container or app specified"
fi
if [[ -z "$APP" ]] && [[ -z "$CONTAINER_NAME" ]]; then
dokku_log_fail "No container or app specified"
fi
if [[ -n "$CONTAINER_NAME" ]]; then
if [[ "$(echo "$CONTAINER_NAME" | grep -o '\.' | wc -l)" -ne 2 ]]; then
dokku_log_fail "Invalid container name specified: $CONTAINER_NAME"
fi
APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)"
local CONTAINER_APP="$(echo "$CONTAINER_NAME" | cut -d'.' -f1)"
if [[ -n "$APP" ]] && [[ "$APP" != "$CONTAINER_APP" ]]; then
dokku_log_fail "Specified app does not match app in container name"
fi
APP="$CONTAINER_APP"
STATE="$(echo "$CONTAINER_NAME" | cut -d'.' -f2)"
if [[ "$STATE" != "run" ]]; then
dokku_log_fail "Specified container must be a run container"
@@ -53,7 +74,7 @@ trigger-scheduler-docker-local-scheduler-run-stop() {
DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds || true)"
if [[ -n "$CONTAINER_NAME" ]]; then
fn-scheduler-docker-local-stop-container "$CONTAINER_NAME" "$DOKKU_DOCKER_STOP_TIMEOUT"
fn-scheduler-docker-local-stop-app-run-container "$APP" "$CONTAINER_NAME" "$DOKKU_DOCKER_STOP_TIMEOUT"
return $?
fi

View File

@@ -25,11 +25,8 @@ cmd-traefik-set() {
dokku_log_fail "Invalid key specified, valid keys include: api-enabled api-entry-point api-entry-point-address api-vhost challenge-mode dashboard-enabled basic-auth-username basic-auth-password dns-provider dns-provider-<ENV_VAR> image letsencrypt-email letsencrypt-server log-level http-entry-point https-entry-point"
fi
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$is_dns_provider_env_var" != "true" ]]; then
if [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
verify_app_name "$APP"
if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}" && [[ "$is_dns_provider_env_var" != "true" ]] && [[ "$APP" == "--global" ]]; then
dokku_log_fail "The key '$KEY' cannot be set globally"
fi
# dns-provider-* keys and GLOBAL_ONLY_KEYS can only be set globally
@@ -41,6 +38,8 @@ cmd-traefik-set() {
dokku_log_fail "The key '$KEY' can only be set globally"
fi
[[ "$APP" == "--global" ]] || verify_app_name "$APP"
if [[ -n "$VALUE" ]]; then
dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
fn-plugin-property-write "traefik" "$APP" "$KEY" "$VALUE"

View File

@@ -82,3 +82,16 @@ teardown() {
assert_success
assert_output "false"
}
@test "(caddy:set) missing app" {
run /bin/bash -c "dokku caddy:set missing-app tls-internal true"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/caddy/missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
}

View File

@@ -194,3 +194,11 @@ teardown() {
assert_success
assert_output "--label=a=b"
}
@test "(core) cleanup missing app" {
run /bin/bash -c "dokku cleanup missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
}

View File

@@ -136,6 +136,20 @@ teardown() {
assert_failure
}
@test "(domains) domains:enable and domains:disable (missing app)" {
run /bin/bash -c "dokku domains:disable missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
run /bin/bash -c "dokku domains:enable missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
}
@test "(domains) domains:remove" {
run /bin/bash -c "dokku domains:add $TEST_APP test.app.${DOKKU_DOMAIN}"
echo "output: $output"

View File

@@ -698,3 +698,16 @@ teardown() {
assert_output_contains "Attempting pre-flight checks" 0
assert_output_contains "Application deployed"
}
@test "(network:rebuild) missing app" {
run /bin/bash -c "dokku network:rebuild missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/common/missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
}

View File

@@ -107,3 +107,16 @@ assert_nginx_property_set_get() {
assert_nginx_property_set_get "nginx-conf-sigil-path" "custom.sigil" "global.sigil"
assert_nginx_property_set_get "nginx-service-command" "/usr/sbin/nginx-app" "/usr/sbin/nginx-global"
}
@test "(nginx:set) missing app" {
run /bin/bash -c "dokku nginx:set missing-app hsts false"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/nginx/missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
}

View File

@@ -82,3 +82,16 @@ teardown() {
assert_success
assert_output "5m"
}
@test "(openresty:set) missing app" {
run /bin/bash -c "dokku openresty:set missing-app client-max-body-size 5m"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
run /bin/bash -c "test -e $DOKKU_LIB_ROOT/config/openresty/missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
}

View File

@@ -92,3 +92,11 @@ teardown() {
echo "status: $status"
assert_output "console: 0"
}
@test "(ps:retire) missing app" {
run /bin/bash -c "dokku ps:retire missing-app"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App missing-app does not exist"
}

View File

@@ -8,6 +8,7 @@ setup() {
}
teardown() {
docker container rm -f "$TEST_APP.run.9999" >/dev/null 2>&1 || true
destroy_app
global_teardown
}
@@ -157,6 +158,58 @@ teardown() {
assert_output "2"
}
@test "(run:stop) only stops run containers for the app" {
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku run:detached $TEST_APP sleep 300"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku run:list $TEST_APP --format json | jq -r '.[0].name'"
echo "output: $output"
echo "status: $status"
assert_success
local RUN_CONTAINER="$output"
run /bin/bash -c "docker container run -d --name $TEST_APP.run.9999 --entrypoint sleep dokku/$TEST_APP:latest 300"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku run:stop $TEST_APP --container other-app.run.1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Specified app does not match app in container name"
run /bin/bash -c "dokku run:stop $TEST_APP --container $TEST_APP.run.9999"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Specified container does not exist"
run /bin/bash -c "docker container inspect -f '{{.State.Running}}' $TEST_APP.run.9999"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku run:stop $TEST_APP --container $RUN_CONTAINER"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker container ls -q --filter name=^/$RUN_CONTAINER\$ | wc -l"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "0"
}
@test "(run) docker-options and -e flags are not eval-injected" {
run deploy_app
echo "output: $output"