From e23b8f640efd5057e9e97f9672ca20f2ef755af8 Mon Sep 17 00:00:00 2001 From: KeyCode17 Date: Sat, 30 May 2026 05:51:36 +0700 Subject: [PATCH 1/7] feat(types): add ContextId newtype for browser-context isolation Co-Authored-By: Claude Sonnet 4.6 --- ras-types/src/domain/ids.rs | 17 +++++++++++++++++ ras-types/src/lib.rs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ras-types/src/domain/ids.rs b/ras-types/src/domain/ids.rs index 8fd7f91..4f30a26 100644 --- a/ras-types/src/domain/ids.rs +++ b/ras-types/src/domain/ids.rs @@ -38,3 +38,20 @@ pub struct BackendNodeId(pub i64); #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(transparent)] pub struct ActionName(pub SmolStr); + +/// Identifies an isolated CDP browser context (one per tenant session). +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(transparent)] +pub struct ContextId(pub SmolStr); + +#[cfg(test)] +mod context_id_tests { + use super::ContextId; + + #[test] + fn context_id_roundtrips_through_string() { + let c = ContextId("ABC123".into()); + assert_eq!(c.0.as_str(), "ABC123"); + assert_eq!(c.clone(), c); + } +} diff --git a/ras-types/src/lib.rs b/ras-types/src/lib.rs index 222d852..a9265e6 100644 --- a/ras-types/src/lib.rs +++ b/ras-types/src/lib.rs @@ -3,7 +3,7 @@ pub mod domain; pub mod infrastructure; pub use domain::action_result::ActionResult; -pub use domain::ids::{ActionName, AgentId, BackendNodeId, SessionId, StepId, TargetId}; +pub use domain::ids::{ActionName, AgentId, BackendNodeId, ContextId, SessionId, StepId, TargetId}; pub use domain::responses::{ListResponse, PaginationMeta, SingleResponse}; pub use domain::timing::{ActionTimeout, ActionTimeoutError}; pub use domain::url_pattern::{DomainPattern, DomainPatternError, MatchLevel}; From c90d8d80198c3ed71abeb38d977edf8ca9315c18 Mon Sep 17 00:00:00 2001 From: KeyCode17 Date: Sat, 30 May 2026 05:53:41 +0700 Subject: [PATCH 2/7] feat(cdp): add context-aware methods to BrowserPort with default impls Co-Authored-By: Claude Sonnet 4.6 --- ras-cdp/src/domain/repository.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/ras-cdp/src/domain/repository.rs b/ras-cdp/src/domain/repository.rs index c8e75f6..00b4e58 100644 --- a/ras-cdp/src/domain/repository.rs +++ b/ras-cdp/src/domain/repository.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use ras_errors::AppError; -use ras_types::{BackendNodeId, TargetId}; +use ras_types::{BackendNodeId, ContextId, TargetId}; use serde::{Deserialize, Serialize}; use url::Url; @@ -64,4 +64,32 @@ pub trait BrowserPort: Send + Sync + 'static { async fn clear_cookies(&self, target: &TargetId, origin: &str) -> Result<(), AppError>; async fn close_target(&self, target: &TargetId) -> Result<(), AppError>; async fn create_target(&self, url: &Url) -> Result; + + /// Create a fresh isolated browser context (separate cookies/storage). + async fn create_context(&self) -> Result { + Err(AppError::ActionFailed( + "create_context not supported by this BrowserPort".into(), + )) + } + + /// Dispose a context, freeing its cookies/storage/tabs. + async fn close_context(&self, _ctx: &ContextId) -> Result<(), AppError> { + Err(AppError::ActionFailed( + "close_context not supported by this BrowserPort".into(), + )) + } + + /// Open a new tab inside a specific context. + async fn new_target_in(&self, _ctx: &ContextId, _url: &Url) -> Result { + Err(AppError::ActionFailed( + "new_target_in not supported by this BrowserPort".into(), + )) + } + + /// List only the tabs belonging to a specific context. + async fn list_targets_in(&self, _ctx: &ContextId) -> Result, AppError> { + Err(AppError::ActionFailed( + "list_targets_in not supported by this BrowserPort".into(), + )) + } } From 26664d04070763b2b9df19b0569dd0581def90da Mon Sep 17 00:00:00 2001 From: KeyCode17 Date: Sat, 30 May 2026 05:57:01 +0700 Subject: [PATCH 3/7] feat(cdp): add context_ops (create/dispose/new_target_in/list_targets_in/clear) Co-Authored-By: Claude Sonnet 4.6 --- ras-cdp/src/infrastructure/context_ops.rs | 115 ++++++++++++++++++++++ ras-cdp/src/infrastructure/mod.rs | 1 + 2 files changed, 116 insertions(+) create mode 100644 ras-cdp/src/infrastructure/context_ops.rs diff --git a/ras-cdp/src/infrastructure/context_ops.rs b/ras-cdp/src/infrastructure/context_ops.rs new file mode 100644 index 0000000..340e682 --- /dev/null +++ b/ras-cdp/src/infrastructure/context_ops.rs @@ -0,0 +1,115 @@ +use std::sync::Arc; + +use chromiumoxide::Browser; +use chromiumoxide::cdp::browser_protocol::browser::{ + BrowserContextId, SetDownloadBehaviorBehavior, SetDownloadBehaviorParams, +}; +use chromiumoxide::cdp::browser_protocol::storage::ClearCookiesParams; +use chromiumoxide::cdp::browser_protocol::target::{ + CreateBrowserContextParams, CreateTargetParams, GetTargetsParams, +}; +use ras_errors::AppError; +use ras_types::{ContextId, TargetId}; +use tokio::sync::Mutex; +use url::Url; + +fn to_cdp(ctx: &ContextId) -> BrowserContextId { + BrowserContextId::new(ctx.0.to_string()) +} + +/// Create an isolated context and point its downloads at a per-context directory. +pub(crate) async fn create_context(browser: &Arc>) -> Result { + let guard = browser.lock().await; + let id = guard + .create_browser_context(CreateBrowserContextParams::default()) + .await + .map_err(|e| AppError::ActionFailed(format!("createBrowserContext: {e}")))?; + let ctx = ContextId(id.inner().as_str().into()); + drop(guard); + set_context_download_dir(browser, &ctx).await?; + Ok(ctx) +} + +pub(crate) async fn dispose_context( + browser: &Arc>, + ctx: &ContextId, +) -> Result<(), AppError> { + let guard = browser.lock().await; + guard + .dispose_browser_context(to_cdp(ctx)) + .await + .map_err(|e| AppError::ActionFailed(format!("disposeBrowserContext: {e}"))) +} + +pub(crate) async fn new_target_in( + browser: &Arc>, + ctx: &ContextId, + url: &Url, +) -> Result { + let mut params = CreateTargetParams::new(url.as_str()); + params.browser_context_id = Some(to_cdp(ctx)); + let guard = browser.lock().await; + let page = guard + .new_page(params) + .await + .map_err(|e| AppError::ActionFailed(format!("new_page in context: {e}")))?; + Ok(TargetId(page.target_id().as_ref().into())) +} + +#[allow(dead_code)] +pub(crate) async fn list_targets_in( + browser: &Arc>, + ctx: &ContextId, +) -> Result, AppError> { + let wanted = to_cdp(ctx); + let guard = browser.lock().await; + let resp = guard + .execute(GetTargetsParams::default()) + .await + .map_err(|e| AppError::BrowserDisconnected(format!("getTargets: {e}")))?; + Ok(resp + .result + .target_infos + .iter() + .filter(|t| t.browser_context_id.as_ref() == Some(&wanted)) + .filter(|t| t.r#type == "page") + .map(|t| TargetId(t.target_id.as_ref().into())) + .collect()) +} + +#[allow(dead_code)] +pub(crate) async fn clear_context_cookies( + browser: &Arc>, + ctx: &ContextId, +) -> Result<(), AppError> { + let params = ClearCookiesParams::builder() + .browser_context_id(to_cdp(ctx)) + .build(); + let guard = browser.lock().await; + guard + .execute(params) + .await + .map_err(|e| AppError::ActionFailed(format!("storage.clearCookies: {e}")))?; + Ok(()) +} + +async fn set_context_download_dir( + browser: &Arc>, + ctx: &ContextId, +) -> Result<(), AppError> { + let dir = std::env::temp_dir() + .join("ras-downloads") + .join(ctx.0.as_str()); + tokio::fs::create_dir_all(&dir) + .await + .map_err(|e| AppError::ActionFailed(format!("download dir: {e}")))?; + let mut params = SetDownloadBehaviorParams::new(SetDownloadBehaviorBehavior::AllowAndName); + params.browser_context_id = Some(to_cdp(ctx)); + params.download_path = Some(dir.to_string_lossy().into_owned()); + let guard = browser.lock().await; + guard + .execute(params) + .await + .map_err(|e| AppError::ActionFailed(format!("setDownloadBehavior: {e}")))?; + Ok(()) +} diff --git a/ras-cdp/src/infrastructure/mod.rs b/ras-cdp/src/infrastructure/mod.rs index ffd5c7f..b302e3a 100644 --- a/ras-cdp/src/infrastructure/mod.rs +++ b/ras-cdp/src/infrastructure/mod.rs @@ -2,5 +2,6 @@ pub mod cdp_ext; pub mod chromiumoxide_adapter; pub mod chromiumoxide_helpers; pub mod chromiumoxide_input; +pub mod context_ops; pub mod mouse_input; pub mod timeout; From 4cf261dd90939c04191fe6c0b8ec53b1a54d9411 Mon Sep 17 00:00:00 2001 From: KeyCode17 Date: Sat, 30 May 2026 05:59:04 +0700 Subject: [PATCH 4/7] feat(cdp): implement context methods on ChromiumoxideAdapter Delegates create_context, close_context, new_target_in, and list_targets_in to context_ops free functions; removes now-unnecessary #[allow(dead_code)] from list_targets_in. Co-Authored-By: Claude Sonnet 4.6 --- .../src/infrastructure/chromiumoxide_adapter.rs | 17 ++++++++++++++++- ras-cdp/src/infrastructure/context_ops.rs | 1 - 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ras-cdp/src/infrastructure/chromiumoxide_adapter.rs b/ras-cdp/src/infrastructure/chromiumoxide_adapter.rs index 0120941..c8eae14 100644 --- a/ras-cdp/src/infrastructure/chromiumoxide_adapter.rs +++ b/ras-cdp/src/infrastructure/chromiumoxide_adapter.rs @@ -6,7 +6,7 @@ use chromiumoxide::Browser; use chromiumoxide::handler::HandlerConfig; use futures::StreamExt; use ras_errors::AppError; -use ras_types::{BackendNodeId, TargetId}; +use ras_types::{BackendNodeId, ContextId, TargetId}; use tokio::sync::Mutex; use tracing::warn; use url::Url; @@ -19,6 +19,9 @@ use crate::infrastructure::cdp_ext::{ }; use crate::infrastructure::chromiumoxide_helpers::{list_target_ids, new_target, page_for}; use crate::infrastructure::chromiumoxide_input::{click_backend_node, type_chars}; +use crate::infrastructure::context_ops::{ + create_context, dispose_context, list_targets_in, new_target_in, +}; use crate::infrastructure::mouse_input::{ dispatch_mouse_hold, dispatch_mouse_move, dispatch_mouse_press, dispatch_mouse_release, }; @@ -182,4 +185,16 @@ impl BrowserPort for ChromiumoxideAdapter { async fn create_target(&self, url: &Url) -> Result { new_target(&self.browser, url).await } + async fn create_context(&self) -> Result { + create_context(&self.browser).await + } + async fn close_context(&self, ctx: &ContextId) -> Result<(), AppError> { + dispose_context(&self.browser, ctx).await + } + async fn new_target_in(&self, ctx: &ContextId, url: &Url) -> Result { + new_target_in(&self.browser, ctx, url).await + } + async fn list_targets_in(&self, ctx: &ContextId) -> Result, AppError> { + list_targets_in(&self.browser, ctx).await + } } diff --git a/ras-cdp/src/infrastructure/context_ops.rs b/ras-cdp/src/infrastructure/context_ops.rs index 340e682..a8716d0 100644 --- a/ras-cdp/src/infrastructure/context_ops.rs +++ b/ras-cdp/src/infrastructure/context_ops.rs @@ -56,7 +56,6 @@ pub(crate) async fn new_target_in( Ok(TargetId(page.target_id().as_ref().into())) } -#[allow(dead_code)] pub(crate) async fn list_targets_in( browser: &Arc>, ctx: &ContextId, From 33e5976342d1209f683df4687ff59acc944ebd8f Mon Sep 17 00:00:00 2001 From: KeyCode17 Date: Sat, 30 May 2026 06:01:57 +0700 Subject: [PATCH 5/7] test(cdp): live e2e proving per-context cookie + target isolation Co-Authored-By: Claude Sonnet 4.6 --- ras-cdp/Cargo.toml | 5 +- ras-cdp/tests/e2e_context_isolation.rs | 84 ++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 ras-cdp/tests/e2e_context_isolation.rs diff --git a/ras-cdp/Cargo.toml b/ras-cdp/Cargo.toml index d520f35..1770aee 100644 --- a/ras-cdp/Cargo.toml +++ b/ras-cdp/Cargo.toml @@ -27,4 +27,7 @@ tracing = { workspace = true } url = { workspace = true } [dev-dependencies] -tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +url = { workspace = true } +serde_json = { workspace = true } +ras-types = { workspace = true } diff --git a/ras-cdp/tests/e2e_context_isolation.rs b/ras-cdp/tests/e2e_context_isolation.rs new file mode 100644 index 0000000..29033aa --- /dev/null +++ b/ras-cdp/tests/e2e_context_isolation.rs @@ -0,0 +1,84 @@ +use std::time::Duration; + +use ras_cdp::BrowserPort; +use ras_cdp::infrastructure::chromiumoxide_adapter::ChromiumoxideAdapter; +use ras_types::{ContextId, TargetId}; +use url::Url; + +fn cdp_url() -> Option { + std::env::var("CDP_URL").ok()?.parse().ok() +} + +fn test_url() -> Url { + std::env::var("TEST_URL") + .unwrap_or_else(|_| "http://127.0.0.1:8731/".to_string()) + .parse() + .expect("TEST_URL parse") +} + +async fn adapter() -> ChromiumoxideAdapter { + let url = cdp_url().expect("set CDP_URL to a running chrome --remote-debugging-port"); + ChromiumoxideAdapter::connect(url, Duration::from_secs(30)) + .await + .expect("connect") +} + +async fn cookie_len(a: &ChromiumoxideAdapter, target: &TargetId) -> i64 { + let v = a + .evaluate(target, "document.cookie.length") + .await + .expect("eval cookie len"); + v.as_i64().unwrap_or(-1) +} + +#[tokio::test] +#[ignore] +async fn contexts_isolate_cookies() { + let a = adapter().await; + let ctx_a: ContextId = a.create_context().await.expect("ctx a"); + let ctx_b: ContextId = a.create_context().await.expect("ctx b"); + let url = test_url(); + + let tab_a = a.new_target_in(&ctx_a, &url).await.expect("tab a"); + let tab_b = a.new_target_in(&ctx_b, &url).await.expect("tab b"); + tokio::time::sleep(Duration::from_millis(900)).await; + + a.evaluate(&tab_a, "document.cookie = 'ras_iso=1; path=/'") + .await + .expect("set cookie in A"); + + assert!( + cookie_len(&a, &tab_a).await > 0, + "A should see its own cookie" + ); + assert_eq!(cookie_len(&a, &tab_b).await, 0, "B must NOT see A's cookie"); + + a.close_context(&ctx_a).await.expect("close a"); + a.close_context(&ctx_b).await.expect("close b"); +} + +#[tokio::test] +#[ignore] +async fn list_targets_in_is_context_scoped() { + let a = adapter().await; + let ctx_a = a.create_context().await.expect("ctx a"); + let ctx_b = a.create_context().await.expect("ctx b"); + let url = test_url(); + let tab_a = a.new_target_in(&ctx_a, &url).await.expect("tab a"); + let tab_b = a.new_target_in(&ctx_b, &url).await.expect("tab b"); + + let in_a = a.list_targets_in(&ctx_a).await.expect("list a"); + let in_b = a.list_targets_in(&ctx_b).await.expect("list b"); + + assert!( + in_a.contains(&tab_a) && !in_a.contains(&tab_b), + "A lists only A's tab" + ); + assert!( + in_b.contains(&tab_b) && !in_b.contains(&tab_a), + "B lists only B's tab" + ); + + a.close_context(&ctx_a).await.expect("close a"); + a.close_context(&ctx_b).await.expect("close b"); +} From 4d7b514dd690f233e17027d1693064818ad2adad Mon Sep 17 00:00:00 2001 From: KeyCode17 Date: Sat, 30 May 2026 06:06:19 +0700 Subject: [PATCH 6/7] fix(cdp): dispose context on create error path; assert close frees it Co-Authored-By: Claude Sonnet 4.6 --- ras-cdp/src/infrastructure/context_ops.rs | 5 ++++- ras-cdp/tests/e2e_context_isolation.rs | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ras-cdp/src/infrastructure/context_ops.rs b/ras-cdp/src/infrastructure/context_ops.rs index a8716d0..ec1fa35 100644 --- a/ras-cdp/src/infrastructure/context_ops.rs +++ b/ras-cdp/src/infrastructure/context_ops.rs @@ -26,7 +26,10 @@ pub(crate) async fn create_context(browser: &Arc>) -> Result Date: Sat, 30 May 2026 09:13:40 +0700 Subject: [PATCH 7/7] =?UTF-8?q?chore:=20bump=20to=203.2.0=20(Phase=201=20?= =?UTF-8?q?=E2=80=94=20CDP=20context=20isolation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 76 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1b9471..16904ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1465,7 +1465,7 @@ dependencies = [ [[package]] name = "ras-agent" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "chrono", @@ -1497,7 +1497,7 @@ dependencies = [ [[package]] name = "ras-browser" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-cdp", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "ras-cdp" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "chromiumoxide", @@ -1534,7 +1534,7 @@ dependencies = [ [[package]] name = "ras-cli" -version = "3.1.0" +version = "3.2.0" dependencies = [ "anyhow", "clap", @@ -1564,7 +1564,7 @@ dependencies = [ [[package]] name = "ras-cloud" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1581,7 +1581,7 @@ dependencies = [ [[package]] name = "ras-config" -version = "3.1.0" +version = "3.2.0" dependencies = [ "dotenvy", "once_cell", @@ -1595,7 +1595,7 @@ dependencies = [ [[package]] name = "ras-cosmium" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-cdp", @@ -1612,7 +1612,7 @@ dependencies = [ [[package]] name = "ras-daemon" -version = "3.1.0" +version = "3.2.0" dependencies = [ "anyhow", "dotenvy", @@ -1632,7 +1632,7 @@ dependencies = [ [[package]] name = "ras-dom" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "chromiumoxide", @@ -1652,7 +1652,7 @@ dependencies = [ [[package]] name = "ras-errors" -version = "3.1.0" +version = "3.2.0" dependencies = [ "serde", "thiserror", @@ -1660,7 +1660,7 @@ dependencies = [ [[package]] name = "ras-events" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-broadcast", "async-trait", @@ -1678,7 +1678,7 @@ dependencies = [ [[package]] name = "ras-filesystem" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1693,7 +1693,7 @@ dependencies = [ [[package]] name = "ras-judge" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "image", @@ -1708,7 +1708,7 @@ dependencies = [ [[package]] name = "ras-llm" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1722,7 +1722,7 @@ dependencies = [ [[package]] name = "ras-llm-anthropic" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "chrono", @@ -1745,7 +1745,7 @@ dependencies = [ [[package]] name = "ras-llm-bedrock" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1762,7 +1762,7 @@ dependencies = [ [[package]] name = "ras-llm-cerebras" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1780,7 +1780,7 @@ dependencies = [ [[package]] name = "ras-llm-cloud" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1797,7 +1797,7 @@ dependencies = [ [[package]] name = "ras-llm-deepseek" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1815,7 +1815,7 @@ dependencies = [ [[package]] name = "ras-llm-google" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1832,7 +1832,7 @@ dependencies = [ [[package]] name = "ras-llm-groq" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1850,7 +1850,7 @@ dependencies = [ [[package]] name = "ras-llm-langchain" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1867,7 +1867,7 @@ dependencies = [ [[package]] name = "ras-llm-mistral" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1885,7 +1885,7 @@ dependencies = [ [[package]] name = "ras-llm-oci" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1902,7 +1902,7 @@ dependencies = [ [[package]] name = "ras-llm-ollama" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1919,7 +1919,7 @@ dependencies = [ [[package]] name = "ras-llm-openai" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1936,7 +1936,7 @@ dependencies = [ [[package]] name = "ras-llm-openrouter" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1954,7 +1954,7 @@ dependencies = [ [[package]] name = "ras-llm-vercel" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1972,7 +1972,7 @@ dependencies = [ [[package]] name = "ras-mcp" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -1989,7 +1989,7 @@ dependencies = [ [[package]] name = "ras-recording" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "image", @@ -2004,7 +2004,7 @@ dependencies = [ [[package]] name = "ras-sandbox" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -2017,7 +2017,7 @@ dependencies = [ [[package]] name = "ras-skills" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -2034,7 +2034,7 @@ dependencies = [ [[package]] name = "ras-telemetry" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -2048,7 +2048,7 @@ dependencies = [ [[package]] name = "ras-tokens" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "chrono", @@ -2066,7 +2066,7 @@ dependencies = [ [[package]] name = "ras-tools" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "indexmap", @@ -2087,7 +2087,7 @@ dependencies = [ [[package]] name = "ras-types" -version = "3.1.0" +version = "3.2.0" dependencies = [ "chrono", "indexmap", @@ -2103,7 +2103,7 @@ dependencies = [ [[package]] name = "ras-validation" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-errors", @@ -2117,7 +2117,7 @@ dependencies = [ [[package]] name = "ras-watchdogs" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "ras-browser", diff --git a/Cargo.toml b/Cargo.toml index 3118313..eab840b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ exclude = ["examples", "tests", "docs", "scripts"] default-members = ["ras-cli", "ras-daemon"] [workspace.package] -version = "3.1.0" +version = "3.2.0" edition = "2024" rust-version = "1.95.0" license = "MIT"