Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Configuration options for the server are defined only via command-line options a
| `allowed_local_media_path` | `string` | Path to the directory containing images to include in requests. If unset, local filesystem images in requests are not supported.|
| `allowed_media_domains` | `string` | Comma separated list of media domains from which URLs can be used as input for LLMs. Set to \"all\" to disable this restrictions. If unset, URLs in requests are not supported."
| `verbose_response` | `NA` | When enabled, responses include an extra `__verbose` object with additional debug information. Applies for text generation models |
| `disable_input_count_validation` | `bool` (default: false) | Disables enforcement for the KServe requests to match all the model inputs. It ignores all inputs which are not used in the model. Not recommended for performance reasons but in some cases might simplify the client. |

## Config management mode options

Expand Down
1 change: 0 additions & 1 deletion docs/security_considerations.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,3 @@ OpenVINO Model Server has a set of mechanisms preventing denial of service attac
---

- MediaPipe does not validate all the settings during graph initialization. Some settings are checked during graph creation phase (upon request processing). Therefore it is a good practice to always test the configuration by sending example requests to the KServe endpoints before deployment.

4 changes: 4 additions & 0 deletions src/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,8 @@ ovms_cc_library(
"libovms_kfs_utils",
"libovms_tensorinfo",
"libovmsprecision",
"libovms_config",
"cpp_headers",
],
visibility = ["//visibility:public",],
)
Expand Down Expand Up @@ -1468,6 +1470,8 @@ ovms_cc_library(
srcs = ["capi_frontend/inferenceparameter.cpp",],
deps = [
"ovms_header",
"libovms_config",
"cpp_headers",
"libovmscapi_utils_h", # TODO @atobisze
Comment thread
przepeck marked this conversation as resolved.
],
visibility = ["//visibility:public"],
Expand Down
1 change: 1 addition & 0 deletions src/capi_frontend/server_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ struct ServerSettingsImpl {
std::string logLevel = "INFO";
std::string logPath;
bool verboseResponse = false;
bool disableInputCountValidation = false;
bool allowCredentials = false;
std::string allowedOrigins{"*"};
std::string allowedMethods{"*"};
Expand Down
6 changes: 6 additions & 0 deletions src/cli_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ std::variant<bool, std::pair<int, std::string>> CLIParser::parse(int argc, char*
"\"__verbose\" object with additional debug information.",
cxxopts::value<bool>()->default_value("false"),
"VERBOSE_RESPONSE")
("disable_input_count_validation",
"When enabled, OVMS allows inference requests to include additional, unrecognized inputs beyond the model/pipeline signature (extra inputs are ignored). Required inputs must still be present, and shape/precision validation is still performed for recognized inputs. Default: false (extra inputs cause the request to be rejected).",
cxxopts::value<bool>()->default_value("false"),
"DISABLE_INPUT_COUNT_VALIDATION")
#ifdef MTR_ENABLED
("trace_path",
"Path to the trace file",
Expand Down Expand Up @@ -577,6 +581,8 @@ void CLIParser::prepareServer(ServerSettingsImpl& serverSettings) {
serverSettings.logPath = result->operator[]("log_path").as<std::string>();
if (result->count("verbose_response"))
serverSettings.verboseResponse = result->operator[]("verbose_response").as<bool>();
if (result->count("disable_input_count_validation"))
serverSettings.disableInputCountValidation = result->operator[]("disable_input_count_validation").as<bool>();

if (result->count("grpc_channel_arguments"))
serverSettings.grpcChannelArguments = result->operator[]("grpc_channel_arguments").as<std::string>();
Expand Down
1 change: 1 addition & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ const std::string& Config::tracePath() const { return this->serverSettings.trace
const std::string& Config::grpcChannelArguments() const { return this->serverSettings.grpcChannelArguments; }
uint32_t Config::filesystemPollWaitMilliseconds() const { return this->serverSettings.filesystemPollWaitMilliseconds; }
uint32_t Config::resourcesCleanerPollWaitSeconds() const { return this->serverSettings.resourcesCleanerPollWaitSeconds; }
bool Config::disableInputCountValidation() const { return this->serverSettings.disableInputCountValidation; }
bool Config::allowCredentials() const { return this->serverSettings.allowCredentials; }
const std::string& Config::allowedOrigins() const { return this->serverSettings.allowedOrigins; }
const std::string& Config::allowedMethods() const { return this->serverSettings.allowedMethods; }
Expand Down
1 change: 1 addition & 0 deletions src/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ class Config {
*/
uint32_t resourcesCleanerPollWaitSeconds() const;

bool disableInputCountValidation() const;
bool allowCredentials() const;
const std::string& allowedOrigins() const;
const std::string& allowedMethods() const;
Expand Down
5 changes: 4 additions & 1 deletion src/predict_request_validation_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <string>
#include <vector>

#include "config.hpp"
#include "logging.hpp"
#include "modelversion.hpp"
#include "shape.hpp"
Expand Down Expand Up @@ -290,7 +291,9 @@ Status RequestValidator<RequestType, InputTensorType, choice, IteratorType, Shap
return StatusCode::NOT_IMPLEMENTED;
}
Status finalStatus = StatusCode::OK;
RETURN_IF_ERR(validateNumberOfTensors());
if (choice == ValidationChoice::INPUT && !ovms::Config::instance().disableInputCountValidation()) {
RETURN_IF_ERR(validateNumberOfTensors());
}
RETURN_IF_ERR(validateRequestCoherency());
Comment on lines 293 to 297

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot agree with this comment, error "INVALID_MISSING_INPUT" is better for described scenario

size_t bufferId = 0;
for (const auto& [name, tensorInfo] : ((choice == ValidationChoice::INPUT) ? inputsInfo : outputsInfo)) {
Expand Down
20 changes: 19 additions & 1 deletion src/test/ovmsconfig_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2488,6 +2488,7 @@ TEST(OvmsConfigTest, positiveMulti) {
"--allowed_headers", "Content-Type",
"--allowed_methods", "GET,POST",
"--allowed_origins", "example.com,example.org",
"--disable_input_count_validation",
#ifdef _WIN32
"--grpc_workers", "1",
"--cpu_extension", "tmp_cpu_extension_library_dir",
Expand All @@ -2504,7 +2505,7 @@ TEST(OvmsConfigTest, positiveMulti) {
"--grpc_memory_quota", "1000000",
"--config_path", "/config.json"};

int arg_count = 44;
int arg_count = 45;
ConstructorEnabledConfig config;
config.parse(arg_count, n_argv);

Expand All @@ -2516,6 +2517,7 @@ TEST(OvmsConfigTest, positiveMulti) {
EXPECT_EQ(config.grpcChannelArguments(), "grpc_channel_args");
EXPECT_EQ(config.filesystemPollWaitMilliseconds(), 2000);
EXPECT_EQ(config.resourcesCleanerPollWaitSeconds(), 8);
EXPECT_TRUE(config.disableInputCountValidation());
#ifdef _WIN32
EXPECT_EQ(config.cpuExtensionLibraryPath(), cpu_extension_lib_path);
EXPECT_EQ(config.grpcWorkers(), 1);
Expand Down Expand Up @@ -2547,6 +2549,22 @@ TEST(OvmsConfigTest, positiveMulti) {
#endif
}

TEST(OvmsConfigTest, disableInputCountValidationDefaultsToFalse) {
char* n_argv[] = {
"ovms",
"--rest_port",
"45",
"--model_name",
"model",
"--model_path",
"/path",
};
int arg_count = 7;
ConstructorEnabledConfig config;
config.parse(arg_count, n_argv);
EXPECT_FALSE(config.disableInputCountValidation());
}

TEST(OvmsConfigTest, allowedLocalMediaPathRelativeIsNormalized) {
char* n_argv[] = {
"ovms",
Expand Down
42 changes: 42 additions & 0 deletions src/test/predict_validation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,48 @@ TEST_F(KFSPredictValidation, RequestTooManyInputs) {
EXPECT_EQ(status, ovms::StatusCode::INVALID_NO_OF_INPUTS) << status.string();
}

class KFSPredictValidationInputCountConfig : public KFSPredictValidation {
protected:
ovms::ServerSettingsImpl originalServerSettings;
ovms::ModelsSettingsImpl originalModelsSettings;

void SetUp() override {
KFSPredictValidation::SetUp();
originalServerSettings = ovms::Config::instance().getServerSettings();
originalModelsSettings = ovms::Config::instance().getModelSettings();
}

void setDisableInputCountValidation(bool value) {
ovms::ServerSettingsImpl testServerSettings = originalServerSettings;
testServerSettings.disableInputCountValidation = value;
ovms::Config::instance().parse(&testServerSettings, &originalModelsSettings);
}

void TearDown() override {
ovms::Config::instance().parse(&originalServerSettings, &originalModelsSettings);
KFSPredictValidation::TearDown();
}
};

TEST_F(KFSPredictValidationInputCountConfig, RequestTooManyInputsWithDisabledInputCountValidation) {
setDisableInputCountValidation(true);

auto inputWrongName = request.add_inputs();
inputWrongName->set_name("Some_Input");
request.add_raw_input_contents(); // keep raw_input_contents count in sync with inputs count
auto status = instance->mockValidate(&request);
EXPECT_TRUE(status.ok()) << status.string();
}

TEST_F(KFSPredictValidationInputCountConfig, RequestTooManyInputsWithEnabledInputCountValidation) {
setDisableInputCountValidation(false);

auto inputWrongName = request.add_inputs();
inputWrongName->set_name("Some_Input");
auto status = instance->mockValidate(&request);
EXPECT_EQ(status, ovms::StatusCode::INVALID_NO_OF_INPUTS) << status.string();
}

TEST_F(KFSPredictValidation, RequestWrongInputName) {
request.mutable_inputs()->RemoveLast(); // remove redundant input
auto inputWrongName = request.add_inputs();
Expand Down