WIP we need to check chats + add chats restrictions to tenant tokens

This commit is contained in:
Clément Renault
2025-06-03 15:29:15 +02:00
parent 5ccb24377a
commit d63cf4a5a8
5 changed files with 26 additions and 6 deletions

View File

@@ -419,6 +419,7 @@ pub(crate) mod test {
uid: Uuid::from_str("9f8a34da-b6b2-42f0-939b-dbd4c3448655").unwrap(),
actions: vec![Action::DocumentsAll],
indexes: vec![IndexUidPattern::from_str("doggos").unwrap()],
chats: vec![IndexUidPattern::from_str("OpenAI").unwrap()],
expires_at: Some(datetime!(4130-03-14 12:21 UTC)),
created_at: datetime!(1960-11-15 0:00 UTC),
updated_at: datetime!(2022-11-10 0:00 UTC),
@@ -429,6 +430,7 @@ pub(crate) mod test {
uid: Uuid::from_str("4622f717-1c00-47bb-a494-39d76a49b591").unwrap(),
actions: vec![Action::All],
indexes: vec![IndexUidPattern::all()],
chats: vec![IndexUidPattern::all()],
expires_at: None,
created_at: datetime!(0000-01-01 00:01 UTC),
updated_at: datetime!(1964-05-04 17:25 UTC),
@@ -439,6 +441,7 @@ pub(crate) mod test {
uid: Uuid::from_str("fb80b58b-0a34-412f-8ba7-1ce868f8ac5c").unwrap(),
actions: vec![],
indexes: vec![],
chats: vec![],
expires_at: None,
created_at: datetime!(400-02-29 0:00 UTC),
updated_at: datetime!(1024-02-29 0:00 UTC),

View File

@@ -187,6 +187,7 @@ impl CompatV5ToV6 {
v5::StarOr::Other(uid) => v6::IndexUidPattern::new_unchecked(uid.as_str()),
})
.collect(),
chats: vec![],
expires_at: key.expires_at,
created_at: key.created_at,
updated_at: key.updated_at,

View File

@@ -390,6 +390,7 @@ InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQU
EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ;
InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ;
// Experimental features - Chat Completions
InvalidApiKeyChats , InvalidRequest , BAD_REQUEST ;
ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND ;
InvalidChatCompletionSource , InvalidRequest , BAD_REQUEST ;
InvalidChatCompletionBaseApi , InvalidRequest , BAD_REQUEST ;

View File

@@ -57,6 +57,10 @@ pub struct CreateApiKey {
#[deserr(error = DeserrJsonError<InvalidApiKeyIndexes>, missing_field_error = DeserrJsonError::missing_api_key_indexes)]
#[schema(value_type = Vec<String>, example = json!(["products"]))]
pub indexes: Vec<IndexUidPattern>,
/// A list of accessible chats permitted for the key. `["*"]` for all chats. The `*` character can be used as a wildcard when located at the last position. e.g. `chats_*` to allow access to all indexes whose names start with `chats_`.
#[deserr(default, error = DeserrJsonError<InvalidApiKeyChats>)]
#[schema(value_type = Vec<String>, example = json!(["OpenAI", "ChatGPT"]))]
pub chats: Vec<IndexUidPattern>,
/// Represent the expiration date and time as RFC 3339 format. `null` equals to no expiration time.
#[deserr(error = DeserrJsonError<InvalidApiKeyExpiresAt>, try_from(Option<String>) = parse_expiration_date -> ParseOffsetDateTimeError, missing_field_error = DeserrJsonError::missing_api_key_expires_at)]
pub expires_at: Option<OffsetDateTime>,
@@ -64,7 +68,7 @@ pub struct CreateApiKey {
impl CreateApiKey {
pub fn to_key(self) -> Key {
let CreateApiKey { description, name, uid, actions, indexes, expires_at } = self;
let CreateApiKey { description, name, uid, actions, indexes, chats, expires_at } = self;
let now = OffsetDateTime::now_utc();
Key {
description,
@@ -72,6 +76,7 @@ impl CreateApiKey {
uid,
actions,
indexes,
chats,
expires_at,
created_at: now,
updated_at: now,
@@ -120,6 +125,7 @@ pub struct Key {
pub uid: KeyId,
pub actions: Vec<Action>,
pub indexes: Vec<IndexUidPattern>,
pub chats: Vec<IndexUidPattern>,
#[serde(with = "time::serde::rfc3339::option")]
pub expires_at: Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc3339")]
@@ -138,6 +144,7 @@ impl Key {
uid,
actions: vec![Action::All],
indexes: vec![IndexUidPattern::all()],
chats: vec![IndexUidPattern::all()],
expires_at: None,
created_at: now,
updated_at: now,
@@ -153,6 +160,7 @@ impl Key {
uid,
actions: vec![Action::Search],
indexes: vec![IndexUidPattern::all()],
chats: vec![],
expires_at: None,
created_at: now,
updated_at: now,
@@ -168,6 +176,7 @@ impl Key {
uid,
actions: vec![Action::ChatCompletions, Action::Search],
indexes: vec![IndexUidPattern::all()],
chats: vec![IndexUidPattern::all()],
expires_at: None,
created_at: now,
updated_at: now,

View File

@@ -165,16 +165,22 @@ pub mod policies {
ExpiredTenantToken { exp: i64, now: i64 },
#[error("The provided API key is invalid.")]
InvalidApiKey,
#[error("The provided tenant token cannot acces the index `{index}`, allowed indexes are {allowed:?}.")]
#[error("The provided tenant token cannot access the index `{index}`, allowed indexes are {allowed:?}.")]
TenantTokenAccessingnUnauthorizedIndex { index: String, allowed: Vec<String> },
#[error(
"The API key used to generate this tenant token cannot acces the index `{index}`."
"The API key used to generate this tenant token cannot access the index `{index}`."
)]
TenantTokenApiKeyAccessingnUnauthorizedIndex { index: String },
#[error(
"The API key cannot acces the index `{index}`, authorized indexes are {allowed:?}."
"The API key cannot access the index `{index}`, authorized indexes are {allowed:?}."
)]
ApiKeyAccessingnUnauthorizedIndex { index: String, allowed: Vec<String> },
#[error("The provided tenant token cannot access the chats `{chat}`, allowed chats are {allowed:?}.")]
TenantTokenAccessingnUnauthorizedChat { chat: String, allowed: Vec<String> },
#[error("The API key used to generate this tenant token cannot access the chat `{chat}`.")]
TenantTokenApiKeyAccessingnUnauthorizedChat { chat: String },
#[error("The API key cannot access the chat `{chat}`, authorized chats are {allowed:?}.")]
ApiKeyAccessingnUnauthorizedChat { chat: String, allowed: Vec<String> },
#[error("The provided tenant token is invalid.")]
InvalidTenantToken,
#[error("Could not decode tenant token, {0}.")]
@@ -231,8 +237,8 @@ pub mod policies {
pub struct ActionPolicy<const A: u8>;
impl<const A: u8> Policy for ActionPolicy<A> {
/// Attempts to grant authentication from a bearer token (that can be a tenant token or an API key), the requested Action,
/// and a list of requested indexes.
/// Attempts to grant authentication from a bearer token (that can be a tenant token or an API key),
/// the requested Action, and a list of requested indexes.
///
/// If the bearer token is not allowed for the specified indexes and action, returns `None`.
/// Otherwise, returns an object containing the generated permissions: the search filters to add to a search, and the list of allowed indexes