This commit is contained in:
Mubelotix
2025-07-17 11:11:33 +02:00
parent cc9fd82f79
commit 3191316cf3
9 changed files with 145 additions and 199 deletions

View File

@ -138,7 +138,9 @@ pub trait Policy {
auth: Data<AuthController>,
token: &str,
index: Option<&str>,
) -> Result<AuthFilter, policies::AuthError> where Self: Sized;
) -> Result<AuthFilter, policies::AuthError>
where
Self: Sized;
}
pub mod policies {

View File

@ -424,7 +424,8 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
fragment.clone()
}
found => return Err(UnknownTemplatePrefix {
found => {
return Err(UnknownTemplatePrefix {
embedder_name: embedder_name.to_string(),
found: found.to_string(),
available_indexing_fragments: embedding_config
@ -435,7 +436,8 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
.config
.embedder_options
.search_fragments(),
}),
})
}
}
}
"chatCompletions" | "chatcompletions" => {

View File

@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet};
use ::time::format_description::well_known::Rfc3339;
use maplit::{hashmap};
use maplit::hashmap;
use meilisearch::Opt;
use once_cell::sync::Lazy;
use tempfile::TempDir;
@ -33,8 +33,9 @@ macro_rules! hashset {
}
#[allow(clippy::type_complexity)]
pub static AUTHORIZATIONS: Lazy<HashMap<(&'static str, &'static str), HashSet<&'static [&'static str]>>> =
Lazy::new(|| {
pub static AUTHORIZATIONS: Lazy<
HashMap<(&'static str, &'static str), HashSet<&'static [&'static str]>>,
> = Lazy::new(|| {
let authorizations = hashmap! {
("POST", "/multi-search") => hashset!{"search", "*"},
("POST", "/indexes/products/search") => hashset!{"search", "*"},
@ -97,10 +98,15 @@ pub static AUTHORIZATIONS: Lazy<HashMap<(&'static str, &'static str), HashSet<&'
};
authorizations
});
});
pub static ALL_ACTIONS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
AUTHORIZATIONS.values().flat_map(|v| v.iter()).flat_map(|v| v.iter()).copied().collect::<HashSet<_>>()
AUTHORIZATIONS
.values()
.flat_map(|v| v.iter())
.flat_map(|v| v.iter())
.copied()
.collect::<HashSet<_>>()
});
static INVALID_RESPONSE: Lazy<Value> = Lazy::new(|| {
@ -298,7 +304,11 @@ async fn unauthorized_partial_actions() {
// create a new API key letting all actions except one.
server.use_api_key(MASTER_KEY);
let actions = actions.iter().filter(|&a| a != excluded_action).copied().collect::<HashSet<_>>();
let actions = actions
.iter()
.filter(|&a| a != excluded_action)
.copied()
.collect::<HashSet<_>>();
let content = json!({
"indexes": ["products"],
"actions": actions,
@ -315,7 +325,14 @@ async fn unauthorized_partial_actions() {
let (mut response, code) = server.dummy_request(method, route).await;
response["message"] = serde_json::json!(null);
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?} with actions: {:?}", method, route, actions);
assert_eq!(
response,
INVALID_RESPONSE.clone(),
"on route: {:?} - {:?} with actions: {:?}",
method,
route,
actions
);
assert_eq!(code, 403, "{:?}", &response);
}
}
@ -355,7 +372,11 @@ async fn access_authorized_no_index_restriction() {
route,
actions
);
assert_ne!(code, 403, "on route: {:?} - {:?} with action: {:?}", method, route, actions);
assert_ne!(
code, 403,
"on route: {:?} - {:?} with action: {:?}",
method, route, actions
);
}
}
}
@ -793,7 +814,13 @@ async fn error_creating_index_without_action() {
server.use_api_key(MASTER_KEY);
// create key with access on all indexes.
let create_index_actions = AUTHORIZATIONS.get(&("POST","/indexes")).unwrap().iter().flat_map(|s| s.iter()).cloned().collect::<HashSet<_>>();
let create_index_actions = AUTHORIZATIONS
.get(&("POST", "/indexes"))
.unwrap()
.iter()
.flat_map(|s| s.iter())
.cloned()
.collect::<HashSet<_>>();
let content = json!({
"indexes": ["*"],
// Give all action but the ones allowing to create an index.

View File

@ -457,10 +457,7 @@ impl<State> Index<'_, State> {
self.service.get(url).await
}
pub async fn render(
&self,
query: Value
) -> (Value, StatusCode) {
pub async fn render(&self, query: Value) -> (Value, StatusCode) {
let url = format!("/indexes/{}/render", urlencode(self.uid.as_ref()));
self.service.post_encoded(url, query, self.encoder).await
}

View File

@ -2,5 +2,5 @@ mod add_documents;
mod delete_documents;
mod errors;
mod get_documents;
mod update_documents;
mod render_documents;
mod update_documents;

View File

@ -6,13 +6,7 @@ use meili_snap::snapshot;
async fn empty_id() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": ""
}
}})
.await;
let (value, code) = index.render(json! {{ "template": { "id": "" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -28,13 +22,7 @@ async fn empty_id() {
async fn wrong_id_prefix() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "wrong.disregarded"
}
}})
.await;
let (value, code) = index.render(json! {{ "template": { "id": "wrong.disregarded" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -50,13 +38,7 @@ async fn wrong_id_prefix() {
async fn missing_embedder() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders"
}
}})
.await;
let (value, code) = index.render(json! {{ "template": { "id": "embedders" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -72,13 +54,8 @@ async fn missing_embedder() {
async fn wrong_embedder() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.wrong.disregarded"
}
}})
.await;
let (value, code) =
index.render(json! {{ "template": { "id": "embedders.wrong.disregarded" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -94,13 +71,7 @@ async fn wrong_embedder() {
async fn missing_template_kind() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest"
}
}})
.await;
let (value, code) = index.render(json! {{ "template": { "id": "embedders.rest" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -116,13 +87,8 @@ async fn missing_template_kind() {
async fn wrong_template_kind() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.wrong.disregarded"
}
}})
.await;
let (value, code) =
index.render(json! {{ "template": { "id": "embedders.rest.wrong.disregarded" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -138,13 +104,8 @@ async fn wrong_template_kind() {
async fn document_template_on_fragmented_index() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.documentTemplate"
}
}})
.await;
let (value, code) =
index.render(json! {{ "template": { "id": "embedders.rest.documentTemplate" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -160,13 +121,8 @@ async fn document_template_on_fragmented_index() {
async fn missing_fragment_name() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.indexingFragments"
}
}})
.await;
let (value, code) =
index.render(json! {{ "template": { "id": "embedders.rest.indexingFragments" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -177,13 +133,8 @@ async fn missing_fragment_name() {
}
"#);
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.searchFragments"
}
}})
.await;
let (value, code) =
index.render(json! {{ "template": { "id": "embedders.rest.searchFragments" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -200,11 +151,7 @@ async fn wrong_fragment_name() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.indexingFragments.wrong"
}
}})
.render(json! {{ "template": { "id": "embedders.rest.indexingFragments.wrong" }}})
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
@ -216,13 +163,8 @@ async fn wrong_fragment_name() {
}
"#);
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.searchFragments.wrong"
}
}})
.await;
let (value, code) =
index.render(json! {{ "template": { "id": "embedders.rest.searchFragments.wrong" }}}).await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
@ -239,11 +181,9 @@ async fn leftover_tokens() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.indexingFragments.withBreed.leftover"
}
}})
.render(
json! {{ "template": { "id": "embedders.rest.indexingFragments.withBreed.leftover" }}},
)
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
@ -256,11 +196,7 @@ async fn leftover_tokens() {
"#);
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.searchFragments.justBreed.leftover"
}
}})
.render(json! {{"template": { "id": "embedders.rest.searchFragments.justBreed.leftover" }}})
.await;
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
@ -278,11 +214,7 @@ async fn fragment_retrieval() {
let index = shared_index_for_fragments().await;
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.indexingFragments.withBreed"
}
}})
.render(json! {{ "template": { "id": "embedders.rest.indexingFragments.withBreed" }}})
.await;
snapshot!(code, @"200 OK");
snapshot!(value, @r#"
@ -293,11 +225,7 @@ async fn fragment_retrieval() {
"#);
let (value, code) = index
.render(json! {{
"template": {
"id": "embedders.rest.searchFragments.justBreed"
}
}})
.render(json! {{ "template": { "id": "embedders.rest.searchFragments.justBreed" }}})
.await;
snapshot!(code, @"200 OK");
snapshot!(value, @r#"

View File

@ -63,10 +63,7 @@ impl Error {
/// Produces an error message when the error happened at rendering time.
pub fn rendering_error(&self, root: &str) -> String {
if self.path.is_empty() {
format!(
"error while rendering template: {}",
&self.template_error
)
format!("error while rendering template: {}", &self.template_error)
} else {
format!(
"in `{}`, error while rendering template: {}",
@ -79,10 +76,7 @@ impl Error {
/// Produces an error message when the error happened at parsing time.
pub fn parsing_error(&self, root: &str) -> String {
if self.path.is_empty() {
format!(
"error while parsing template: {}",
&self.template_error
)
format!("error while parsing template: {}", &self.template_error)
} else {
format!(
"in `{}`, error while parsing template: {}",
@ -153,10 +147,7 @@ impl JsonTemplate {
/// If its a map, values inside can be accessed directly by their keys.
pub fn render_serializable<T: Serialize>(&self, object: &T) -> Result<Value, Error> {
let object = liquid::to_object(object)
.map_err(|err| Error {
template_error: err,
path: ValuePath::new(),
})?;
.map_err(|err| Error { template_error: err, path: ValuePath::new() })?;
self.render(&object)
}

View File

@ -886,9 +886,7 @@ impl EmbedderOptions {
| EmbedderOptions::OpenAi(_)
| EmbedderOptions::Ollama(_)
| EmbedderOptions::UserProvided(_) => None,
EmbedderOptions::Rest(embedder_options) => {
embedder_options.search_fragments.get(name)
}
EmbedderOptions::Rest(embedder_options) => embedder_options.search_fragments.get(name),
EmbedderOptions::Composite(embedder_options) => {
if let SubEmbedderOptions::Rest(embedder_options) = &embedder_options.search {
embedder_options.search_fragments.get(name)