Skip to content

Commit 2157d1a

Browse files
committed
ingress: Sanitize env vars
1 parent 401dd24 commit 2157d1a

File tree

4 files changed

+160
-1
lines changed

4 files changed

+160
-1
lines changed

custom-domain/dstack-ingress/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ configs:
176176
- `CERTBOT_EMAIL`: Your email address used in Let's Encrypt certificate requests
177177
- `TARGET_ENDPOINT`: The plain HTTP endpoint of your dstack application (for single domain mode)
178178
- `SET_CAA`: Set to `true` to enable CAA record setup
179-
- `CLIENT_MAX_BODY_SIZE`: Optional value for nginx `client_max_body_size` (e.g. `50m`) in single-domain mode
179+
- `CLIENT_MAX_BODY_SIZE`: Optional value for nginx `client_max_body_size` (numeric with optional `k|m|g` suffix, e.g. `50m`) in single-domain mode
180180

181181
**Backward Compatibility:**
182182

custom-domain/dstack-ingress/scripts/entrypoint.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,27 @@
22

33
set -e
44

5+
source "/scripts/functions.sh"
6+
57
PORT=${PORT:-443}
68
TXT_PREFIX=${TXT_PREFIX:-"_dstack-app-address"}
9+
10+
if ! PORT=$(sanitize_port "$PORT"); then
11+
exit 1
12+
fi
13+
if ! DOMAIN=$(sanitize_domain "$DOMAIN"); then
14+
exit 1
15+
fi
16+
if ! TARGET_ENDPOINT=$(sanitize_target_endpoint "$TARGET_ENDPOINT"); then
17+
exit 1
18+
fi
19+
if ! CLIENT_MAX_BODY_SIZE=$(sanitize_client_max_body_size "$CLIENT_MAX_BODY_SIZE"); then
20+
exit 1
21+
fi
22+
if ! TXT_PREFIX=$(sanitize_dns_label "$TXT_PREFIX"); then
23+
exit 1
24+
fi
25+
726
PROXY_CMD="proxy"
827
if [[ "${TARGET_ENDPOINT}" == grpc://* ]]; then
928
PROXY_CMD="grpc"
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
3+
# Sanitizer helpers shared across scripts. Each function echoes the sanitized
4+
# value on success; on failure it writes an error to stderr and returns non-zero.
5+
6+
sanitize_port() {
7+
local candidate="$1"
8+
if [[ "$candidate" =~ ^[0-9]+$ ]] && (( candidate >= 1 && candidate <= 65535 )); then
9+
echo "$candidate"
10+
else
11+
echo "Error: Invalid PORT value: $candidate" >&2
12+
return 1
13+
fi
14+
}
15+
16+
sanitize_domain() {
17+
local candidate="$1"
18+
if [ -z "$candidate" ]; then
19+
echo ""
20+
return 0
21+
fi
22+
if [[ "$candidate" =~ ^(\*\.)?[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$ ]]; then
23+
echo "$candidate"
24+
else
25+
echo "Error: Invalid DOMAIN value: $candidate" >&2
26+
return 1
27+
fi
28+
}
29+
30+
sanitize_target_endpoint() {
31+
local candidate="$1"
32+
if [ -z "$candidate" ]; then
33+
echo ""
34+
return 0
35+
fi
36+
if [[ "$candidate" =~ ^(grpc|https?)://[A-Za-z0-9._-]+(:[0-9]{1,5})?(/[A-Za-z0-9._~:/?&=%-]*)?$ ]]; then
37+
echo "$candidate"
38+
else
39+
echo "Error: Invalid TARGET_ENDPOINT value: $candidate" >&2
40+
return 1
41+
fi
42+
}
43+
44+
sanitize_client_max_body_size() {
45+
local candidate="$1"
46+
if [ -z "$candidate" ]; then
47+
echo ""
48+
return 0
49+
fi
50+
if [[ "$candidate" =~ ^[0-9]+[kKmMgG]?$ ]]; then
51+
echo "$candidate"
52+
else
53+
echo "Warning: Ignoring invalid CLIENT_MAX_BODY_SIZE value: $candidate" >&2
54+
echo ""
55+
fi
56+
}
57+
58+
sanitize_dns_label() {
59+
local candidate="$1"
60+
if [ -z "$candidate" ]; then
61+
echo "Error: TXT_PREFIX cannot be empty" >&2
62+
return 1
63+
fi
64+
if [[ "$candidate" =~ ^[A-Za-z0-9_-]+$ ]]; then
65+
echo "$candidate"
66+
else
67+
echo "Error: Invalid TXT_PREFIX value: $candidate" >&2
68+
return 1
69+
fi
70+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
THIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
SCRIPTS_DIR="$(cd "${THIS_DIR}/.." && pwd)"
7+
8+
# shellcheck source=../functions.sh
9+
source "${SCRIPTS_DIR}/functions.sh"
10+
11+
failures=0
12+
13+
assert_equal() {
14+
local actual="$1"
15+
local expected="$2"
16+
local msg="$3"
17+
if [[ "$actual" != "$expected" ]]; then
18+
echo "FAIL: ${msg} (expected '${expected}', got '${actual}')" >&2
19+
failures=$((failures + 1))
20+
else
21+
echo "PASS: ${msg}"
22+
fi
23+
}
24+
25+
assert_fails() {
26+
local msg="$1"
27+
shift
28+
local output_file
29+
output_file="$(mktemp)"
30+
if "$@" >"$output_file" 2>&1; then
31+
echo "FAIL: ${msg} (expected failure)" >&2
32+
cat "$output_file" >&2
33+
failures=$((failures + 1))
34+
else
35+
cat "$output_file"
36+
echo "PASS: ${msg}"
37+
fi
38+
rm -f "$output_file"
39+
}
40+
41+
# Successful cases
42+
assert_equal "$(sanitize_port 8080)" "8080" "sanitize_port accepts numeric port"
43+
assert_equal "$(sanitize_domain example.com)" "example.com" "sanitize_domain accepts fqdn"
44+
assert_equal "$(sanitize_domain '*.example.com')" "*.example.com" "sanitize_domain accepts wildcard"
45+
assert_equal "$(sanitize_target_endpoint http://service:80/path)" "http://service:80/path" "sanitize_target_endpoint accepts http"
46+
assert_equal "$(sanitize_target_endpoint grpc://svc:50051)" "grpc://svc:50051" "sanitize_target_endpoint accepts grpc"
47+
assert_equal "$(sanitize_client_max_body_size 50m)" "50m" "sanitize_client_max_body_size accepts suffix"
48+
assert_equal "$(sanitize_dns_label test_label)" "test_label" "sanitize_dns_label accepts lowercase"
49+
assert_equal "$(sanitize_dns_label test-label)" "test-label" "sanitize_dns_label accepts hyphen"
50+
51+
# Failing cases
52+
assert_fails "sanitize_port rejects non-numeric" sanitize_port abc
53+
assert_fails "sanitize_domain rejects invalid domain" sanitize_domain bad_domain
54+
assert_fails "sanitize_target_endpoint rejects malformed URL" sanitize_target_endpoint "http:///broken"
55+
warning_output="$(sanitize_client_max_body_size "50mb" 2>&1 || true)"
56+
if [[ "$warning_output" == "Warning: Ignoring invalid CLIENT_MAX_BODY_SIZE value: 50mb" ]]; then
57+
echo "PASS: sanitize_client_max_body_size warns and returns empty"
58+
else
59+
echo "FAIL: sanitize_client_max_body_size warning unexpected"
60+
printf '%s\n' "$warning_output"
61+
failures=$((failures + 1))
62+
fi
63+
assert_fails "sanitize_dns_label rejects invalid characters" sanitize_dns_label "bad*label"
64+
65+
if [[ $failures -eq 0 ]]; then
66+
echo "All sanitizer tests passed"
67+
else
68+
echo "$failures sanitizer tests failed" >&2
69+
exit 1
70+
fi

0 commit comments

Comments
 (0)