diff --git a/docs/parameters.md b/docs/parameters.md index 1b4ce9ca71..890927501d 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -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 diff --git a/docs/security_considerations.md b/docs/security_considerations.md index 56f33c2a87..564349e3f2 100644 --- a/docs/security_considerations.md +++ b/docs/security_considerations.md @@ -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. - diff --git a/src/BUILD b/src/BUILD index 1e2368327b..fe3a1c6f16 100644 --- a/src/BUILD +++ b/src/BUILD @@ -1425,6 +1425,8 @@ ovms_cc_library( "libovms_kfs_utils", "libovms_tensorinfo", "libovmsprecision", + "libovms_config", + "cpp_headers", ], visibility = ["//visibility:public",], ) @@ -1468,6 +1470,8 @@ ovms_cc_library( srcs = ["capi_frontend/inferenceparameter.cpp",], deps = [ "ovms_header", + "libovms_config", + "cpp_headers", "libovmscapi_utils_h", # TODO @atobisze ], visibility = ["//visibility:public"], diff --git a/src/capi_frontend/server_settings.hpp b/src/capi_frontend/server_settings.hpp index fa21d03be2..df3913a13c 100644 --- a/src/capi_frontend/server_settings.hpp +++ b/src/capi_frontend/server_settings.hpp @@ -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{"*"}; diff --git a/src/cli_parser.cpp b/src/cli_parser.cpp index d7125abc87..44d533f1c2 100644 --- a/src/cli_parser.cpp +++ b/src/cli_parser.cpp @@ -125,6 +125,10 @@ std::variant> CLIParser::parse(int argc, char* "\"__verbose\" object with additional debug information.", cxxopts::value()->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()->default_value("false"), + "DISABLE_INPUT_COUNT_VALIDATION") #ifdef MTR_ENABLED ("trace_path", "Path to the trace file", @@ -577,6 +581,8 @@ void CLIParser::prepareServer(ServerSettingsImpl& serverSettings) { serverSettings.logPath = result->operator[]("log_path").as(); if (result->count("verbose_response")) serverSettings.verboseResponse = result->operator[]("verbose_response").as(); + if (result->count("disable_input_count_validation")) + serverSettings.disableInputCountValidation = result->operator[]("disable_input_count_validation").as(); if (result->count("grpc_channel_arguments")) serverSettings.grpcChannelArguments = result->operator[]("grpc_channel_arguments").as(); diff --git a/src/config.cpp b/src/config.cpp index cdbd47c6f0..28e15bbf12 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -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; } diff --git a/src/config.hpp b/src/config.hpp index d710bc4e9a..45cea149c3 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -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; diff --git a/src/predict_request_validation_utils.hpp b/src/predict_request_validation_utils.hpp index 31e7eb8fb5..8923b28337 100644 --- a/src/predict_request_validation_utils.hpp +++ b/src/predict_request_validation_utils.hpp @@ -20,6 +20,7 @@ #include #include +#include "config.hpp" #include "logging.hpp" #include "modelversion.hpp" #include "shape.hpp" @@ -290,7 +291,9 @@ Status RequestValidatorset_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();