From 791839aae5771a6e4e7f1ada0632071ffb9eee80 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 20 Aug 2026 13:56:40 -0400 Subject: [PATCH] fix(gem): name the skipped BUNDLE_PATH verbatim in the config-ignored warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gem_bundle_config_path_ignored detail interpolated the refused config value with `{value:?}` (Debug), which escapes backslashes. On Unix the two forms coincide (temp paths carry no backslashes), but on Windows the warning printed `C:\\Users\\…` for a config that says `C:\Users\…` — failing all three in_process_gem_config_warning tests on the windows-latest CI leg (red on main since #222 merged, inherited by every open PR) and mangling the path for any human copy-pasting it out of the warning. Format with Display inside manual quotes instead. The value is a single scraped config line, so Display cannot smuggle in newlines the quotes would mask. New platform-independent unit test pins it with a backslash-bearing value: `{:?}` doubles backslashes on every OS, so the pin is RED under the old format everywhere, not just on Windows. Co-Authored-By: Claude Fable 5 --- .../src/crawlers/ruby_crawler.rs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/socket-patch-core/src/crawlers/ruby_crawler.rs b/crates/socket-patch-core/src/crawlers/ruby_crawler.rs index b6bc0f0f..0016556d 100644 --- a/crates/socket-patch-core/src/crawlers/ruby_crawler.rs +++ b/crates/socket-patch-core/src/crawlers/ruby_crawler.rs @@ -673,8 +673,14 @@ pub struct BundleStoreDiscovery { pub fn config_path_ignored_warning(value: &str) -> (&'static str, String) { ( "gem_bundle_config_path_ignored", + // Display inside manual quotes, NOT `{value:?}`: Debug escaping + // doubles backslashes, so on Windows the detail printed + // `C:\\Users\\…` for a config that says `C:\Users\…` — breaking + // both the substring assertions and any human copy-pasting the + // path. The value is already a single scraped line, so Display + // cannot smuggle in newlines the quotes would mask. format!( - "bundler app config BUNDLE_PATH {value:?} resolves outside the project \ + "bundler app config BUNDLE_PATH \"{value}\" resolves outside the project \ root; ignoring it as an install root (a committed .bundle/config is \ untrusted input — set BUNDLE_PATH in the environment to use an \ out-of-tree bundle path)" @@ -1532,6 +1538,27 @@ mod tests { /// the CLI's warning channels), keyed by the verbatim config value — /// and stays `None` for a contained value or a `path.system` drop /// (bundler itself ignores the path there; nothing was refused). + /// The detail must carry the config value VERBATIM. `{value:?}` (Debug) + /// escaped backslashes, so on Windows the warning printed `C:\\Users\\…` + /// for a config that says `C:\Users\…` — invisible on Unix (temp paths + /// carry no backslashes), red on the windows-latest CI leg, and wrong + /// for any human copy-pasting the path out of the warning. A + /// backslash-bearing value pins it on every platform. + #[test] + fn config_path_ignored_warning_names_the_value_verbatim() { + let value = r"C:\Users\dev\bundle store"; + let (code, detail) = config_path_ignored_warning(value); + assert_eq!(code, "gem_bundle_config_path_ignored"); + assert!( + detail.contains(value), + "detail must contain the unescaped value: {detail}" + ); + assert!( + !detail.contains(r"C:\\Users"), + "Debug escaping must not double backslashes: {detail}" + ); + } + #[tokio::test] async fn discovery_records_skipped_config_path() { let dir = tempfile::tempdir().unwrap();