From c1006d6f42f44c1c63d66afd4bb7552599d029e6 Mon Sep 17 00:00:00 2001 From: "Claude Sonnet 4.6" Date: Mon, 23 Feb 2026 14:55:03 +0900 Subject: [PATCH 1/3] fix: add --no-sandbox flags for Chrome in CI/Docker environments Running Chrome in Docker containers or CI environments requires additional flags to work properly. This commit adds --no-sandbox and --disable-setuid-sandbox flags when CI environment variable is detected. Changes: - Add --no-sandbox flag in CI environments - Add --disable-setuid-sandbox flag in CI environments These flags are essential for running Chrome in containerized environments where sandboxing may not work properly. Co-Authored-By: Claude Sonnet 4.5 --- src/core/cdp/browser.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/cdp/browser.rs b/src/core/cdp/browser.rs index 1e1b0c2..aaccb26 100644 --- a/src/core/cdp/browser.rs +++ b/src/core/cdp/browser.rs @@ -369,6 +369,8 @@ impl BrowserManager { if std::env::var("CI").is_ok() { args.push("--disable-gpu"); + args.push("--no-sandbox"); + args.push("--disable-setuid-sandbox"); } let browser_path = self.browser_path.clone(); From 81cd6e0710c3f0e551044cc17af60777bb7a5d77 Mon Sep 17 00:00:00 2001 From: "Claude Sonnet 4.6" Date: Mon, 23 Feb 2026 15:02:13 +0900 Subject: [PATCH 2/3] feat: add chrome_args configuration for custom Chrome flags Add chrome_args configuration option to allow users to specify custom Chrome/Chromium flags via config file. This is useful for Docker/devcontainer environments where Chrome requires additional flags like --no-sandbox to work properly. Changes: - Add chrome_args field to Config (Vec) - Pass chrome_args from Config to BrowserManager - Apply custom Chrome args in get_browser method - Update README.md with configuration documentation Users can now configure Chrome flags in config.toml: chrome_args = ["--no-sandbox", "--disable-setuid-sandbox"] This provides flexibility while keeping CI environment auto-detection (when CI=true is set, --no-sandbox is automatically added). Co-Authored-By: Claude Sonnet 4.5 --- README.md | 35 ++++++++++++++++++++++++++++++++++- src/cli/mod.rs | 6 ++++-- src/core/cdp/browser.rs | 15 +++++++++++++-- src/core/config.rs | 2 ++ src/core/patent_search.rs | 3 ++- src/mcp/mod.rs | 3 ++- 6 files changed, 57 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6fab7b0..2158bb6 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,39 @@ google-patent-cli config # Set custom browser path google-patent-cli config --set-browser "/path/to/chrome" ``` - + +### Configuration File + +The configuration file is located at: +- **Linux/macOS**: `~/.config/google-patent-cli/config.toml` +- **Windows**: `%APPDATA%\google-patent-cli\config.toml` + +You can manually edit the TOML file to configure additional Chrome arguments: + +```toml +# Path to Chrome/Chromium executable +browser_path = "/usr/bin/google-chrome" + +# Additional Chrome arguments (useful for Docker/CI environments) +chrome_args = [ + "--no-sandbox", + "--disable-setuid-sandbox" +] +``` + +### Docker/DevContainer Environment + +When running in Docker containers or devcontainers, Chrome requires additional flags to work properly. You can configure these flags via `chrome_args` in your config file: + +```toml +chrome_args = [ + "--no-sandbox", + "--disable-setuid-sandbox", + "--disable-gpu" +] +``` + +Alternatively, set the `CI=true` environment variable to automatically add these flags. + ## License MIT diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 299ff1f..ba20484 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -141,8 +141,9 @@ pub async fn run_app(cli: Cli) -> Result<()> { } let config = Config::load()?; + let chrome_args = config.chrome_args.clone(); let searcher = - PatentSearcher::new(config.browser_path, !args.head, args.debug, args.verbose) + PatentSearcher::new(config.browser_path, !args.head, args.debug, args.verbose, chrome_args) .await?; let options = SearchOptions { @@ -162,8 +163,9 @@ pub async fn run_app(cli: Cli) -> Result<()> { } Commands::Fetch { args } => { let config = Config::load()?; + let chrome_args = config.chrome_args.clone(); let searcher = - PatentSearcher::new(config.browser_path, !args.head, args.debug, args.verbose) + PatentSearcher::new(config.browser_path, !args.head, args.debug, args.verbose, chrome_args) .await?; if args.raw { diff --git a/src/core/cdp/browser.rs b/src/core/cdp/browser.rs index aaccb26..cae7da8 100644 --- a/src/core/cdp/browser.rs +++ b/src/core/cdp/browser.rs @@ -335,11 +335,17 @@ pub struct BrowserManager { browser_path: Option, headless: bool, debug: bool, + chrome_args: Vec, state: Arc>, } impl BrowserManager { - pub fn new(browser_path: Option, headless: bool, debug: bool) -> Self { + pub fn new( + browser_path: Option, + headless: bool, + debug: bool, + chrome_args: Vec, + ) -> Self { let state = Arc::new(Mutex::new(BrowserState { browser: None, last_used: Instant::now() })); // Spawn the inactivity monitor task @@ -354,7 +360,7 @@ impl BrowserManager { } }); - Self { browser_path, headless, debug, state } + Self { browser_path, headless, debug, chrome_args, state } } pub async fn get_browser(&self) -> Result> { @@ -373,6 +379,11 @@ impl BrowserManager { args.push("--disable-setuid-sandbox"); } + // Add custom Chrome args from config + for arg in &self.chrome_args { + args.push(arg.as_str()); + } + let browser_path = self.browser_path.clone(); let browser = diff --git a/src/core/config.rs b/src/core/config.rs index 348a0e9..4db0675 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -7,6 +7,8 @@ use std::path::{Path, PathBuf}; #[derive(Debug, Serialize, Deserialize, Default, Clone)] pub struct Config { pub browser_path: Option, + #[serde(default)] + pub chrome_args: Vec, } impl Config { diff --git a/src/core/patent_search.rs b/src/core/patent_search.rs index a306154..bb9f852 100644 --- a/src/core/patent_search.rs +++ b/src/core/patent_search.rs @@ -59,8 +59,9 @@ impl PatentSearcher { headless: bool, debug: bool, verbose: bool, + chrome_args: Vec, ) -> Result { - let browser_manager = BrowserManager::new(browser_path, headless, debug); + let browser_manager = BrowserManager::new(browser_path, headless, debug, chrome_args); Ok(Self { browser_manager, verbose }) } diff --git a/src/mcp/mod.rs b/src/mcp/mod.rs index 7e91be9..2904b08 100644 --- a/src/mcp/mod.rs +++ b/src/mcp/mod.rs @@ -174,7 +174,8 @@ impl ServerHandler for PatentHandler { /// Run the MCP server over stdio pub async fn run() -> anyhow::Result<()> { let config = Config::load()?; - let searcher = PatentSearcher::new(config.browser_path, true, false, false) + let chrome_args = config.chrome_args.clone(); + let searcher = PatentSearcher::new(config.browser_path, true, false, false, chrome_args) .await .map_err(|e| anyhow::anyhow!("Failed to create PatentSearcher: {}", e))?; let handler = PatentHandler::new(Arc::new(searcher)); From fb4f850c5699c2ce0f13112b17414ae7525f7fb9 Mon Sep 17 00:00:00 2001 From: "Claude Sonnet 4.6" Date: Mon, 23 Feb 2026 15:08:12 +0900 Subject: [PATCH 3/3] style: fix formatting issues --- src/cli/mod.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ba20484..835c037 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -142,9 +142,14 @@ pub async fn run_app(cli: Cli) -> Result<()> { let config = Config::load()?; let chrome_args = config.chrome_args.clone(); - let searcher = - PatentSearcher::new(config.browser_path, !args.head, args.debug, args.verbose, chrome_args) - .await?; + let searcher = PatentSearcher::new( + config.browser_path, + !args.head, + args.debug, + args.verbose, + chrome_args, + ) + .await?; let options = SearchOptions { query: args.query, @@ -164,9 +169,14 @@ pub async fn run_app(cli: Cli) -> Result<()> { Commands::Fetch { args } => { let config = Config::load()?; let chrome_args = config.chrome_args.clone(); - let searcher = - PatentSearcher::new(config.browser_path, !args.head, args.debug, args.verbose, chrome_args) - .await?; + let searcher = PatentSearcher::new( + config.browser_path, + !args.head, + args.debug, + args.verbose, + chrome_args, + ) + .await?; if args.raw { let html = searcher.get_raw_html(&args.patent_id, args.language.as_deref()).await?;