Add nice error message for users trying to set uuid or isEditable

This commit is contained in:
Mubelotix
2025-08-04 16:53:41 +02:00
parent 3b26d64a5d
commit ddfcacbb62
3 changed files with 111 additions and 8 deletions

View File

@ -425,7 +425,9 @@ InvalidWebhooksUrl , InvalidRequest , BAD_REQU
InvalidWebhooksHeaders , InvalidRequest , BAD_REQUEST ;
ReservedWebhook , InvalidRequest , BAD_REQUEST ;
InvalidWebhookUuid , InvalidRequest , BAD_REQUEST ;
WebhookNotFound , InvalidRequest , NOT_FOUND
WebhookNotFound , InvalidRequest , NOT_FOUND ;
ImmutableWebhookUuid , InvalidRequest , BAD_REQUEST ;
ImmutableWebhookIsEditable , InvalidRequest , BAD_REQUEST
}
impl ErrorCode for JoinError {

View File

@ -7,12 +7,15 @@ use actix_http::header::{
};
use actix_web::web::{self, Data, Path};
use actix_web::{HttpRequest, HttpResponse};
use core::convert::Infallible;
use deserr::actix_web::AwebJson;
use deserr::Deserr;
use deserr::{DeserializeError, Deserr, ValuePointerRef};
use index_scheduler::IndexScheduler;
use meilisearch_types::deserr::DeserrJsonError;
use meilisearch_types::error::deserr_codes::{InvalidWebhooksHeaders, InvalidWebhooksUrl};
use meilisearch_types::error::{ErrorCode, ResponseError};
use meilisearch_types::deserr::{immutable_field_error, DeserrJsonError};
use meilisearch_types::error::deserr_codes::{
BadRequest, InvalidWebhooksHeaders, InvalidWebhooksUrl,
};
use meilisearch_types::error::{Code, ErrorCode, ResponseError};
use meilisearch_types::keys::actions;
use meilisearch_types::milli::update::Setting;
use meilisearch_types::webhooks::Webhook;
@ -54,7 +57,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
}
#[derive(Debug, Deserr, ToSchema)]
#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)]
#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields = deny_immutable_fields_webhook)]
#[serde(rename_all = "camelCase")]
#[schema(rename_all = "camelCase")]
pub(super) struct WebhookSettings {
@ -68,6 +71,22 @@ pub(super) struct WebhookSettings {
headers: Setting<BTreeMap<String, Setting<String>>>,
}
fn deny_immutable_fields_webhook(
field: &str,
accepted: &[&str],
location: ValuePointerRef,
) -> DeserrJsonError {
match field {
"uuid" => immutable_field_error(field, accepted, Code::ImmutableWebhookUuid),
"isEditable" => immutable_field_error(field, accepted, Code::ImmutableWebhookIsEditable),
_ => deserr::take_cf_content(DeserrJsonError::<BadRequest>::error::<Infallible>(
None,
deserr::ErrorKind::UnknownKey { key: field, accepted },
location,
)),
}
}
#[derive(Debug, Serialize, ToSchema)]
#[serde(rename_all = "camelCase")]
#[schema(rename_all = "camelCase")]

View File

@ -273,7 +273,7 @@ async fn reserved_names() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Cannot edit webhook `[uuid]`. Webhooks prefixed with an underscore are reserved and may not be modified using the API.",
"message": "Cannot edit webhook `[uuid]`. The webhook defined from the command line cannot be modified using the API.",
"code": "reserved_webhook",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#reserved_webhook"
@ -284,7 +284,7 @@ async fn reserved_names() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Cannot edit webhook `[uuid]`. Webhooks prefixed with an underscore are reserved and may not be modified using the API.",
"message": "Cannot edit webhook `[uuid]`. The webhook defined from the command line cannot be modified using the API.",
"code": "reserved_webhook",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#reserved_webhook"
@ -562,3 +562,85 @@ async fn invalid_uuid() {
}
"#);
}
#[actix_web::test]
async fn forbidden_fields() {
let server = Server::new().await;
// Test creating webhook with uuid field
let custom_uuid = Uuid::new_v4();
let (value, code) = server
.create_webhook(json!({
"url": "https://example.com/hook",
"uuid": custom_uuid.to_string(),
"headers": { "authorization": "TOKEN" }
}))
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Immutable field `uuid`: expected one of `url`, `headers`",
"code": "immutable_webhook_uuid",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#immutable_webhook_uuid"
}
"#);
// Test creating webhook with isEditable field
let (value, code) = server
.create_webhook(json!({
"url": "https://example.com/hook2",
"isEditable": false,
"headers": { "authorization": "TOKEN" }
}))
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Immutable field `isEditable`: expected one of `url`, `headers`",
"code": "immutable_webhook_is_editable",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#immutable_webhook_is_editable"
}
"#);
// Test patching webhook with uuid field
let (value, code) = server
.patch_webhook(
"uuid-whatever",
json!({
"uuid": Uuid::new_v4(),
"headers": { "new-header": "value" }
}),
)
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Immutable field `uuid`: expected one of `url`, `headers`",
"code": "immutable_webhook_uuid",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#immutable_webhook_uuid"
}
"#);
// Test patching webhook with isEditable field
let (value, code) = server
.patch_webhook(
"uuid-whatever",
json!({
"isEditable": false,
"headers": { "another-header": "value" }
}),
)
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(json_string!(value, { ".uuid" => "[uuid]" }), @r#"
{
"message": "Immutable field `isEditable`: expected one of `url`, `headers`",
"code": "immutable_webhook_is_editable",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#immutable_webhook_is_editable"
}
"#);
}