Skip to content

Commit 36f4b17

Browse files
authored
ci: Add model name validation for model management requests (#8672)
1 parent df3dec3 commit 36f4b17

2 files changed

Lines changed: 99 additions & 2 deletions

File tree

qa/L0_input_validation/input_validation_test.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python
2-
# Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
#
44
# Redistribution and use in source and binary forms, with or without
55
# modification, are permitted provided that the following conditions
@@ -288,5 +288,76 @@ def inference_helper(model_name, batch_size=1):
288288
inference_helper(model_name="plan_zero_1_float32_int32", batch_size=8)
289289

290290

291+
class ModelNameValidationTest(unittest.TestCase):
292+
INVALID_TRAVERSAL_NAMES = [
293+
"../etc",
294+
"a/../b",
295+
"../../etc/passwd",
296+
"../../../../etc",
297+
"model/..",
298+
"..",
299+
"/etc/passwd",
300+
"model/subdir",
301+
"model/",
302+
" ..",
303+
".. ",
304+
]
305+
306+
def test_model_name_invalid_load(self):
307+
client = tritongrpcclient.InferenceServerClient("localhost:8001")
308+
for model_name in self.INVALID_TRAVERSAL_NAMES:
309+
with self.assertRaises(InferenceServerException) as cm:
310+
client.load_model(model_name)
311+
self.assertIn(
312+
"model name must not contain path traversal characters",
313+
str(cm.exception),
314+
f"Expected traversal rejection for model name: {model_name!r}",
315+
)
316+
317+
def test_model_name_empty_load(self):
318+
client = tritongrpcclient.InferenceServerClient("localhost:8001")
319+
with self.assertRaises(InferenceServerException) as cm:
320+
client.load_model("")
321+
self.assertIn("model name must not be empty", str(cm.exception))
322+
323+
def test_model_name_whitespace_only_load(self):
324+
client = tritongrpcclient.InferenceServerClient("localhost:8001")
325+
whitespace_names = [" ", " ", "\t", "\n", "\r", "\f", "\v", " \t \n "]
326+
for model_name in whitespace_names:
327+
with self.assertRaises(InferenceServerException) as cm:
328+
client.load_model(model_name)
329+
self.assertIn(
330+
"model name must not contain only whitespace",
331+
str(cm.exception),
332+
f"Expected whitespace-only rejection for model name: {model_name!r}",
333+
)
334+
335+
def test_model_name_invalid_unload(self):
336+
# Unload should not trigger traversal check
337+
client = tritongrpcclient.InferenceServerClient("localhost:8001")
338+
for model_name in self.INVALID_TRAVERSAL_NAMES:
339+
try:
340+
client.unload_model(model_name)
341+
except InferenceServerException as e:
342+
self.assertNotIn(
343+
"model name must not contain path traversal characters",
344+
str(e),
345+
f"Unload should not trigger traversal rejection for model name: {model_name!r}",
346+
)
347+
348+
def test_model_name_valid(self):
349+
"""Verify that a syntactically valid model name is not rejected by
350+
the traversal check -- it should fail with a model not found error instead."""
351+
client = tritongrpcclient.InferenceServerClient("localhost:8001")
352+
with self.assertRaises(InferenceServerException) as cm:
353+
client.load_model("nonexistent_model")
354+
self.assertNotIn(
355+
"path traversal characters",
356+
str(cm.exception),
357+
"Valid model name should not trigger path traversal rejection",
358+
)
359+
self.assertIn("failed to poll from model repository", str(cm.exception))
360+
361+
291362
if __name__ == "__main__":
292363
unittest.main()

qa/L0_input_validation/test.sh

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/bash
2-
# Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
#
44
# Redistribution and use in source and binary forms, with or without
55
# modification, are permitted provided that the following conditions
@@ -175,6 +175,32 @@ if [ $? -ne 0 ]; then
175175
fi
176176
set -e
177177

178+
# Model name validation test
179+
rm -rf test_models ; mkdir -p test_models
180+
SERVER_LOG="./model_name_validation_server.log"
181+
CLIENT_LOG="./model_name_validation_client.log"
182+
SERVER_ARGS="--model-repository=`pwd`/test_models --model-control-mode=explicit --log-verbose=1"
183+
run_server
184+
if [ "$SERVER_PID" == "0" ]; then
185+
echo -e "\n***\n*** Failed to start $SERVER\n***"
186+
cat $SERVER_LOG
187+
exit 1
188+
fi
189+
190+
set +e
191+
python3 -m pytest -s --junitxml="model_name_validation.report.xml" $TEST_PY::ModelNameValidationTest >> $CLIENT_LOG 2>&1
192+
193+
if [ $? -ne 0 ]; then
194+
cat $CLIENT_LOG
195+
cat $SERVER_LOG
196+
echo -e "\n***\n*** input_validation_test.py::ModelNameValidationTest FAILED. \n***"
197+
RET=1
198+
fi
199+
set -e
200+
201+
kill $SERVER_PID
202+
wait $SERVER_PID
203+
178204
if [ $RET -eq 0 ]; then
179205
echo -e "\n***\n*** Input Validation Test Passed\n***"
180206
else

0 commit comments

Comments
 (0)