From 6351f8397f92aeee3686b6d53fbda59c3c142b4f Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 11:22:31 -0400 Subject: [PATCH 01/19] Support Poetry patch lock generations Wire hosted and vendored wheels across native Poetry lock formats. Preserve independent rollback and verify installer compatibility. Assisted-by: Codex:gpt-6-astra --- .../src/commands/scan/hosted.rs | 1 + .../src/patch/redirect/mod.rs | 2 + .../src/patch/redirect/poetry.rs | 71 +++++ .../src/patch/redirect/replay.rs | 4 +- crates/socket-patch-core/src/utils/mod.rs | 1 + .../src/utils/poetry_lock.rs | 215 +++++++++++++ .../src/vendor/pypi_poetry.rs | 220 ++++++++++---- .../tests/fixtures/poetry/0.12.17/poetry.lock | 14 + .../fixtures/poetry/0.12.17/pyproject.toml | 9 + .../tests/fixtures/poetry/1.0.10/poetry.lock | 20 ++ .../fixtures/poetry/1.0.10/pyproject.toml | 9 + .../tests/fixtures/poetry/1.1.15/poetry.lock | 20 ++ .../fixtures/poetry/1.1.15/pyproject.toml | 9 + .../tests/fixtures/poetry/1.2.2/poetry.lock | 23 ++ .../fixtures/poetry/1.2.2/pyproject.toml | 9 + .../tests/fixtures/poetry/1.3.2/poetry.lock | 23 ++ .../fixtures/poetry/1.3.2/pyproject.toml | 9 + .../tests/fixtures/poetry/1.4.2/poetry.lock | 23 ++ .../fixtures/poetry/1.4.2/pyproject.toml | 9 + .../tests/fixtures/poetry/1.5.1/poetry.lock | 22 ++ .../fixtures/poetry/1.5.1/pyproject.toml | 9 + .../tests/fixtures/poetry/1.6.1/poetry.lock | 22 ++ .../fixtures/poetry/1.6.1/pyproject.toml | 9 + .../tests/fixtures/poetry/1.7.1/poetry.lock | 22 ++ .../fixtures/poetry/1.7.1/pyproject.toml | 9 + .../tests/fixtures/poetry/1.8.5/poetry.lock | 22 ++ .../fixtures/poetry/1.8.5/pyproject.toml | 9 + .../tests/fixtures/poetry/2.0.1/poetry.lock | 23 ++ .../fixtures/poetry/2.0.1/pyproject.toml | 9 + .../tests/fixtures/poetry/2.1.4/poetry.lock | 23 ++ .../fixtures/poetry/2.1.4/pyproject.toml | 9 + .../tests/fixtures/poetry/2.2.1/poetry.lock | 23 ++ .../fixtures/poetry/2.2.1/pyproject.toml | 9 + .../tests/fixtures/poetry/2.3.4/poetry.lock | 23 ++ .../fixtures/poetry/2.3.4/pyproject.toml | 9 + .../tests/fixtures/poetry/2.4.3/poetry.lock | 23 ++ .../fixtures/poetry/2.4.3/pyproject.toml | 9 + .../socket-patch-core/tests/poetry_hosted.rs | 283 ++++++++++++++++++ docs/ecosystems.md | 2 +- docs/testing/poetry-compatibility.md | 28 ++ 40 files changed, 1221 insertions(+), 67 deletions(-) create mode 100644 crates/socket-patch-core/src/patch/redirect/poetry.rs create mode 100644 crates/socket-patch-core/src/utils/poetry_lock.rs create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/0.12.17/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/0.12.17/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.0.10/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.0.10/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.1.15/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.1.15/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.2.2/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.2.2/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.3.2/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.3.2/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.4.2/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.4.2/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.5.1/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.5.1/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.6.1/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.6.1/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.7.1/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.7.1/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.8.5/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/1.8.5/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.0.1/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.0.1/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.1.4/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.1.4/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.2.1/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.2.1/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.3.4/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.3.4/pyproject.toml create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock create mode 100644 crates/socket-patch-core/tests/fixtures/poetry/2.4.3/pyproject.toml create mode 100644 crates/socket-patch-core/tests/poetry_hosted.rs create mode 100644 docs/testing/poetry-compatibility.md diff --git a/crates/socket-patch-cli/src/commands/scan/hosted.rs b/crates/socket-patch-cli/src/commands/scan/hosted.rs index 2060cac0..53b05628 100644 --- a/crates/socket-patch-cli/src/commands/scan/hosted.rs +++ b/crates/socket-patch-cli/src/commands/scan/hosted.rs @@ -27,6 +27,7 @@ const REDIRECT_CANDIDATE_FILES: &[&str] = &[ "bun.lock", "requirements.txt", "uv.lock", + "poetry.lock", "pyproject.toml", "Cargo.toml", "Cargo.lock", diff --git a/crates/socket-patch-core/src/patch/redirect/mod.rs b/crates/socket-patch-core/src/patch/redirect/mod.rs index d291c7b9..e604b749 100644 --- a/crates/socket-patch-core/src/patch/redirect/mod.rs +++ b/crates/socket-patch-core/src/patch/redirect/mod.rs @@ -25,6 +25,7 @@ use crate::vendor::yarn_berry_lock::yarnrc_compression_level; pub mod golang_local; mod pnpm; +mod poetry; mod replay; mod requirements; mod state; @@ -215,6 +216,7 @@ pub fn rewrite_registry_redirect_with_python_metadata( rewrite_bun_lock(files, overrides, &mut result); rewrite_pypi_requirements(files, overrides, &mut result); rewrite_uv_lock(files, overrides, python_metadata, &mut result); + poetry::rewrite_poetry(files, overrides, &mut result); rewrite_cargo(files, overrides, &mut result); rewrite_composer_lock(files, overrides, &mut result); rewrite_nuget(files, overrides, &mut result); diff --git a/crates/socket-patch-core/src/patch/redirect/poetry.rs b/crates/socket-patch-core/src/patch/redirect/poetry.rs new file mode 100644 index 00000000..35c86aba --- /dev/null +++ b/crates/socket-patch-core/src/patch/redirect/poetry.rs @@ -0,0 +1,71 @@ +use std::collections::BTreeMap; + +use serde_json::Value; + +use super::{DepOverride, FileEdit, RewriteResult, RewriteWarning}; +use crate::utils::poetry_lock::{poetry_lock_edits, rewrite_poetry_lock}; + +pub(super) fn rewrite_poetry( + files: &BTreeMap, + overrides: &[DepOverride], + result: &mut RewriteResult, +) { + for (path, original) in files + .iter() + .filter(|(path, _)| path.as_str() == "poetry.lock" || path.ends_with("/poetry.lock")) + { + let mut content = original.clone(); + for dep in overrides.iter().filter(|dep| dep.ecosystem == "pypi") { + let Some(sha256) = dep.integrity.sha256.as_deref() else { + result.warnings.push(RewriteWarning { + code: "redirect_poetry_missing_sha256".into(), + detail: format!("{} has no SHA-256 integrity", dep.name), + }); + continue; + }; + let filename = dep.artifact_url.rsplit('/').next().unwrap_or(""); + match rewrite_poetry_lock( + &content, + &dep.name, + &dep.version, + "url", + &dep.artifact_url, + filename, + sha256, + ) { + Ok(Some(rewritten)) if rewritten != content => { + match poetry_lock_edits(&content, &rewritten, &dep.name) { + Ok(edits) => { + for (original, new) in edits { + result.edits.push(FileEdit { + path: path.clone(), + kind: "redirect_poetry_lock_package".into(), + action: "rewritten".into(), + key: Some(format!("{}@{}", dep.name, dep.version)), + original: Some(Value::String(original)), + new: Some(Value::String(new)), + }); + } + } + Err(detail) => { + result.warnings.push(RewriteWarning { + code: "redirect_poetry_lock_unsupported".into(), + detail, + }); + continue; + } + } + content = rewritten; + } + Ok(_) => {} + Err(detail) => result.warnings.push(RewriteWarning { + code: "redirect_poetry_lock_unsupported".into(), + detail: format!("{path}: {detail}"), + }), + } + } + if content != *original { + result.files.insert(path.clone(), content); + } + } +} diff --git a/crates/socket-patch-core/src/patch/redirect/replay.rs b/crates/socket-patch-core/src/patch/redirect/replay.rs index af29f644..a35f29cd 100644 --- a/crates/socket-patch-core/src/patch/redirect/replay.rs +++ b/crates/socket-patch-core/src/patch/redirect/replay.rs @@ -86,7 +86,9 @@ enum Inverse { /// Gemfile.lock) revert together or not at all. fn classify(kind: &str, action: &str) -> (&'static str, Inverse) { match kind { - "redirect_requirements_line" | "redirect_uv_lock_wheel" => ("pypi", Inverse::ReplaceFragment), + "redirect_requirements_line" | "redirect_uv_lock_wheel" | "redirect_poetry_lock_package" => { + ("pypi", Inverse::ReplaceFragment) + } "redirect_composer_dist" => ("composer", Inverse::ReplaceFragment), "redirect_cargo_toml_dep" | "redirect_cargo_lock_entry" => ("cargo", Inverse::ReplaceFragment), "redirect_cargo_registry" => ( diff --git a/crates/socket-patch-core/src/utils/mod.rs b/crates/socket-patch-core/src/utils/mod.rs index d50be2dd..e83802f9 100644 --- a/crates/socket-patch-core/src/utils/mod.rs +++ b/crates/socket-patch-core/src/utils/mod.rs @@ -1,6 +1,7 @@ pub mod env_compat; pub mod fs; pub(crate) mod http; +pub mod poetry_lock; pub mod process; pub mod purl; pub mod python_lock; diff --git a/crates/socket-patch-core/src/utils/poetry_lock.rs b/crates/socket-patch-core/src/utils/poetry_lock.rs new file mode 100644 index 00000000..b6cedde3 --- /dev/null +++ b/crates/socket-patch-core/src/utils/poetry_lock.rs @@ -0,0 +1,215 @@ +use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table, Value}; + +use crate::crawlers::python_crawler::canonicalize_pypi_name; + +pub fn lock_version(lock: &DocumentMut) -> Result<&str, String> { + let metadata = lock.get("metadata").ok_or("missing Poetry lock metadata")?; + match metadata.get("lock-version").and_then(Item::as_str) { + Some(version @ ("1.0" | "1.1" | "2.0" | "2.1")) => Ok(version), + None if metadata + .get("hashes") + .and_then(Item::as_table_like) + .is_some() => + { + Ok("0") + } + _ => Err("unsupported Poetry lock version".into()), + } +} + +pub fn rewrite_poetry_lock( + text: &str, + name: &str, + version: &str, + source_type: &str, + source_url: &str, + filename: &str, + sha256: &str, +) -> Result, String> { + if !matches!(source_type, "file" | "url") + || sha256.len() != 64 + || !sha256.bytes().all(|byte| byte.is_ascii_hexdigit()) + { + return Err("invalid Poetry artifact source or SHA-256".into()); + } + let parts: Vec<_> = filename.split('-').collect(); + if !filename.ends_with(".whl") + || !matches!(parts.len(), 5 | 6) + || canonicalize_pypi_name(parts[0]) != canonicalize_pypi_name(name) + || parts[1] != version + || filename.contains(['/', '\\']) + { + return Err("Poetry patch wheel does not match the locked package".into()); + } + let mut lock: DocumentMut = text + .parse() + .map_err(|e| format!("invalid Poetry lock: {e}"))?; + let format = lock_version(&lock)?.to_string(); + if format == "0" && source_type == "url" { + return Err("Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0".into()); + } + let effective_url = if format == "1.0" && source_type == "url" { + // Poetry 1.0 appends #egg without checking for an existing fragment. + format!("{source_url}#sha256={sha256}&") + } else { + source_url.to_string() + }; + let packages = lock + .get_mut("package") + .and_then(Item::as_array_of_tables_mut) + .ok_or("missing Poetry packages")?; + let indices: Vec<_> = packages + .iter() + .enumerate() + .filter(|(_, package)| { + package + .get("name") + .and_then(Item::as_str) + .is_some_and(|candidate| { + canonicalize_pypi_name(candidate) == canonicalize_pypi_name(name) + }) + }) + .map(|(index, _)| index) + .collect(); + if indices.is_empty() { + return Ok(None); + } + if indices.len() != 1 { + return Err("forked Poetry package requires an unambiguous source".into()); + } + let package = packages + .get_mut(indices[0]) + .ok_or("missing Poetry package")?; + if package.get("version").and_then(Item::as_str) != Some(version) { + return Ok(None); + } + let package_name = package + .get("name") + .and_then(Item::as_str) + .unwrap_or(name) + .to_string(); + if let Some(source) = package.get("source") { + if source.get("type").and_then(Item::as_str) != Some(source_type) + || source.get("url").and_then(Item::as_str) != Some(effective_url.as_str()) + { + return Err("refusing to replace an existing Poetry source".into()); + } + } + let mut entry = InlineTable::new(); + entry.insert("file", Value::from(filename)); + entry.insert("hash", Value::from(format!("sha256:{sha256}"))); + let mut files = Array::new(); + files.push(entry); + let mut source = Table::new(); + source.insert("type", value(source_type)); + source.insert("url", value(effective_url)); + if matches!(format.as_str(), "0" | "1.0") { + source.insert("reference", value("")); + } + package.insert("source", Item::Table(source)); + if format == "1.1" && source_type == "url" { + package.insert("files", value(files.clone())); + } + if format.starts_with('2') { + package.insert("files", value(files)); + } else if format == "0" { + let mut hashes = Array::new(); + hashes.push(sha256); + lock["metadata"]["hashes"][&package_name] = value(hashes); + } else { + lock["metadata"]["files"][&package_name] = value(files); + } + let mut rewritten = lock.to_string(); + if text.contains("\r\n") { + rewritten = rewritten.replace("\r\n", "\n").replace('\n', "\r\n"); + } + let edits = poetry_lock_edits(text, &rewritten, name)?; + let mut result = text.to_string(); + for (original, replacement) in edits { + result = result.replacen(&original, &replacement, 1); + } + Ok(Some(result)) +} + +pub fn poetry_lock_edits( + original: &str, + rewritten: &str, + name: &str, +) -> Result, String> { + fn fragments(text: &str, name: &str) -> Result, String> { + let lock = toml_edit::Document::parse(text).map_err(|e| e.to_string())?; + let package = lock + .get("package") + .and_then(Item::as_array_of_tables) + .and_then(|packages| { + packages.iter().find(|package| { + package + .get("name") + .and_then(Item::as_str) + .is_some_and(|value| { + canonicalize_pypi_name(value) == canonicalize_pypi_name(name) + }) + }) + }) + .ok_or("missing Poetry package")?; + fn extend_span(table: &Table, span: &mut std::ops::Range) { + if let Some(own) = table.span() { + span.start = span.start.min(own.start); + span.end = span.end.max(own.end); + } + for (_, item) in table.iter() { + if let Some(own) = item.span() { + span.start = span.start.min(own.start); + span.end = span.end.max(own.end); + } + if let Some(child) = item.as_table() { + extend_span(child, span); + } + } + } + let mut span = package.span().ok_or("missing Poetry package span")?; + extend_span(package, &mut span); + span.end += text[span.end..] + .find(['\r', '\n']) + .unwrap_or(text.len() - span.end); + let mut result = vec![text[span].to_string()]; + let metadata = lock.get("metadata").ok_or("missing Poetry metadata")?; + let format = metadata + .get("lock-version") + .and_then(Item::as_str) + .unwrap_or("0"); + if !format.starts_with('2') { + let field = if format == "0" { "hashes" } else { "files" }; + let table = metadata + .get(field) + .and_then(Item::as_table) + .ok_or("missing Poetry integrity table")?; + let package_name = package["name"].as_str().ok_or("missing package name")?; + let start = table + .key(package_name) + .and_then(|key| key.span()) + .ok_or("missing Poetry integrity key")? + .start; + let end = table + .get(package_name) + .and_then(Item::span) + .ok_or("missing Poetry integrity span")? + .end; + result.push(text[start..end].to_string()); + } + Ok(result) + } + let before = fragments(original, name)?; + let after = fragments(rewritten, name)?; + let mut edits = Vec::new(); + for (old, new) in before.into_iter().zip(after) { + if old == new { + continue; + } + if original.matches(&old).count() != 1 || rewritten.matches(&new).count() != 1 { + return Err("ambiguous Poetry rollback fragment".into()); + } + edits.push((old, new)); + } + Ok(edits) +} diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index 164984fd..ed55b5eb 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -1,21 +1,4 @@ -//! poetry-project wiring: a lock-ONLY `[[package]]` splice (poetry.lock -//! lock-versions 2.0 and 2.1). -//! -//! Unlike uv (whose sources entry must be paired into pyproject.toml), poetry -//! installs are 100% lock-driven and `metadata.content-hash` covers ONLY the -//! pyproject — so the vendored wheel is wired by rewriting just the target -//! `[[package]]` unit (files[] → the single patched-wheel hash, plus a -//! `[package.source] type = "file"` table) and touching nothing else. The -//! spike proved this splice passes `poetry install`/`sync`/`check --lock` -//! byte-stably on BOTH supported majors (Poetry 2.4.1 = lock 2.1, Poetry -//! 1.8.5 = lock 2.0), is hash-fail-closed against a tampered wheel, and works -//! for direct AND transitive deps — see `spikes/poetry/` and the poetry -//! section of `spikes/PHASE0-V2-FINDINGS.txt`. -//! -//! Drift caveat (spike P5): `poetry update `, 2.x `poetry lock -//! --regenerate` and 1.x plain `poetry lock` silently revert the splice with -//! exit 0; the lock's files[] hash is the drift oracle. `pyproject.toml` and -//! `metadata.content-hash` are NEVER written by this backend. +//! Poetry lock wiring preserves the pyproject content hash and records reversible edits. use std::path::Path; @@ -108,16 +91,21 @@ pub(super) async fn load_poetry_project( .and_then(|m| item_get(m, "lock-version")) .and_then(Item::as_str) .map(str::to_string) + .or_else(|| { + crate::utils::poetry_lock::lock_version(&lock) + .ok() + .map(str::to_string) + }) .ok_or_else(|| { ( "pypi_poetry_lock_version_unsupported", - format!("{LOCK_FILE} has no [metadata] lock-version; only 2.x locks are supported"), + format!("{LOCK_FILE} has no [metadata] lock-version; supported locks are legacy hashes, 1.0, 1.1, and 2.x"), ) })?; let mut warnings = Vec::new(); match lock_version.as_str() { // The fixture-tested versions (Poetry 1.8.x writes 2.0, 2.x writes 2.1). - "2.0" | "2.1" => {} + "0" | "1.0" | "1.1" | "2.0" | "2.1" => {} // A newer 2.x minor keeps the shapes we rewrite (additive schema), so // it warns instead of refusing; `poetry check --lock` is the backstop. v if is_newer_2x(v) => warnings.push(VendorWarning::new( @@ -131,12 +119,18 @@ pub(super) async fn load_poetry_project( return Err(( "pypi_poetry_lock_version_unsupported", format!( - "poetry.lock lock-version {v:?} is not a supported 2.x lock; re-lock with \ + "poetry.lock lock-version {v:?} is not a supported lock; re-lock with \ Poetry >= 1.3" ), )) } } + if matches!(lock_version.as_str(), "0" | "1.0" | "1.1" | "2.0") { + warnings.push(VendorWarning::new( + "pypi_poetry_integrity_unverified", + "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes".to_string(), + )); + } let pyproject_text = read_regular_to_string(&root.join("pyproject.toml")) .await @@ -303,14 +297,39 @@ pub(super) async fn wire_poetry( PoetryTarget::Fresh => {} } - let (old_unit, new_unit) = rewrite_target_package_unit( - &p.lock_text, - canon_name, - rel_wheel, - wheel_file_name, - wheel_sha256_hex, - )?; - let new_lock = p.lock_text.replacen(&old_unit, &new_unit, 1); + let edits = + if matches!(p.lock_version.as_str(), "0" | "1.0" | "1.1") || p.lock_text.contains("\r\n") { + let rewritten = crate::utils::poetry_lock::rewrite_poetry_lock( + &p.lock_text, + canon_name, + version, + "file", + rel_wheel, + wheel_file_name, + wheel_sha256_hex, + ) + .map_err(|detail| ("pypi_poetry_lock_parse_failed", detail))? + .ok_or_else(|| { + ( + "pypi_poetry_lock_package_missing", + format!("no {canon_name}@{version} in {LOCK_FILE}"), + ) + })?; + crate::utils::poetry_lock::poetry_lock_edits(&p.lock_text, &rewritten, canon_name) + .map_err(|detail| ("pypi_poetry_lock_parse_failed", detail))? + } else { + vec![rewrite_target_package_unit( + &p.lock_text, + canon_name, + rel_wheel, + wheel_file_name, + wheel_sha256_hex, + )?] + }; + let mut new_lock = p.lock_text.clone(); + for (old_unit, new_unit) in &edits { + new_lock = new_lock.replacen(old_unit, new_unit, 1); + } // Mode-preserving: the lock is a user-owned file we merely edit, so the // swapped-in inode must keep its permission bits rather than reset them // to umask defaults (same class as the revert leg in common.rs). @@ -323,14 +342,19 @@ pub(super) async fn wire_poetry( ) })?; - let wiring = vec![record( - LOCK_FILE, - KIND_LOCK_PACKAGE, - WiringAction::Rewritten, - canon_name, - Some(old_unit), - new_unit, - )]; + let wiring = edits + .into_iter() + .map(|(old_unit, new_unit)| { + record( + LOCK_FILE, + KIND_LOCK_PACKAGE, + WiringAction::Rewritten, + canon_name, + Some(old_unit), + new_unit, + ) + }) + .collect(); let meta = PoetryMeta { dep_class: classify_dependency(p, canon_name).to_string(), lock_version: p.lock_version.clone(), @@ -824,6 +848,89 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 .unwrap() } + #[tokio::test] + async fn legacy_and_crlf_patches_revert_independently() { + for version in ["0.12.17", "1.0.10", "1.1.15", "1.2.2", "1.8.5", "2.4.3"] { + for crlf in [false, true] { + for reverse in [false, true] { + let native = std::fs::read_to_string(format!( + "{}/tests/fixtures/poetry/{version}/poetry.lock", + env!("CARGO_MANIFEST_DIR") + )) + .unwrap(); + let mut lock: DocumentMut = native.parse().unwrap(); + let packages = lock["package"].as_array_of_tables_mut().unwrap(); + let mut second = packages.get(0).unwrap().clone(); + second["name"] = toml_edit::value("six"); + second["version"] = toml_edit::value("1.16.0"); + second.set_position(None); + second.remove("extras"); + second.set_position(None); + second.remove("extras"); + packages.push(second); + for field in ["files", "hashes"] { + if let Some(entries) = lock["metadata"].get_mut(field) { + if let Some(value) = entries.get("urllib3").cloned() { + entries["six"] = value; + } + } + } + let pristine = lock.to_string(); + let pristine = if crlf { + pristine.replace('\n', "\r\n") + } else { + pristine + }; + let tmp = write_project(&pristine, PYPROJECT_DIRECT).await; + let mut entries = Vec::new(); + for (name, version, wheel) in [ + ("urllib3", "1.26.18", "urllib3-1.26.18-py2.py3-none-any.whl"), + ("six", "1.16.0", WHEEL_NAME), + ] { + let project = load_poetry_project(tmp.path()).await.unwrap(); + let path = format!(".socket/vendor/pypi/{UUID}/{wheel}"); + let (wiring, meta) = wire_poetry( + &project, + tmp.path(), + name, + version, + &path, + wheel, + WHEEL_SHA, + UUID, + ) + .await + .unwrap(); + entries.push(entry_for(wiring, meta)); + } + if reverse { + entries.reverse(); + } + let comment = if crlf { + "# retained edit\r\n" + } else { + "# retained edit\n" + }; + tokio::fs::write( + tmp.path().join("poetry.lock"), + format!("{comment}{}", read_lock(tmp.path()).await), + ) + .await + .unwrap(); + for entry in entries { + let outcome = revert_poetry(&entry, tmp.path(), false).await; + assert!( + outcome.success && outcome.warnings.is_empty(), + "{version}: {:?}", + outcome.warnings + ); + } + assert_eq!(read_lock(tmp.path()).await, format!("{comment}{pristine}")); + } + } + } + } + /// The load-bearing oracle: wiring the registry lock must produce the /// spliced evidence-lockonly lock BYTE-IDENTICALLY (per lock version, /// direct and transitive), leaving pyproject and content-hash untouched. @@ -862,7 +969,7 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 for (lock_version, before, after, pyproject, dep_class) in cases { let tmp = write_project(before, pyproject).await; let p = load_poetry_project(tmp.path()).await.unwrap(); - assert!(p.warnings.is_empty(), "{lock_version}: {:?}", p.warnings); + assert_eq!(p.warnings.len(), usize::from(lock_version == "2.0")); assert_eq!(p.lock_version, lock_version); assert_eq!(classify_dependency(&p, "six"), dep_class); assert_eq!( @@ -982,35 +1089,18 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 ); } - /// A CRLF lock (git autocrlf checkout) parses fine, but the splice - /// fragment is re-derived via `str::lines()` (which strips `\r`) and can - /// never byte-match the file — the replacen would silently no-op while - /// still reporting success and recording a rewrite that never landed. - /// Wiring must refuse instead. #[tokio::test] - async fn crlf_lock_refuses_instead_of_silently_wiring_nothing() { + async fn crlf_lock_wires_and_reverts_without_changing_line_endings() { let crlf = LOCK21_DIRECT_REGISTRY.replace('\n', "\r\n"); let tmp = write_project(&crlf, PYPROJECT_DIRECT).await; - let p = load_poetry_project(tmp.path()).await.unwrap(); - assert_eq!( - check_target_guards(&p, "six", "1.16.0", UUID).unwrap(), - PoetryTarget::Fresh - ); - - let err = wire_poetry( - &p, - tmp.path(), - "six", - "1.16.0", - REL_WHEEL, - WHEEL_NAME, - WHEEL_SHA, - UUID, - ) - .await - .unwrap_err(); - assert_eq!(err.0, "pypi_poetry_lock_parse_failed"); - assert_eq!(read_lock(tmp.path()).await, crlf, "refusal writes nothing"); + let project = load_poetry_project(tmp.path()).await.unwrap(); + let (wiring, meta) = wire_default(&project, tmp.path()).await; + let rewritten = read_lock(tmp.path()).await; + assert!(rewritten.contains(REL_WHEEL)); + assert!(!rewritten.replace("\r\n", "").contains('\n')); + let outcome = revert_poetry(&entry_for(wiring, meta), tmp.path(), false).await; + assert!(outcome.success); + assert_eq!(read_lock(tmp.path()).await, crlf); } /// Valid TOML poetry itself never emits — `name="six"` with no spaces @@ -1093,7 +1183,7 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 let tmp = write_project("[[package]]\nname = \"six\"\n", PYPROJECT_DIRECT).await; let err = load_poetry_project(tmp.path()).await.unwrap_err(); assert_eq!(err.0, "pypi_poetry_lock_version_unsupported"); - for bad in ["1.1", "3.0"] { + for bad in ["1.2", "3.0"] { let lock = LOCK21_DIRECT_REGISTRY.replace( "lock-version = \"2.1\"", &format!("lock-version = \"{bad}\""), diff --git a/crates/socket-patch-core/tests/fixtures/poetry/0.12.17/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/0.12.17/poetry.lock new file mode 100644 index 00000000..b9148ce1 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/0.12.17/poetry.lock @@ -0,0 +1,14 @@ +[[package]] +category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +version = "1.26.18" + +[metadata] +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" +python-versions = ">=3.8" + +[metadata.hashes] +urllib3 = [] diff --git a/crates/socket-patch-core/tests/fixtures/poetry/0.12.17/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/0.12.17/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/0.12.17/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.0.10/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.0.10/poetry.lock new file mode 100644 index 00000000..617f6844 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.0.10/poetry.lock @@ -0,0 +1,20 @@ +[[package]] +category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +version = "1.26.18" + +[package.extras] +brotli = ["brotlicffi (>=0.8.0)", "brotli (1.0.9)", "brotlipy (>=0.6.0)", "brotli (>=1.0.9)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[metadata] +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" +lock-version = "1.0" +python-versions = ">=3.8" + +[metadata.files] +urllib3 = [] diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.0.10/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.0.10/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.0.10/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.1.15/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.1.15/poetry.lock new file mode 100644 index 00000000..afb7e058 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.1.15/poetry.lock @@ -0,0 +1,20 @@ +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" + +[metadata.files] +urllib3 = [] diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.1.15/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.1.15/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.1.15/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.2.2/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.2.2/poetry.lock new file mode 100644 index 00000000..81885b17 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.2.2/poetry.lock @@ -0,0 +1,23 @@ +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" + +[metadata.files] +urllib3 = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.2.2/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.2.2/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.2.2/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.3.2/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.3.2/poetry.lock new file mode 100644 index 00000000..1fc3bf45 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.3.2/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.3.2/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.3.2/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.3.2/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.4.2/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.4.2/poetry.lock new file mode 100644 index 00000000..6cf04876 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.4.2/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.4.2/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.4.2/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.4.2/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.5.1/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.5.1/poetry.lock new file mode 100644 index 00000000..5fc7fd61 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.5.1/poetry.lock @@ -0,0 +1,22 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.5.1/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.5.1/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.5.1/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.6.1/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.6.1/poetry.lock new file mode 100644 index 00000000..fa84f4d0 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.6.1/poetry.lock @@ -0,0 +1,22 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.6.1/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.6.1/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.6.1/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.7.1/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.7.1/poetry.lock new file mode 100644 index 00000000..f2eab4d2 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.7.1/poetry.lock @@ -0,0 +1,22 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.7.1/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.7.1/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.7.1/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.8.5/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/1.8.5/poetry.lock new file mode 100644 index 00000000..4ccb63f6 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.8.5/poetry.lock @@ -0,0 +1,22 @@ +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/1.8.5/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/1.8.5/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/1.8.5/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.0.1/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/2.0.1/poetry.lock new file mode 100644 index 00000000..43ce61ce --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.0.1/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main"] +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.0.1/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/2.0.1/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.0.1/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.1.4/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/2.1.4/poetry.lock new file mode 100644 index 00000000..ce51e702 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.1.4/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main"] +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.1.4/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/2.1.4/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.1.4/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.2.1/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/2.2.1/poetry.lock new file mode 100644 index 00000000..5fca1f1e --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.2.1/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main"] +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.2.1/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/2.2.1/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.2.1/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.3.4/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/2.3.4/poetry.lock new file mode 100644 index 00000000..b7e609fd --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.3.4/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main"] +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.3.4/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/2.3.4/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.3.4/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock b/crates/socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock new file mode 100644 index 00000000..efa06eee --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Poetry 2.4.3 and should not be changed by hand. + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main"] +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.8" +content-hash = "4f9ffb08e662523420bf03909c6f496ad5f6d44d5107bda8fb5955ce0dfe3ab2" diff --git a/crates/socket-patch-core/tests/fixtures/poetry/2.4.3/pyproject.toml b/crates/socket-patch-core/tests/fixtures/poetry/2.4.3/pyproject.toml new file mode 100644 index 00000000..4e9d7ee4 --- /dev/null +++ b/crates/socket-patch-core/tests/fixtures/poetry/2.4.3/pyproject.toml @@ -0,0 +1,9 @@ +[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" diff --git a/crates/socket-patch-core/tests/poetry_hosted.rs b/crates/socket-patch-core/tests/poetry_hosted.rs new file mode 100644 index 00000000..c6d32622 --- /dev/null +++ b/crates/socket-patch-core/tests/poetry_hosted.rs @@ -0,0 +1,283 @@ +use socket_patch_core::patch::redirect::{ + revert_remaining_redirect_edits, rewrite_registry_redirect, DepOverride, Integrity, + RedirectState, +}; +use socket_patch_core::utils::poetry_lock::rewrite_poetry_lock; +use std::collections::BTreeMap; + +const VERSIONS: &[&str] = &[ + "0.12.17", "1.0.10", "1.1.15", "1.2.2", "1.3.2", "1.4.2", "1.5.1", "1.6.1", "1.7.1", "1.8.5", + "2.0.1", "2.1.4", "2.2.1", "2.3.4", "2.4.3", +]; +const WHEEL: &str = "urllib3-1.26.18-py2.py3-none-any.whl"; +const URL: &str = "https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl"; + +fn original(version: &str) -> String { + std::fs::read_to_string(format!( + "{}/tests/fixtures/poetry/{version}/poetry.lock", + env!("CARGO_MANIFEST_DIR") + )) + .unwrap() +} + +fn patch() -> DepOverride { + DepOverride { + ecosystem: "pypi".into(), + name: "urllib3".into(), + namespace: None, + version: "1.26.18".into(), + token: "7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e".into(), + patch_uuid: "e828efa5-5c6d-43f3-9909-03f5ac232b98".into(), + artifact_url: URL.into(), + berry_zip_url: None, + registry_override: None, + integrity: Integrity { + sha256: Some("a".repeat(64)), + ..Integrity::default() + }, + } +} + +#[tokio::test] +async fn native_lock_generations_redirect_idempotently_and_restore_every_byte() { + for version in VERSIONS { + for crlf in [false, true] { + let pristine = if crlf { + original(version).replace('\n', "\r\n") + } else { + original(version) + }; + let files = BTreeMap::from([("poetry.lock".into(), pristine.clone())]); + let result = rewrite_registry_redirect(&files, &[patch()]); + if *version == "0.12.17" { + assert!(result.files.is_empty()); + assert!(result.edits.is_empty()); + assert!(result + .warnings + .iter() + .any(|warning| warning.detail.contains("ignores URL sources"))); + continue; + } + assert!( + result.warnings.is_empty(), + "{version}: {:?}", + result.warnings + ); + let redirected = &result.files["poetry.lock"]; + assert!(redirected.contains(URL)); + let again = rewrite_registry_redirect(&result.files, &[patch()]); + assert!(again.warnings.is_empty(), "{version}: {:?}", again.warnings); + assert!(again.files.is_empty()); + assert!(again.edits.is_empty()); + let directory = tempfile::tempdir().unwrap(); + tokio::fs::write(directory.path().join("poetry.lock"), redirected) + .await + .unwrap(); + let mut state = RedirectState { + edits: result.edits, + ..RedirectState::default() + }; + let outcome = + revert_remaining_redirect_edits(directory.path(), &mut state, false).await; + assert!(outcome.fully_reverted(), "{:?}", outcome.refusals); + assert_eq!( + tokio::fs::read_to_string(directory.path().join("poetry.lock")) + .await + .unwrap(), + pristine + ); + } + } +} + +#[test] +fn every_native_lock_generation_supports_file_sources() { + for version in VERSIONS { + let pristine = original(version); + let path = format!(".socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/{WHEEL}"); + let rewritten = rewrite_poetry_lock( + &pristine, + "URLLib3", + "1.26.18", + "file", + &path, + WHEEL, + &"a".repeat(64), + ) + .unwrap() + .unwrap(); + let lock: toml_edit::DocumentMut = rewritten.parse().unwrap(); + let package = lock["package"] + .as_array_of_tables() + .unwrap() + .get(0) + .unwrap(); + assert_eq!(package["source"]["url"].as_str(), Some(path.as_str())); + assert_eq!( + rewrite_poetry_lock( + &rewritten, + "urllib3", + "1.26.18", + "file", + &path, + WHEEL, + &"a".repeat(64) + ) + .unwrap() + .unwrap(), + rewritten + ); + let old: toml_edit::DocumentMut = pristine.parse().unwrap(); + assert_eq!( + old["metadata"]["content-hash"].as_str(), + lock["metadata"]["content-hash"].as_str() + ); + } +} + +#[test] +fn invalid_inputs_never_produce_edits() { + let pristine = original("2.4.3"); + let source = "\n[package.source]\ntype='git'\nurl='https://example.test/urllib3'\n"; + let fork = "\n[[package]]\nname='urllib3'\nversion='1.26.18'\n"; + for lock in [ + pristine.replace("[metadata]", &format!("{source}\n[metadata]")), + format!("{pristine}{fork}"), + pristine.replace("lock-version = \"2.1\"", "lock-version = \"3.0\""), + "[[invalid".into(), + ] { + let files = BTreeMap::from([("poetry.lock".into(), lock)]); + let result = rewrite_registry_redirect(&files, &[patch()]); + assert!(result.files.is_empty()); + assert!(result.edits.is_empty()); + assert!(!result.warnings.is_empty()); + } + for (filename, hash) in [ + ("requests-1.26.18-py3-none-any.whl", "a".repeat(64)), + ("urllib3-1.0-py3-none-any.whl", "a".repeat(64)), + (WHEEL, "bad".into()), + (WHEEL, "z".repeat(64)), + ] { + assert!( + rewrite_poetry_lock(&pristine, "urllib3", "1.26.18", "url", URL, filename, &hash) + .is_err() + ); + } + let files = BTreeMap::from([("poetry.lock".into(), pristine)]); + let mut missing_hash = patch(); + missing_hash.integrity.sha256 = None; + let result = rewrite_registry_redirect(&files, &[missing_hash]); + assert!(result.files.is_empty()); + assert_eq!(result.warnings[0].code, "redirect_poetry_missing_sha256"); +} + +#[tokio::test] +async fn drift_keeps_the_lock_and_rollback_ledger() { + let files = BTreeMap::from([("poetry.lock".into(), original("1.1.15"))]); + let result = rewrite_registry_redirect(&files, &[patch()]); + let changed = result.files["poetry.lock"].replace("sha256:aaaa", "sha256:bbbb"); + let directory = tempfile::tempdir().unwrap(); + tokio::fs::write(directory.path().join("poetry.lock"), &changed) + .await + .unwrap(); + let mut state = RedirectState { + edits: result.edits, + ..RedirectState::default() + }; + let outcome = revert_remaining_redirect_edits(directory.path(), &mut state, false).await; + assert!(!outcome.fully_reverted()); + assert!(!state.edits.is_empty()); + assert_eq!( + tokio::fs::read_to_string(directory.path().join("poetry.lock")) + .await + .unwrap(), + changed + ); +} + +#[tokio::test] +async fn either_patch_reverts_independently_with_unrelated_edits() { + for version in VERSIONS.iter().filter(|version| **version != "0.12.17") { + for crlf in [false, true] { + for first_name in ["urllib3", "six"] { + let mut lock: toml_edit::DocumentMut = original(version).parse().unwrap(); + let packages = lock["package"].as_array_of_tables_mut().unwrap(); + let mut second = packages.get(0).unwrap().clone(); + second["name"] = toml_edit::value("six"); + second["version"] = toml_edit::value("1.16.0"); + second.set_position(None); + second.remove("extras"); + packages.push(second); + if let Some(files) = lock["metadata"].get_mut("files") { + if let Some(value) = files.get("urllib3").cloned() { + files["six"] = value; + } + } + let pristine = lock.to_string(); + let pristine = if crlf { + pristine.replace('\n', "\r\n") + } else { + pristine + }; + let second_patch = DepOverride { + name: "six".into(), + version: "1.16.0".into(), + artifact_url: URL.replace("urllib3", "six").replace("1.26.18", "1.16.0"), + ..patch() + }; + let files = BTreeMap::from([("poetry.lock".into(), pristine.clone())]); + let first = rewrite_registry_redirect(&files, &[patch()]); + assert!( + !first.files.is_empty(), + "{version}: {:?}\n{pristine}", + first.warnings + ); + let second = rewrite_registry_redirect(&first.files, &[second_patch]); + assert!( + !second.files.is_empty(), + "{version}: {:?}\n{}", + second.warnings, + first.files["poetry.lock"] + ); + assert!(second.warnings.is_empty(), "{:?}", second.warnings); + let directory = tempfile::tempdir().unwrap(); + let unrelated = if crlf { + "# retained user edit\r\n" + } else { + "# retained user edit\n" + }; + tokio::fs::write( + directory.path().join("poetry.lock"), + format!("{unrelated}{}", second.files["poetry.lock"]), + ) + .await + .unwrap(); + let mut states: Vec<_> = [first, second] + .into_iter() + .map(|result| RedirectState { + edits: result.edits, + ..RedirectState::default() + }) + .collect(); + if first_name == "six" { + states.reverse(); + } + for state in &mut states { + let outcome = + revert_remaining_redirect_edits(directory.path(), state, false).await; + assert!( + outcome.fully_reverted(), + "{version}: {:?}", + outcome.refusals + ); + } + assert_eq!( + tokio::fs::read_to_string(directory.path().join("poetry.lock")) + .await + .unwrap(), + format!("{unrelated}{pristine}") + ); + } + } + } +} diff --git a/docs/ecosystems.md b/docs/ecosystems.md index 17291b25..2361843b 100644 --- a/docs/ecosystems.md +++ b/docs/ecosystems.md @@ -15,7 +15,7 @@ The backticked slug in each row is the value `-e`/`--ecosystems` accepts (e.g. | Ecosystem | agent (`--mode agent`) | vendored (`--mode vendored`) | hosted (`--mode hosted`) | |-----------|------------------------|------------------------------|--------------------------| | npm (`npm`) — pnpm / yarn / berry / bun | ✅ any install layout; `setup` postinstall hook | ✅ six lockfile flavors: package-lock, yarn classic, yarn berry (node-modules linker; PnP refused), pnpm v9, pnpm legacy v5.4/v6.0 (`pnpm 7/8` — frozen installs are path-bound because those majors absolutize `file:` override specifiers; moved checkouts run one `pnpm install --offline --no-frozen-lockfile`, surfaced as `vendor_pnpm_legacy_absolute_specifier`), bun `bun.lock` (binary `bun.lockb` refused with a `--save-text-lockfile` pointer). Rush monorepos refused (`vendor_rush_unsupported`) — see [Rush notes](#npm-rush-monorepos) | ✅ package-lock / npm-shrinkwrap, pnpm-lock.yaml and legacy shrinkwrap.yaml (pnpm majors 1–12; block and flow resolutions), yarn classic, yarn berry, bun — pnpm, berry, and bun carry constraints, see [npm hosted-mode notes](#npm-hosted-mode-notes) | -| PyPI (`pypi`) — uv / poetry / pdm / pipenv / pip | ✅ `.pth` startup hook via `setup` | ✅ uv project/script locks, PEP 751 `pylock.toml` / `pylock..toml`, poetry, pdm, pipenv (lock rewired, but pipenv doesn't hash-check file entries — `vendor_integrity_unverified` warning; the committed wheel bytes are the protection), and requirements.txt. Native uv vendoring requires uv ≥ 0.2.35 (the `[[package]]` lock grammar); hosted mode covers native `uv.lock` from uv 0.1.45 (the first release whose `uv lock` writes one) and requirements from uv 0.0.5; see [uv compatibility](testing/uv-compatibility.md). | ✅ requirements.txt including hash continuations, uv project/script locks, and PEP 751 locks. Version/source ambiguity is refused; see [uv compatibility](testing/uv-compatibility.md). **poetry / pdm / pipenv locks are not rewritten** — use vendored | +| PyPI (`pypi`) — uv / poetry / pdm / pipenv / pip | ✅ `.pth` startup hook via `setup` | ✅ uv project/script locks, PEP 751 `pylock.toml` / `pylock..toml`, poetry, pdm, pipenv (lock rewired, but pipenv doesn't hash-check file entries — `vendor_integrity_unverified` warning; the committed wheel bytes are the protection), and requirements.txt. Native uv vendoring requires uv ≥ 0.2.35 (the `[[package]]` lock grammar); hosted mode covers native `uv.lock` from uv 0.1.45 (the first release whose `uv lock` writes one) and requirements from uv 0.0.5; see [uv compatibility](testing/uv-compatibility.md). | ✅ requirements.txt including hash continuations, uv project/script locks, and PEP 751 locks. Version/source ambiguity is refused; see [uv compatibility](testing/uv-compatibility.md). Poetry 1.x and 2.x locks are supported; Poetry 0.x ignores URL sources and is refused. See [Poetry compatibility](testing/poetry-compatibility.md). **pdm / pipenv locks are not rewritten** — use vendored | | Cargo (`cargo`) | ✅ in-place + `.cargo-checksum.json` rewrite (shared registry-cache caveat — see [Cargo: shared registry cache](#cargo-shared-registry-cache)) | ✅ `[patch.crates-io]` path entry | ✅ per-patch sparse registry (`[registries.socket-patch-]` + Cargo.lock source/checksum) | | RubyGems (`gem`) | ✅ Bundler plugin via `setup` — needs bundler ≥ 2.2 (1.x cannot load `plugin ... path:` directives; `setup` refuses below the floor and `setup --check` red-flags a wired 1.x project) | ✅ Gemfile + Gemfile.lock path pair (`Gemfile` spelling only — a `gems.rb` project cannot vendor yet) | ✅ per-dep `source` block — edits `gems.rb` + `gems.locked` when present (bundler prefers them over `Gemfile`; spellings that diverge beyond Socket's own edits fail closed with `redirect_gem_gemfile_spellings_diverge`); the `CHECKSUMS` pin needs bundler ≥ 2.6 (older locks get a `redirect_gem_no_checksums_section` warning); a stale pre-redirect materialization that `bundle install` would reuse instead of refetching is flagged `redirect_gem_stale_install` with a prescriptive remedy (see CLI_CONTRACT.md's "Gem stale-install guard") | | Go (`golang`) | ✅ `go.mod` `replace` → `.socket/go-patches/` — see [Go: directory replaces and go.sum](#go-directory-replaces-and-gosum) | ✅ `replace` → the committed vendor tree | ✅ (free tier) fork-style `replace` → `patch.socket.dev/gopatch/` + committed `go.sum` pin; see [golang-hosted.md](design/golang-hosted.md). Paid tier stays ❌ ([golang-hosted-no-go.md](design/golang-hosted-no-go.md)); `redirect_golang_unsupported` names the vendored remedy | diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md new file mode 100644 index 00000000..fb7fd763 --- /dev/null +++ b/docs/testing/poetry-compatibility.md @@ -0,0 +1,28 @@ +# Poetry patches + +Hosted mode rewrites `poetry.lock` to a URL source. Vendored mode writes a local wheel source. Both retain the package version, dependencies, groups, markers, extras, and the pyproject content hash. No pyproject edits are required. Repeated scans leave the lock unchanged; rollback restores the recorded originals. A forked target, an existing unrelated source, an unsupported format, or a wheel/package mismatch is refused before writing. + +The committed native locks cover Poetry 0.12.17, 1.0.10, 1.1.15, 1.2.2, 1.3.2, 1.4.2, 1.5.1, 1.6.1, 1.7.1, 1.8.5, 2.0.1, 2.1.4, 2.2.1, 2.3.4, and 2.4.3. They cover legacy `metadata.hashes`, `metadata.files` in lock 1.0/1.1, and package `files` in lock 2.0/2.1. + +| Poetry | Vendored | Hosted | Installer integrity | +| --- | --- | --- | --- | +| 0.12 | Supported | Refused: the installer ignores URL sources | Local wheel hashes are not checked by Poetry | +| 1.0 | Supported | Supported with a SHA-256 URL fragment | Hosted hashes are checked by pip; local wheel hashes are not checked | +| 1.1–1.3 | Supported | Supported | Hosted hashes are checked; local wheel hashes are not checked | +| 1.4–1.8 | Supported | Supported | Both modes reject mismatched lock hashes | +| 2.0–2.4 | Supported | Supported | Both modes reject mismatched lock hashes | + +Poetry 1.0 requires a `source.reference` even for archive sources and appends `#egg` unconditionally. Its hosted URL fragment therefore ends with a separator to preserve the SHA-256 parameter. Poetry 1.2 drops URL hashes from `metadata.files`; lock 1.1 hosted rewrites also write `package.files`, while retaining `metadata.files` for Poetry 1.1. + +The vendor warning `pypi_poetry_integrity_unverified` is emitted for lock formats readable by Poetry before 1.4. Upgrade the installer to at least 1.4 for local wheel hash enforcement. These older installers still install the patched bytes; the live backtest verifies the installed files against the patch record's SHA-256 Git blob hashes and separately records their inability to reject a changed lock hash. + +Run the local Rust coverage: + +```sh +cargo test -p socket-patch-core --lib vendor::pypi_poetry +cargo test -p socket-patch-core --test poetry_hosted +``` + +The live installer harness is `tools/pipeline/poetry-patch-backtest.py` in SocketDev/depscan. It uses public PyPI and the real patch API, bootstraps the actual Poetry versions with uv, captures both CLI modes, checks repeat scans and unchanged lockfiles, verifies installed patch bytes, and tests tampered hashes. Its additional shapes cover dev dependencies, selected and excluded optional extras, Python markers, groups, PEP 621, transitive requests dependencies, and CRLF files. The edge inputs are derived from native locks; their content hashes are computed by the matching Poetry library before running the real installer. + +`poetry update` and lock regeneration can replace a patch source with an upstream source. Re-run Socket Patch after changing the dependency resolution. From c02770c6e0f7e0d73c518d9c6cc55a974e13c32b Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 11:26:39 -0400 Subject: [PATCH 02/19] Keep Poetry rollback source and hashes together Preserve the lock when a legacy patch fragment has drifted, so rollback does not restore upstream hashes while retaining a patched source. Assisted-by: Codex:gpt-6-astra --- crates/socket-patch-core/src/vendor/common.rs | 31 ++++++++++++- .../src/vendor/pypi_poetry.rs | 43 ++++++++++++++++++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/crates/socket-patch-core/src/vendor/common.rs b/crates/socket-patch-core/src/vendor/common.rs index 89d303c1..1442735c 100644 --- a/crates/socket-patch-core/src/vendor/common.rs +++ b/crates/socket-patch-core/src/vendor/common.rs @@ -395,6 +395,35 @@ pub(crate) async fn revert_lock_fragment_splice( lock_file: &str, kind: &str, flavor: &str, +) -> RevertOutcome { + revert_lock_fragment_splice_inner( + entry, root, dry_run, lock_file, kind, flavor, false, + ) + .await +} + +pub(crate) async fn revert_lock_fragment_splice_atomic( + entry: &VendorEntry, + root: &Path, + dry_run: bool, + lock_file: &str, + kind: &str, + flavor: &str, +) -> RevertOutcome { + revert_lock_fragment_splice_inner( + entry, root, dry_run, lock_file, kind, flavor, true, + ) + .await +} + +async fn revert_lock_fragment_splice_inner( + entry: &VendorEntry, + root: &Path, + dry_run: bool, + lock_file: &str, + kind: &str, + flavor: &str, + atomic: bool, ) -> RevertOutcome { use tokio::io::AsyncReadExt as _; @@ -465,7 +494,7 @@ pub(crate) async fn revert_lock_fragment_splice( } } - if !dry_run { + if !dry_run && (!atomic || warnings.is_empty()) { // Mode-preserving: the lock is a user-owned file we merely edit, so // the swapped-in inode must keep its permission bits rather than // reset them to umask defaults. diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index ed55b5eb..17a41280 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -8,7 +8,7 @@ use crate::crawlers::python_crawler::canonicalize_pypi_name; use crate::utils::fs::atomic_write_bytes_preserving_mode; use super::common::{ - item_get, lock_units_named, pep621_declared_names, record, revert_lock_fragment_splice, + item_get, lock_units_named, pep621_declared_names, record, revert_lock_fragment_splice_atomic, unit_has_canon_name, }; use super::path::parse_vendor_path; @@ -370,7 +370,8 @@ pub(super) async fn revert_poetry( root: &Path, dry_run: bool, ) -> RevertOutcome { - revert_lock_fragment_splice(entry, root, dry_run, LOCK_FILE, KIND_LOCK_PACKAGE, "poetry").await + revert_lock_fragment_splice_atomic(entry, root, dry_run, LOCK_FILE, KIND_LOCK_PACKAGE, "poetry") + .await } // ── helpers ────────────────────────────────────────────────────────────── @@ -848,6 +849,44 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 .unwrap() } + #[tokio::test] + async fn legacy_revert_keeps_source_and_hash_together_on_drift() { + let native = include_str!("../../tests/fixtures/poetry/1.1.15/poetry.lock"); + let lock = native.replace("urllib3 = []", &format!("urllib3 = [{{file = \"urllib3-1.26.18-py2.py3-none-any.whl\", hash = \"sha256:{}\"}}]", "b".repeat(64))); + for crlf in [false, true] { + let pristine = if crlf { + lock.replace('\n', "\r\n") + } else { + lock.clone() + }; + let tmp = write_project(&pristine, PYPROJECT_DIRECT).await; + let project = load_poetry_project(tmp.path()).await.unwrap(); + let wheel = "urllib3-1.26.18-py2.py3-none-any.whl"; + let path = format!(".socket/vendor/pypi/{UUID}/{wheel}"); + let (wiring, meta) = wire_poetry( + &project, + tmp.path(), + "urllib3", + "1.26.18", + &path, + wheel, + WHEEL_SHA, + UUID, + ) + .await + .unwrap(); + let drifted = read_lock(tmp.path()) + .await + .replace("HTTP library", "Edited description"); + tokio::fs::write(tmp.path().join("poetry.lock"), &drifted) + .await + .unwrap(); + let outcome = revert_poetry(&entry_for(wiring, meta), tmp.path(), false).await; + assert!(!outcome.warnings.is_empty()); + assert_eq!(read_lock(tmp.path()).await, drifted); + } + } + #[tokio::test] async fn legacy_and_crlf_patches_revert_independently() { for version in ["0.12.17", "1.0.10", "1.1.15", "1.2.2", "1.8.5", "2.4.3"] { From 2ac24360bc24a95d31c5d4d7671712a97694b92a Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 12:53:01 -0400 Subject: [PATCH 03/19] Keep Poetry fixtures portable across checkouts Normalize checked-out fixtures before explicitly exercising LF and CRLF, so Windows auto-conversion cannot double carriage returns. Assisted-by: Codex:gpt-6-astra --- crates/socket-patch-core/src/vendor/pypi_poetry.rs | 3 ++- crates/socket-patch-core/tests/poetry_hosted.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index 17a41280..01728102 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -851,7 +851,8 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 #[tokio::test] async fn legacy_revert_keeps_source_and_hash_together_on_drift() { - let native = include_str!("../../tests/fixtures/poetry/1.1.15/poetry.lock"); + let native = + include_str!("../../tests/fixtures/poetry/1.1.15/poetry.lock").replace("\r\n", "\n"); let lock = native.replace("urllib3 = []", &format!("urllib3 = [{{file = \"urllib3-1.26.18-py2.py3-none-any.whl\", hash = \"sha256:{}\"}}]", "b".repeat(64))); for crlf in [false, true] { let pristine = if crlf { diff --git a/crates/socket-patch-core/tests/poetry_hosted.rs b/crates/socket-patch-core/tests/poetry_hosted.rs index c6d32622..265dbd9d 100644 --- a/crates/socket-patch-core/tests/poetry_hosted.rs +++ b/crates/socket-patch-core/tests/poetry_hosted.rs @@ -18,6 +18,7 @@ fn original(version: &str) -> String { env!("CARGO_MANIFEST_DIR") )) .unwrap() + .replace("\r\n", "\n") } fn patch() -> DepOverride { From 02c63ecbddfddf2acfe6a16b2e35982fce89aaf7 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:22:16 -0400 Subject: [PATCH 04/19] fix(poetry): harden the shared lock rewriter and align hosted refusals with uv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Never panic on a user-editable lock: a `[metadata.files]` / `[metadata.hashes]` value that is not a table (array of tables, scalar, `[[metadata]]`) used to hit toml_edit's IndexMut and abort `scan --mode hosted|vendored` with exit 101 and no JSON; every table access is now guarded and refuses with a warning. - Accept any `lock-version = "2."` in the shared rewriter (the vendored loader already accepted newer minors with an advisory), so the same lock no longer succeeds LF-vendored, hard-fails CRLF-vendored and silently no-ops hosted. - Supersede an earlier Socket hosted URL for the same wheel in place (same origin + filename, fragment ignored) instead of refusing it as a foreign source, so a grant-token rotation or republished patch does not strand the pin — the bun / requirements / cargo rewriters make the same call. Foreign sources and vendored file sources are still refused. - Hosted rewriter: gate the missing-SHA-256 warning once per dep (not per lock), warn `redirect_poetry_entry_not_found` when a lock has no entry at the granted version (uv parity), and emit `redirect_poetry_stale_install_risk` when the lock was written by Poetry < 1.4 — measured on real 0.12.17–2.4.3: those releases never replace an already-installed same-version package after the redirect, 1.4+ do. - Write the SHA-256 lowercase (Poetry compares hexdigest strings) and anchor the legacy integrity fragment at its line break so a suffix-named sibling entry with the same value cannot make the splice ambiguous. - Unit tests for the shared rewriter (it had none) and hosted integration tests for the new warnings, the 2.x minor, and token rotation. Co-Authored-By: Claude Fable 5.1 --- .../src/patch/redirect/poetry.rs | 78 ++++- .../src/utils/poetry_lock.rs | 325 ++++++++++++++++-- .../socket-patch-core/tests/poetry_hosted.rs | 87 ++++- 3 files changed, 454 insertions(+), 36 deletions(-) diff --git a/crates/socket-patch-core/src/patch/redirect/poetry.rs b/crates/socket-patch-core/src/patch/redirect/poetry.rs index 35c86aba..96d395d9 100644 --- a/crates/socket-patch-core/src/patch/redirect/poetry.rs +++ b/crates/socket-patch-core/src/patch/redirect/poetry.rs @@ -1,28 +1,61 @@ +//! Hosted (URL-source) redirects for `poetry.lock`, every lock generation +//! Poetry 1.0+ has written. Poetry 0.12 (format `"0"`) ignores URL sources and +//! is refused by the shared rewriter. See `crate::utils::poetry_lock`. + use std::collections::BTreeMap; use serde_json::Value; +use toml_edit::DocumentMut; use super::{DepOverride, FileEdit, RewriteResult, RewriteWarning}; -use crate::utils::poetry_lock::{poetry_lock_edits, rewrite_poetry_lock}; +use crate::utils::poetry_lock::{ + generated_by_version, lock_version, poetry_lock_edits, rewrite_poetry_lock, +}; + +/// Whether the lock was written by a Poetry release older than 1.4. Those +/// installers neither verify hashes for local wheels nor replace an +/// already-installed package at the same version, so a warm virtualenv keeps +/// serving the upstream bytes after the redirect. Formats `0`/`1.0`/`1.1` are +/// only written by such releases; lock `2.0` is written by 1.3 through 1.8, so +/// the `@generated by Poetry X.Y.Z` header (present from 1.4) decides there. +fn pre_1_4_writer(lock_text: &str) -> bool { + let Ok(lock) = lock_text.parse::() else { + return false; + }; + match lock_version(&lock) { + Ok("0" | "1.0" | "1.1") => true, + Ok("2.0") => !matches!(generated_by_version(lock_text), Some(v) if v >= (1, 4)), + _ => false, + } +} pub(super) fn rewrite_poetry( files: &BTreeMap, overrides: &[DepOverride], result: &mut RewriteResult, ) { - for (path, original) in files + let locks: Vec<(&String, &String)> = files .iter() .filter(|(path, _)| path.as_str() == "poetry.lock" || path.ends_with("/poetry.lock")) - { + .collect(); + if locks.is_empty() { + return; + } + // Intake gate ONCE per dep, not once per lock file (uv parity). + let mut usable: Vec<(&DepOverride, &str)> = Vec::new(); + for dep in overrides.iter().filter(|dep| dep.ecosystem == "pypi") { + match dep.integrity.sha256.as_deref() { + Some(sha256) => usable.push((dep, sha256)), + None => result.warnings.push(RewriteWarning { + code: "redirect_poetry_missing_sha256".into(), + detail: format!("{} has no SHA-256 integrity", dep.name), + }), + } + } + for (path, original) in locks { let mut content = original.clone(); - for dep in overrides.iter().filter(|dep| dep.ecosystem == "pypi") { - let Some(sha256) = dep.integrity.sha256.as_deref() else { - result.warnings.push(RewriteWarning { - code: "redirect_poetry_missing_sha256".into(), - detail: format!("{} has no SHA-256 integrity", dep.name), - }); - continue; - }; + let mut stale_warned = false; + for &(dep, sha256) in &usable { let filename = dep.artifact_url.rsplit('/').next().unwrap_or(""); match rewrite_poetry_lock( &content, @@ -50,14 +83,33 @@ pub(super) fn rewrite_poetry( Err(detail) => { result.warnings.push(RewriteWarning { code: "redirect_poetry_lock_unsupported".into(), - detail, + detail: format!("{path}: {detail}"), }); continue; } } content = rewritten; + if !stale_warned && pre_1_4_writer(&content) { + stale_warned = true; + result.warnings.push(RewriteWarning { + code: "redirect_poetry_stale_install_risk".into(), + detail: format!( + "{path} was written by Poetry < 1.4, which does not replace an \ + already-installed package at the same version: an existing \ + virtualenv keeps the upstream {} until it is recreated (or the \ + package is `pip uninstall`ed) before `poetry install`; fresh \ + installs pick up the patched wheel", + dep.name + ), + }); + } } - Ok(_) => {} + // Already redirected to this artifact (idempotent re-scan). + Ok(Some(_)) => {} + Ok(None) => result.warnings.push(RewriteWarning { + code: "redirect_poetry_entry_not_found".into(), + detail: format!("no {path} entry for {}@{}", dep.name, dep.version), + }), Err(detail) => result.warnings.push(RewriteWarning { code: "redirect_poetry_lock_unsupported".into(), detail: format!("{path}: {detail}"), diff --git a/crates/socket-patch-core/src/utils/poetry_lock.rs b/crates/socket-patch-core/src/utils/poetry_lock.rs index b6cedde3..ce21edeb 100644 --- a/crates/socket-patch-core/src/utils/poetry_lock.rs +++ b/crates/socket-patch-core/src/utils/poetry_lock.rs @@ -1,11 +1,37 @@ +//! Shared `poetry.lock` rewriter for hosted (URL source) and vendored (file +//! source) patches across every lock generation Poetry has written: +//! +//! * format `"0"` — Poetry 0.12: no `lock-version`, hashes in `[metadata.hashes]` +//! * `"1.0"` / `"1.1"` — Poetry 1.0–1.2: per-package files in `[metadata.files]` +//! * `"2.x"` — Poetry 1.3+: `files = [...]` inside each `[[package]]` +//! +//! Every edit is computed on a parsed `toml_edit` document and then spliced +//! back into the ORIGINAL text as verbatim fragment replacements, so untouched +//! bytes (formatting, comments, line endings) survive and rollback can replay +//! the recorded fragments. A malformed lock (user-editable input) must never +//! panic: every table access here is guarded and degrades to an `Err`, which +//! callers surface as a refusal warning. + use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table, Value}; use crate::crawlers::python_crawler::canonicalize_pypi_name; +/// The lock generation: `"0"`, `"1.0"`, `"1.1"`, or any `"2."` (Poetry +/// bumps the minor additively — 2.0 → 2.1 kept every shape we rewrite, and the +/// vendored loader already accepts newer minors with an advisory; the hosted +/// path must not refuse what the vendored path accepts). pub fn lock_version(lock: &DocumentMut) -> Result<&str, String> { - let metadata = lock.get("metadata").ok_or("missing Poetry lock metadata")?; + let metadata = lock + .get("metadata") + .filter(|item| item.is_table_like()) + .ok_or("missing Poetry lock metadata")?; match metadata.get("lock-version").and_then(Item::as_str) { - Some(version @ ("1.0" | "1.1" | "2.0" | "2.1")) => Ok(version), + Some(version @ ("1.0" | "1.1")) => Ok(version), + Some(version) if is_2x(version) => Ok(version), + Some(version) => Err(format!( + "unsupported Poetry lock-version {version:?} (supported: legacy metadata.hashes, 1.0, \ + 1.1 and 2.x)" + )), None if metadata .get("hashes") .and_then(Item::as_table_like) @@ -13,10 +39,62 @@ pub fn lock_version(lock: &DocumentMut) -> Result<&str, String> { { Ok("0") } - _ => Err("unsupported Poetry lock version".into()), + None => Err("poetry.lock has neither a [metadata] lock-version nor a [metadata.hashes] table".into()), } } +fn is_2x(version: &str) -> bool { + version + .strip_prefix("2.") + .is_some_and(|minor| !minor.is_empty() && minor.bytes().all(|b| b.is_ascii_digit())) +} + +/// The `# This file is automatically @generated by Poetry X.Y.Z …` header +/// Poetry writes from 1.4 on (1.3 writes the sentence without a version). +/// Advisory only — a lock can be consumed by a different Poetry than the one +/// that wrote it — but it lets warnings about the WRITER's installer be +/// precise instead of blaming every lock-2.0 project for Poetry 1.3. +pub fn generated_by_version(lock_text: &str) -> Option<(u64, u64)> { + let first = lock_text.lines().next()?; + let rest = first.split("@generated by Poetry ").nth(1)?; + let version = rest.split_whitespace().next()?; + let mut parts = version.split('.'); + let major = parts.next()?.parse().ok()?; + let minor = parts.next()?.parse().ok()?; + Some((major, minor)) +} + +/// Whether `existing` is an earlier hosted redirect of the SAME artifact: +/// same origin (`scheme://host[:port]`) and same trailing filename as the +/// current artifact URL, fragments ignored. Grant tokens and patch uuids live +/// in the path between them, so a rotated token or a republished patch is +/// superseded in place instead of stranding the pin on a URL that no longer +/// serves (the bun / requirements / cargo rewriters make the same call). +fn is_prior_hosted_url(existing: &str, current: &str) -> bool { + fn origin_and_leaf(url: &str) -> Option<(&str, &str)> { + if !url.starts_with("https://") && !url.starts_with("http://") { + return None; + } + let url = url.split('#').next()?; + let scheme_end = url.find("://")? + 3; + let path_start = url[scheme_end..].find('/')? + scheme_end; + let leaf = url[path_start..] + .rsplit('/') + .next() + .filter(|leaf| !leaf.is_empty())?; + Some((&url[..path_start], leaf)) + } + match (origin_and_leaf(existing), origin_and_leaf(current)) { + (Some(old), Some(new)) => old == new, + _ => false, + } +} + +/// Rewrite the `[[package]]` for `name`@`version` to install the wheel at +/// `source_url` (`source_type` `"url"` for hosted, `"file"` for vendored), +/// pinning `sha256`. Returns `Ok(None)` when the lock has no such entry (or +/// resolves another version) — the caller decides whether that is a warning. +/// Returns `Err` for inputs the rewriter must refuse without writing. pub fn rewrite_poetry_lock( text: &str, name: &str, @@ -32,12 +110,16 @@ pub fn rewrite_poetry_lock( { return Err("invalid Poetry artifact source or SHA-256".into()); } + // Poetry compares the lock's `sha256:` against `hashlib`'s lowercase + // hexdigest as strings, so an uppercase digest would fail every install. + let sha256 = sha256.to_ascii_lowercase(); + if filename.contains(['/', '\\']) || !filename.ends_with(".whl") { + return Err("Poetry patch wheel does not match the locked package".into()); + } let parts: Vec<_> = filename.split('-').collect(); - if !filename.ends_with(".whl") - || !matches!(parts.len(), 5 | 6) + if !matches!(parts.len(), 5 | 6) || canonicalize_pypi_name(parts[0]) != canonicalize_pypi_name(name) || parts[1] != version - || filename.contains(['/', '\\']) { return Err("Poetry patch wheel does not match the locked package".into()); } @@ -49,7 +131,10 @@ pub fn rewrite_poetry_lock( return Err("Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0".into()); } let effective_url = if format == "1.0" && source_type == "url" { - // Poetry 1.0 appends #egg without checking for an existing fragment. + // Poetry 1.0 hands pip `#egg=` unconditionally; the trailing + // `&` keeps `sha256=` a complete fragment parameter when `#egg=` + // is appended (pip >= 22 would otherwise read `#egg=` as the + // digest and hard-fail the install). format!("{source_url}#sha256={sha256}&") } else { source_url.to_string() @@ -89,10 +174,18 @@ pub fn rewrite_poetry_lock( .unwrap_or(name) .to_string(); if let Some(source) = package.get("source") { - if source.get("type").and_then(Item::as_str) != Some(source_type) - || source.get("url").and_then(Item::as_str) != Some(effective_url.as_str()) - { - return Err("refusing to replace an existing Poetry source".into()); + let existing_type = source.get("type").and_then(Item::as_str); + let existing_url = source.get("url").and_then(Item::as_str).unwrap_or(""); + let same_target = existing_type == Some(source_type) && existing_url == effective_url; + let prior_hosted = source_type == "url" + && existing_type == Some("url") + && is_prior_hosted_url(existing_url, &effective_url); + if !same_target && !prior_hosted { + return Err(format!( + "refusing to replace an existing Poetry source ({} {}) for {package_name}", + existing_type.unwrap_or("unknown"), + existing_url + )); } } let mut entry = InlineTable::new(); @@ -104,20 +197,36 @@ pub fn rewrite_poetry_lock( source.insert("type", value(source_type)); source.insert("url", value(effective_url)); if matches!(format.as_str(), "0" | "1.0") { + // Poetry 0.12 / 1.0 read `source.reference` unconditionally (KeyError + // without it), even for archive sources. source.insert("reference", value("")); } package.insert("source", Item::Table(source)); if format == "1.1" && source_type == "url" { + // Poetry 1.2 (a lock-1.1 writer) verifies url sources against the + // package's own `files`, Poetry 1.1 against `metadata.files` — write + // both so either installer enforces the patched hash. package.insert("files", value(files.clone())); } if format.starts_with('2') { package.insert("files", value(files)); - } else if format == "0" { - let mut hashes = Array::new(); - hashes.push(sha256); - lock["metadata"]["hashes"][&package_name] = value(hashes); } else { - lock["metadata"]["files"][&package_name] = value(files); + let field = if format == "0" { "hashes" } else { "files" }; + let table = lock + .get_mut("metadata") + .and_then(Item::as_table_like_mut) + .ok_or("missing Poetry lock metadata")? + .get_mut(field) + .ok_or_else(|| format!("missing Poetry integrity table [metadata.{field}]"))? + .as_table_like_mut() + .ok_or_else(|| format!("[metadata.{field}] is not a table"))?; + if format == "0" { + let mut hashes = Array::new(); + hashes.push(sha256.as_str()); + table.insert(&package_name, value(hashes)); + } else { + table.insert(&package_name, value(files)); + } } let mut rewritten = lock.to_string(); if text.contains("\r\n") { @@ -131,6 +240,12 @@ pub fn rewrite_poetry_lock( Ok(Some(result)) } +/// The verbatim `(original, replacement)` fragments that turn `original` into +/// `rewritten` for `name`: the package's `[[package]]` unit (with its +/// sub-tables) and, for legacy formats, its `[metadata.files]` / +/// `[metadata.hashes]` entry. Each fragment must occur exactly once on both +/// sides so a textual splice — and its rollback — can never hit the wrong +/// place. pub fn poetry_lock_edits( original: &str, rewritten: &str, @@ -173,7 +288,10 @@ pub fn poetry_lock_edits( .find(['\r', '\n']) .unwrap_or(text.len() - span.end); let mut result = vec![text[span].to_string()]; - let metadata = lock.get("metadata").ok_or("missing Poetry metadata")?; + let metadata = lock + .get("metadata") + .filter(|item| item.is_table_like()) + .ok_or("missing Poetry metadata")?; let format = metadata .get("lock-version") .and_then(Item::as_str) @@ -183,13 +301,20 @@ pub fn poetry_lock_edits( let table = metadata .get(field) .and_then(Item::as_table) - .ok_or("missing Poetry integrity table")?; - let package_name = package["name"].as_str().ok_or("missing package name")?; - let start = table + .ok_or_else(|| format!("missing Poetry integrity table [metadata.{field}]"))?; + let package_name = package + .get("name") + .and_then(Item::as_str) + .ok_or("missing package name")?; + let key_start = table .key(package_name) .and_then(|key| key.span()) .ok_or("missing Poetry integrity key")? .start; + // Anchor the fragment at the preceding line break so a + // suffix-named sibling entry (`pyurllib3 = […]` vs `urllib3 = […]`) + // holding the same value can never contain it. + let start = text[..key_start].rfind('\n').unwrap_or(key_start); let end = table .get(package_name) .and_then(Item::span) @@ -213,3 +338,163 @@ pub fn poetry_lock_edits( } Ok(edits) } + +#[cfg(test)] +mod tests { + use super::*; + + const WHEEL: &str = "urllib3-1.26.18-py2.py3-none-any.whl"; + const URL: &str = "https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl"; + + fn fixture(version: &str) -> String { + std::fs::read_to_string(format!( + "{}/tests/fixtures/poetry/{version}/poetry.lock", + env!("CARGO_MANIFEST_DIR") + )) + .unwrap() + .replace("\r\n", "\n") + } + + fn sha() -> String { + "a".repeat(64) + } + + fn hosted(text: &str) -> Result, String> { + rewrite_poetry_lock(text, "urllib3", "1.26.18", "url", URL, WHEEL, &sha()) + } + + /// A user-editable lock with a malformed integrity table must be refused, + /// never panic (it used to `IndexMut` straight into `metadata.files`). + #[test] + fn malformed_integrity_tables_are_refused_without_panicking() { + let lock = fixture("1.2.2"); + let array_of_tables = lock.replace("[metadata.files]", "[[metadata.files]]"); + let scalar = { + let start = lock.find("[metadata.files]").unwrap(); + format!("{}files = \"oops\"\n", &lock[..start]) + }; + let missing = { + let start = lock.find("\n[metadata.files]").unwrap(); + lock[..start + 1].to_string() + }; + let metadata_array = lock.replace("[metadata]", "[[metadata]]"); + for (label, text) in [ + ("array-of-tables", array_of_tables), + ("scalar", scalar), + ("missing", missing), + ("metadata-array", metadata_array), + ] { + match hosted(&text) { + Err(err) => assert!(!err.is_empty(), "{label}"), + Ok(other) => panic!("{label}: expected a refusal, got {other:?}"), + } + // The vendored (file-source) spelling takes the same guarded path. + match rewrite_poetry_lock(&text, "urllib3", "1.26.18", "file", ".socket/vendor/pypi/x/urllib3-1.26.18-py2.py3-none-any.whl", WHEEL, &sha()) { + Err(err) => assert!(!err.is_empty(), "{label}"), + Ok(other) => panic!("{label}: expected a refusal, got {other:?}"), + } + } + } + + /// Poetry bumps the 2.x minor additively; the vendored loader accepts a + /// newer minor with an advisory, so the shared rewriter must too — the + /// same lock used to be applied (LF vendored), hard-failed (CRLF vendored) + /// and silently skipped (hosted) depending only on the path taken. + #[test] + fn newer_2x_minor_is_rewritten_like_2_1() { + let lock = fixture("2.4.3").replace("lock-version = \"2.1\"", "lock-version = \"2.2\""); + let rewritten = hosted(&lock).unwrap().unwrap(); + assert!(rewritten.contains(URL)); + assert!(rewritten.contains("lock-version = \"2.2\"")); + for bad in ["3.0", "2", "2.x", "1.2"] { + let lock = fixture("2.4.3").replace("lock-version = \"2.1\"", &format!("lock-version = \"{bad}\"")); + let err = hosted(&lock).unwrap_err(); + assert!(err.contains(bad), "{bad}: {err}"); + } + } + + /// An earlier hosted redirect of the same wheel (rotated grant token, + /// republished patch) is superseded in place; a foreign url source is not. + #[test] + fn prior_hosted_url_is_superseded_but_foreign_sources_are_refused() { + let lock = fixture("2.4.3"); + let first = hosted(&lock).unwrap().unwrap(); + let rotated = URL.replace("7e52b8b6", "00000000"); + let second = + rewrite_poetry_lock(&first, "urllib3", "1.26.18", "url", &rotated, WHEEL, &sha()) + .unwrap() + .unwrap(); + assert!(second.contains(&rotated) && !second.contains(URL)); + // Idempotent: the same URL again changes nothing. + assert_eq!(hosted(&first).unwrap().unwrap(), first); + // Poetry 1.0 carries a `#sha256=…&` fragment; the comparison ignores it. + let lock10 = fixture("1.0.10"); + let first10 = hosted(&lock10).unwrap().unwrap(); + let second10 = rewrite_poetry_lock(&first10, "urllib3", "1.26.18", "url", &rotated, WHEEL, &"b".repeat(64)) + .unwrap() + .unwrap(); + assert!(second10.contains(&format!("{rotated}#sha256={}&", "b".repeat(64)))); + // A user's own url source on another origin stays untouched. + let foreign = first.replace("https://patch.socket.dev", "https://mirror.example"); + assert!(hosted(&foreign).unwrap_err().contains("existing Poetry source")); + // A vendored file source is never taken over by the hosted path here. + let vendored = rewrite_poetry_lock(&lock, "urllib3", "1.26.18", "file", ".socket/vendor/pypi/x/urllib3-1.26.18-py2.py3-none-any.whl", WHEEL, &sha()) + .unwrap() + .unwrap(); + assert!(hosted(&vendored).unwrap_err().contains("existing Poetry source")); + } + + #[test] + fn sha256_is_written_lowercase() { + let lock = fixture("2.4.3"); + let upper = "A".repeat(64); + let rewritten = + rewrite_poetry_lock(&lock, "urllib3", "1.26.18", "url", URL, WHEEL, &upper) + .unwrap() + .unwrap(); + assert!(rewritten.contains(&format!("sha256:{}", "a".repeat(64)))); + assert!(!rewritten.contains(&upper)); + } + + /// The `[metadata.files]` fragment is anchored at its line break, so a + /// sibling whose key ends in the same characters and holds the same value + /// cannot make the splice ambiguous. + #[test] + fn suffix_named_sibling_with_identical_integrity_does_not_refuse() { + let lock = fixture("1.2.2"); + let files_entry = { + let start = lock.find("urllib3 = [\n").unwrap(); + let end = lock[start..].find("\n]\n").unwrap() + start + 3; + lock[start..end].to_string() + }; + let sibling = files_entry.replacen("urllib3 = [", "pyurllib3 = [", 1); + let lock = format!("{lock}{sibling}"); + let rewritten = hosted(&lock).unwrap().unwrap(); + assert!(rewritten.contains(URL)); + assert!(rewritten.contains(&sibling), "sibling entry must survive verbatim"); + let edits = poetry_lock_edits(&lock, &rewritten, "urllib3").unwrap(); + assert_eq!(edits.len(), 2); + assert!(edits[1].0.starts_with('\n')); + } + + #[test] + fn absent_or_other_version_yields_none_not_error() { + let lock = fixture("2.4.3"); + assert_eq!( + rewrite_poetry_lock(&lock, "six", "1.16.0", "url", &URL.replace("urllib3", "six").replace("1.26.18", "1.16.0"), "six-1.16.0-py2.py3-none-any.whl", &sha()).unwrap(), + None + ); + assert_eq!( + rewrite_poetry_lock(&lock, "urllib3", "1.26.17", "url", &URL.replace("1.26.18", "1.26.17"), "urllib3-1.26.17-py2.py3-none-any.whl", &sha()).unwrap(), + None + ); + } + + #[test] + fn generated_by_header_is_parsed_when_present() { + assert_eq!(generated_by_version(&fixture("1.8.5")), Some((1, 8))); + assert_eq!(generated_by_version(&fixture("2.4.3")), Some((2, 4))); + assert_eq!(generated_by_version(&fixture("1.3.2")), None); + assert_eq!(generated_by_version(&fixture("1.2.2")), None); + } +} diff --git a/crates/socket-patch-core/tests/poetry_hosted.rs b/crates/socket-patch-core/tests/poetry_hosted.rs index 265dbd9d..0cf77aa4 100644 --- a/crates/socket-patch-core/tests/poetry_hosted.rs +++ b/crates/socket-patch-core/tests/poetry_hosted.rs @@ -59,8 +59,13 @@ async fn native_lock_generations_redirect_idempotently_and_restore_every_byte() .any(|warning| warning.detail.contains("ignores URL sources"))); continue; } - assert!( - result.warnings.is_empty(), + // Poetry < 1.4 writers (0/1.0/1.1 locks, and 1.3's unstamped 2.0 lock) + // get the warm-virtualenv advisory; nothing else may warn. + let pre_1_4 = matches!(*version, "1.0.10" | "1.1.15" | "1.2.2" | "1.3.2"); + let codes: Vec<&str> = result.warnings.iter().map(|w| w.code.as_str()).collect(); + assert_eq!( + codes, + if pre_1_4 { vec!["redirect_poetry_stale_install_risk"] } else { vec![] }, "{version}: {:?}", result.warnings ); @@ -240,7 +245,14 @@ async fn either_patch_reverts_independently_with_unrelated_edits() { second.warnings, first.files["poetry.lock"] ); - assert!(second.warnings.is_empty(), "{:?}", second.warnings); + assert!( + second + .warnings + .iter() + .all(|w| w.code == "redirect_poetry_stale_install_risk"), + "{:?}", + second.warnings + ); let directory = tempfile::tempdir().unwrap(); let unrelated = if crlf { "# retained user edit\r\n" @@ -282,3 +294,72 @@ async fn either_patch_reverts_independently_with_unrelated_edits() { } } } + +#[test] +fn absent_entries_warn_once_and_missing_sha256_is_gated_once_per_dep() { + let files = BTreeMap::from([ + ("poetry.lock".to_string(), original("2.4.3")), + ("packages/app/poetry.lock".to_string(), original("1.8.5")), + ]); + let mut six = patch(); + six.name = "six".into(); + six.version = "1.16.0".into(); + six.artifact_url = URL.replace("urllib3", "six").replace("1.26.18", "1.16.0"); + let result = rewrite_registry_redirect(&files, &[six]); + assert!(result.files.is_empty()); + let codes: Vec<&str> = result.warnings.iter().map(|w| w.code.as_str()).collect(); + assert_eq!( + codes, + vec!["redirect_poetry_entry_not_found", "redirect_poetry_entry_not_found"] + ); + let mut missing_hash = patch(); + missing_hash.integrity.sha256 = None; + let result = rewrite_registry_redirect(&files, &[missing_hash]); + assert!(result.files.is_empty()); + let codes: Vec<&str> = result.warnings.iter().map(|w| w.code.as_str()).collect(); + assert_eq!(codes, vec!["redirect_poetry_missing_sha256"], "gated once, not once per lock"); +} + +/// A future Poetry that bumps the lock minor (2.2) is rewritten like 2.1 in +/// hosted mode — the vendored loader already accepts it with an advisory, and +/// the same lock must not be a silent no-op on one path and applied on another. +#[tokio::test] +async fn newer_2x_minor_redirects_and_reverts() { + let lock = original("2.4.3").replace("lock-version = \"2.1\"", "lock-version = \"2.2\""); + let files = BTreeMap::from([("poetry.lock".to_string(), lock.clone())]); + let result = rewrite_registry_redirect(&files, &[patch()]); + assert!(result.warnings.is_empty(), "{:?}", result.warnings); + assert!(result.files["poetry.lock"].contains(URL)); + let directory = tempfile::tempdir().unwrap(); + tokio::fs::write(directory.path().join("poetry.lock"), &result.files["poetry.lock"]) + .await + .unwrap(); + let mut state = RedirectState { + edits: result.edits, + ..RedirectState::default() + }; + let outcome = revert_remaining_redirect_edits(directory.path(), &mut state, false).await; + assert!(outcome.fully_reverted(), "{:?}", outcome.refusals); + assert_eq!( + tokio::fs::read_to_string(directory.path().join("poetry.lock")).await.unwrap(), + lock + ); +} + +/// A rotated grant token (or republished patch) supersedes the earlier hosted +/// URL in place; rollback of the SECOND run restores the FIRST run's fragment, +/// exactly as the ledger records it. +#[test] +fn rotated_grant_token_supersedes_the_prior_hosted_url() { + let files = BTreeMap::from([("poetry.lock".to_string(), original("1.8.5"))]); + let first = rewrite_registry_redirect(&files, &[patch()]); + let mut rotated = patch(); + rotated.token = "00000000-0000-4000-8000-000000000000".into(); + rotated.artifact_url = URL.replace("7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e", "00000000-0000-4000-8000-000000000000"); + let second = rewrite_registry_redirect(&first.files, &[rotated.clone()]); + assert!(second.warnings.is_empty(), "{:?}", second.warnings); + let lock = &second.files["poetry.lock"]; + assert!(lock.contains(&rotated.artifact_url) && !lock.contains(URL)); + assert_eq!(second.edits.len(), 1); + assert!(second.edits[0].original.as_ref().unwrap().as_str().unwrap().contains(URL)); +} From 66680d8ae9d0ede5dd5744098311cd0eff8e5634 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:22:16 -0400 Subject: [PATCH 05/19] fix(poetry): key the vendored pre-1.4 advisory on the lock's writer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pypi_poetry_integrity_unverified` fired for every lock-version 2.0 project, telling Poetry 1.4–1.8 users their installer verifies nothing. Lock 2.0 is written by 1.3 through 1.8; releases from 1.4 stamp `@generated by Poetry X.Y.Z`, so a stamped 2.0 lock is no longer flagged. The advisory now also names the second pre-1.4 behaviour measured on real releases: an already-installed same-version package is not replaced after the lock is rewired. Co-Authored-By: Claude Fable 5.1 --- .../src/vendor/pypi_poetry.rs | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index 01728102..34d9ec6b 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -125,10 +125,29 @@ pub(super) async fn load_poetry_project( )) } } - if matches!(lock_version.as_str(), "0" | "1.0" | "1.1" | "2.0") { + // Poetry < 1.4 neither verifies local wheel hashes nor replaces an + // already-installed package at the same version (a warm virtualenv keeps + // the upstream bytes after the lock is rewired). Formats 0/1.0/1.1 are + // only written by those releases; lock 2.0 is written by 1.3 through 1.8, + // so the `@generated by Poetry X.Y.Z` header (present from 1.4) decides. + let pre_1_4_writer = match lock_version.as_str() { + "0" | "1.0" | "1.1" => true, + "2.0" => !matches!( + crate::utils::poetry_lock::generated_by_version(&lock_text), + Some(v) if v >= (1, 4) + ), + _ => false, + }; + if pre_1_4_writer { warnings.push(VendorWarning::new( "pypi_poetry_integrity_unverified", - "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes".to_string(), + format!( + "{LOCK_FILE} was written by Poetry < 1.4: that installer does not verify local \ + wheel hashes (the committed wheel bytes are the protection — review them) and \ + does not replace an already-installed package at the same version — upgrade to \ + Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) \ + before `poetry install`" + ), )); } @@ -849,6 +868,38 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 .unwrap() } + /// The pre-1.4 advisory follows the WRITER: every 0/1.0/1.1 lock, and a + /// 2.0 lock without a `@generated by Poetry X.Y.Z` header (1.3 wrote + /// those); 1.4–1.8 also write 2.0 but stamp their version, and verify + /// hashes / reinstall over a warm venv, so they must not be blamed. + #[tokio::test] + async fn integrity_advisory_tracks_pre_1_4_writers_not_the_bare_format() { + for (version, expect) in [ + ("0.12.17", true), + ("1.0.10", true), + ("1.1.15", true), + ("1.2.2", true), + ("1.3.2", true), + ("1.4.2", false), + ("1.8.5", false), + ("2.0.1", false), + ("2.4.3", false), + ] { + let native = std::fs::read_to_string(format!( + "{}/tests/fixtures/poetry/{version}/poetry.lock", + env!("CARGO_MANIFEST_DIR") + )) + .unwrap(); + let tmp = write_project(&native, PYPROJECT_DIRECT).await; + let project = load_poetry_project(tmp.path()).await.unwrap(); + let fired = project + .warnings + .iter() + .any(|w| w.code == "pypi_poetry_integrity_unverified"); + assert_eq!(fired, expect, "{version}: {:?}", project.warnings); + } + } + #[tokio::test] async fn legacy_revert_keeps_source_and_hash_together_on_drift() { let native = @@ -1009,7 +1060,7 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 for (lock_version, before, after, pyproject, dep_class) in cases { let tmp = write_project(before, pyproject).await; let p = load_poetry_project(tmp.path()).await.unwrap(); - assert_eq!(p.warnings.len(), usize::from(lock_version == "2.0")); + assert!(p.warnings.is_empty(), "{lock_version}: {:?}", p.warnings); assert_eq!(p.lock_version, lock_version); assert_eq!(classify_dependency(&p, "six"), dep_class); assert_eq!( From 98a3253c36c4f59e6e40aa671765444b056badea Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:22:16 -0400 Subject: [PATCH 06/19] test(poetry): add the per-release live matrix harness and its results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/backtest-poetry.py mirrors backtest-uv.py: it bootstraps every Poetry release (0.12.17 … 2.4.3) with uv, generates a native lock for a one-dependency project with a public free-tier patch, and drives the real CLI through hosted, vendored, agent and out-of-tree-venv agent mode plus `setup`, checking applied counts, idempotent re-scans, lock-driven installs into an emptied virtualenv, fresh-clone installs, `poetry check --lock`, `vex`, tampered-hash rejection, warm-virtualenv reinstall, Poetry's own relock, and `rollback` restoring every byte. 108 cases pass on the PR head; the results file feeds the docs table. Co-Authored-By: Claude Fable 5.1 --- .../testing/poetry-compatibility/results.json | 11184 ++++++++++++++++ scripts/backtest-poetry.py | 731 + 2 files changed, 11915 insertions(+) create mode 100644 docs/testing/poetry-compatibility/results.json create mode 100755 scripts/backtest-poetry.py diff --git a/docs/testing/poetry-compatibility/results.json b/docs/testing/poetry-compatibility/results.json new file mode 100644 index 00000000..aaee0a18 --- /dev/null +++ b/docs/testing/poetry-compatibility/results.json @@ -0,0 +1,11184 @@ +{ + "errors": [], + "provenance": { + "capturedAt": "2026-09-17T17:42:39.168405+00:00", + "cliRevision": "2ac2436", + "cliSha256": "ce223a4e26e9536d8aa87c8044e437def508245d37ebefc79372b695923eb3dc", + "host": "Darwin arm64", + "modes": [ + "hosted", + "vendored", + "agent", + "agent-oot", + "setup" + ], + "note": "Merged from three harness runs on the same CLI build (full matrix; legacy-version rerun after a harness timeout bug; warm-install pass).", + "poetryVersions": [ + "0.12.17", + "1.0.10", + "1.1.15", + "1.2.2", + "1.3.2", + "1.4.2", + "1.5.1", + "1.6.1", + "1.7.1", + "1.8.5", + "2.0.1", + "2.1.4", + "2.2.1", + "2.3.4", + "2.4.3" + ], + "shapes": [ + "direct", + "populated", + "crlf", + "pep621" + ] + }, + "results": [ + { + "checks": { + "lockUnchanged": true, + "noLedger": true, + "pyprojectUnchanged": true, + "refusedWithWarning": true + }, + "expected": "refused: Poetry 0.x ignores URL sources", + "info": { + "applied": 0, + "refusedWithWarning": [ + { + "code": "redirect_poetry_lock_unsupported", + "detail": "poetry.lock: Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0" + } + ], + "scanExit": 0, + "warnings": [ + { + "code": "redirect_poetry_lock_unsupported", + "detail": "poetry.lock: Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0" + } + ] + }, + "mode": "hosted", + "passed": true, + "poetry": "0.12.17", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n - Installing poetry-patch-fixture (0.1.0)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n - Installing poetry-patch-fixture (0.1.0)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "0.12.17", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "0.12.17", + "shape": "direct" + }, + { + "checks": { + "lockUnchanged": true, + "noLedger": true, + "pyprojectUnchanged": true, + "refusedWithWarning": true + }, + "expected": "refused: Poetry 0.x ignores URL sources", + "info": { + "applied": 0, + "refusedWithWarning": [ + { + "code": "redirect_poetry_lock_unsupported", + "detail": "poetry.lock: Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0" + } + ], + "scanExit": 0, + "warnings": [ + { + "code": "redirect_poetry_lock_unsupported", + "detail": "poetry.lock: Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0" + } + ] + }, + "mode": "hosted", + "passed": true, + "poetry": "0.12.17", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n - Installing poetry-patch-fixture (0.1.0)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n - Installing poetry-patch-fixture (0.1.0)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "0.12.17", + "shape": "direct" + }, + { + "checks": { + "lockUnchanged": true, + "noLedger": true, + "pyprojectUnchanged": true, + "refusedWithWarning": true + }, + "expected": "refused: Poetry 0.x ignores URL sources", + "info": { + "applied": 0, + "refusedWithWarning": [ + { + "code": "redirect_poetry_lock_unsupported", + "detail": "poetry.lock: Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0" + } + ], + "scanExit": 0, + "warnings": [ + { + "code": "redirect_poetry_lock_unsupported", + "detail": "poetry.lock: Poetry 0.x ignores URL sources; hosted patches require Poetry >= 1.0" + } + ] + }, + "mode": "hosted", + "passed": true, + "poetry": "0.12.17", + "shape": "populated" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n - Installing poetry-patch-fixture (0.1.0)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n - Installing poetry-patch-fixture (0.1.0)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "0.12.17", + "shape": "populated" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl#sha256=ccc9a9e0b18a5efc7038c504cfc580e47d2e02e5390f2e29cad833cbccb956b6&)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl#sha256=ccc9a9e0b18a5efc7038c504cfc580e47d2e02e5390f2e29cad833cbccb956b6&)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.0.10", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.0.10", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.0.10", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-rerun/captures/1.0.10-direct-agent-oot/venvs/poetry-patch-fixture-hXmFHJiT-py3.8", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.0.10", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl#sha256=ccc9a9e0b18a5efc7038c504cfc580e47d2e02e5390f2e29cad833cbccb956b6&)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl#sha256=ccc9a9e0b18a5efc7038c504cfc580e47d2e02e5390f2e29cad833cbccb956b6&)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.0.10", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.0.10", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl#sha256=ccc9a9e0b18a5efc7038c504cfc580e47d2e02e5390f2e29cad833cbccb956b6&)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl#sha256=ccc9a9e0b18a5efc7038c504cfc580e47d2e02e5390f2e29cad833cbccb956b6&)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.0.10", + "shape": "populated" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": false, + "pyprojectUnchanged": true, + "tail": "Updating dependencies\nResolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.0.10", + "shape": "populated" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.1.15", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.1.15", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.1.15", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-rerun/captures/1.1.15-direct-agent-oot/venvs/poetry-patch-fixture-3wcEJDxH-py3.8", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.1.15", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.1.15", + "shape": "direct" + }, + { + "checks": {}, + "expected": "informational: setup edits pyproject; poetry must resolve socket-patch[hook]", + "info": { + "lockChanged": true, + "poetryLockAfterSetup": { + "exit": 0, + "tail": "Creating virtualenv poetry-patch-fixture in /matrix-rerun/captures/1.1.15-direct-setup/project/.venv\nResolving dependencies...\n" + }, + "pyprojectChanged": true, + "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", + "setupCheckExit": 0, + "setupEnvelope": { + "alreadyConfigured": 0, + "errors": 0, + "files": [ + { + "error": null, + "kind": "pth", + "path": "/matrix-rerun/captures/1.1.15-direct-setup/project/pyproject.toml", + "status": "updated" + } + ], + "packageManager": "npm", + "pythonPackageManager": "poetry", + "status": "success", + "updated": 1 + }, + "setupExit": 0 + }, + "mode": "setup", + "passed": true, + "poetry": "1.1.15", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.1.15", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n\nWriting lock file\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.1.15", + "shape": "populated" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-populated-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": null + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-populated-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.1.15", + "shape": "populated" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n\nWriting lock file\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.2.2", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "-mikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.2.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": ": 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.2.2", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.2.2", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.2.2-direct-agent-oot/venvs/poetry-patch-fixture-XGPMXTkb-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.2.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": false, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n\nWriting lock file\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.2.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "ikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.2.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.2.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.3.2", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "-mikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.3.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": ": 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.3.2", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.3.2", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.3.2-direct-agent-oot/venvs/poetry-patch-fixture-jcmV2dHD-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.3.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.3.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "ikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.3.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "tamperBehaviorAsDocumented": { + "expectsReject": false, + "installExit": 0, + "installedPatchedAnyway": true + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.3.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": " 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.4.2", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "jects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.4.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "ates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.4.2", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.4.2", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.4.2-direct-agent-oot/venvs/poetry-patch-fixture-4MHp-XhW-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.4.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": " 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.4.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "cts-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.4.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "es, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.4.2", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.5.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.5.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.5.1", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.5.1-direct-agent-oot/venvs/poetry-patch-fixture-SaNI20UL-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.5.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.5.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "lock --check", + "exit": 0, + "tail": "poetry.lock is consistent with pyproject.toml.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.5.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.6.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.6.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.6.1", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.6.1-direct-agent-oot/venvs/poetry-patch-fixture-ZKoUeQwE-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.6.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.6.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.6.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.7.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.7.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.7.1", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.7.1-direct-agent-oot/venvs/poetry-patch-fixture-gylI0DbJ-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.7.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.7.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.7.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.8.5", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.8.5", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "1.8.5", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/1.8.5-direct-agent-oot/venvs/poetry-patch-fixture-gX0pmtjt-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "1.8.5", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "1.8.5", + "shape": "direct" + }, + { + "checks": {}, + "expected": "informational: setup edits pyproject; poetry must resolve socket-patch[hook]", + "info": { + "lockChanged": true, + "poetryLockAfterSetup": { + "exit": 0, + "tail": "Resolving dependencies...\n\nWriting lock file\nCreating virtualenv poetry-patch-fixture in /matrix-full/captures/1.8.5-direct-setup/project/.venv\nThe lock file might not be compatible with the current version of Poetry.\nUpgrade Poetry to ensure the lock file is read properly or, alternatively, regenerate the lock file with the `poetry lock` command.\n" + }, + "pyprojectChanged": true, + "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", + "setupCheckExit": 0, + "setupEnvelope": { + "alreadyConfigured": 0, + "errors": 0, + "files": [ + { + "error": null, + "kind": "pth", + "path": "/matrix-full/captures/1.8.5-direct-setup/project/pyproject.toml", + "status": "updated" + } + ], + "packageManager": "npm", + "pythonPackageManager": "poetry", + "status": "success", + "updated": 1 + }, + "setupExit": 0 + }, + "mode": "setup", + "passed": true, + "poetry": "1.8.5", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock --no-update -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "pypi_poetry_integrity_unverified", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "1.8.5", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.0.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.0.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "2.0.1", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/2.0.1-direct-agent-oot/venvs/poetry-patch-fixture-f-Vekhwz-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "2.0.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.0.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.0.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.0.1", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.0.1", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.1.4", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.1.4", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "2.1.4", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/2.1.4-direct-agent-oot/venvs/poetry-patch-fixture-9t5jsywg-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "2.1.4", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.1.4", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.1.4", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.1.4", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.1.4", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.2.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.2.1", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "2.2.1", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/2.2.1-direct-agent-oot/venvs/poetry-patch-fixture-SrpgH9Jy-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "2.2.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.2.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.2.1", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.2.1", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.2.1", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.3.4", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.3.4", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "2.3.4", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/2.3.4-direct-agent-oot/venvs/poetry-patch-fixture-i2qKgRB8-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "2.3.4", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.3.4", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.3.4", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.3.4", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.3.4", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.4.3", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "crlfPreserved": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.4.3", + "shape": "crlf" + }, + { + "checks": { + "appliedExactlyOne": true, + "installedBytesPatched": true, + "lockUnchanged": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "rollbackRestoresUpstreamBytes": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 1, + "status": "success", + "vendoredReverted": [] + }, + "rollbackRestoresUpstreamBytes": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + }, + "scanExit": 0, + "survivesRepeatInstall": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "warnings": [] + }, + "mode": "agent", + "passed": true, + "poetry": "2.4.3", + "shape": "direct" + }, + { + "checks": { + "bareScanSeesPoetryVenv": false, + "patchedViaPoetryRun": true, + "poetryRunScanApplied": true, + "rollbackClearsManifest": true, + "rollbackRestoresUpstream": true, + "survivesRepeatInstall": true, + "survivesSync": true + }, + "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", + "info": { + "bareScan": { + "exit": 0, + "packageDirs": [], + "packagesWithPatches": 1, + "paths": [], + "scannedPackages": 57, + "urllib3Found": true + }, + "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", + "ootVenv": "/matrix-full/captures/2.4.3-direct-agent-oot/venvs/poetry-patch-fixture-6KMianfx-py3.12", + "patchedViaPoetryRun": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "poetryRunScanApplied": { + "applied": 1, + "exit": 0 + }, + "rollbackRestoresUpstream": { + "exit": 0, + "oracle": { + "urllib3/response.py": "ea86196bb5cb3f20fee709d7507cd6b9b2c98017050f3a70033c27f47051ce06" + } + }, + "survivesRepeatInstall": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "survivesSync": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + } + } + }, + "mode": "agent-oot", + "passed": true, + "poetry": "2.4.3", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.4.3", + "shape": "direct" + }, + { + "checks": {}, + "expected": "informational: setup edits pyproject; poetry must resolve socket-patch[hook]", + "info": { + "lockChanged": true, + "poetryLockAfterSetup": { + "exit": 0, + "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-full/captures/2.4.3-direct-setup/project/.venv\n" + }, + "pyprojectChanged": true, + "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", + "setupCheckExit": 0, + "setupEnvelope": { + "alreadyConfigured": 0, + "errors": 0, + "files": [ + { + "error": null, + "kind": "pth", + "path": "/matrix-full/captures/2.4.3-direct-setup/project/pyproject.toml", + "status": "updated" + } + ], + "packageManager": "npm", + "pythonPackageManager": "poetry", + "status": "success", + "updated": 1 + }, + "setupExit": 0 + }, + "mode": "setup", + "passed": true, + "poetry": "2.4.3", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.4.3", + "shape": "direct" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasUrlSource": true, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackClearsRedirectLedger": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 1, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 1, + "failed": [], + "reverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [] + }, + "mode": "hosted", + "passed": true, + "poetry": "2.4.3", + "shape": "pep621" + }, + { + "checks": { + "appliedExactlyOne": true, + "freshCloneInstallsPatch": true, + "installedBytesPatched": true, + "lockHasFileSource": true, + "lockOnlyVendorApplies": false, + "lockRewritten": true, + "lockUnchangedByInstall": true, + "poetryInstallExit0": true, + "pyprojectUnchanged": true, + "recordHasFiles": true, + "rescanIdempotent": true, + "rollbackClearsManifest": true, + "rollbackExit0": true, + "rollbackKeepsPyproject": true, + "rollbackRemovesVendoredWheel": true, + "rollbackRestoresLockBytes": true, + "tamperBehaviorAsDocumented": true, + "vendoredWheelPresent": true + }, + "info": { + "applied": 1, + "appliedExactlyOne": { + "applied": 1, + "status": "success", + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "freshCloneInstallsPatch": { + "exit": 0, + "oracle": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "installedBytesPatched": { + "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" + }, + "lockCheck": { + "cmd": "check --lock", + "exit": 0, + "tail": "All set!\n" + }, + "lockOnlyVendor": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "lockOnlyVendorApplies": { + "applied": 0, + "codes": [ + "package_not_installed", + "vendor_fetch_unverifiable" + ], + "exit": 1 + }, + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "relock": { + "cmd": "lock -n", + "exit": 0, + "lockBytesUnchanged": true, + "patchSourceKept": true, + "pyprojectUnchanged": true, + "tail": "Resolving dependencies...\n" + }, + "rescanIdempotent": { + "applied": 0, + "exit": 0, + "status": "success" + }, + "rollbackEnvelope": { + "failed": 0, + "hosted": { + "editedFiles": 0, + "failed": [], + "reverted": [], + "unsupported": [] + }, + "manifest": { + "preserved": false, + "removedEntries": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "rolledBack": 0, + "status": "success", + "vendoredReverted": [ + "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + ] + }, + "scanExit": 0, + "tamper": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "tamperBehaviorAsDocumented": { + "expectsReject": true, + "installExit": 1, + "installedPatchedAnyway": false + }, + "uuid": "e828efa5-5c6d-43f3-9909-03f5ac232b98", + "vex": { + "exit": 0, + "statements": 1 + }, + "warnings": [ + { + "action": "applied", + "files": [ + { + "path": "urllib3/response.py", + "verified": true + } + ], + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" + }, + { + "action": "skipped", + "errorCode": "vendor_prebuilt_downloaded", + "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", + "reason": "vendored the wheel for pkg:pypi/urllib3@1.26.18 from the patch service (https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)" + } + ] + }, + "mode": "vendored", + "passed": true, + "poetry": "2.4.3", + "shape": "pep621" + } + ] +} \ No newline at end of file diff --git a/scripts/backtest-poetry.py b/scripts/backtest-poetry.py new file mode 100755 index 00000000..02df804b --- /dev/null +++ b/scripts/backtest-poetry.py @@ -0,0 +1,731 @@ +#!/usr/bin/env python3 +"""Drive the real socket-patch CLI and real Poetry releases through hosted, +vendored and agent mode on native poetry.lock generations. + +For every Poetry version the harness bootstraps that exact release with uv, +generates a native lock for a one-dependency project (urllib3 1.26.18, which +has a public free-tier Socket patch), then for each mode: + + hosted scan --mode hosted -> poetry install -> installed bytes == patch + vendored scan --mode vendored -> poetry install -> installed bytes == patch + agent poetry install -> scan --mode agent -> installed bytes == patch + +and checks idempotent re-scans, unchanged pyproject, lock-driven installs in a +FRESH clone of the committed state, tampered-hash rejection, what Poetry's own +relock does to the patch source, `poetry check --lock`, `vex`, and `rollback` +restoring every byte. Extra modes: `agent-oot` (Poetry's default out-of-tree +venv) and `setup`. Shapes: `direct` (native lock), `populated` (legacy locks +with real hashes filled in, as 2020-era locks have), `crlf`, `pep621` (2.x). + +Needs network (PyPI + patch.socket.dev), uv, and no Socket token. +""" + +import argparse +import concurrent.futures +import hashlib +import json +import os +import re +import shutil +import subprocess +import sys +import traceback +import urllib.request +from datetime import datetime, timezone +from pathlib import Path + +VERSIONS = [ + "0.12.17", + "1.0.10", + "1.1.15", + "1.2.2", + "1.3.2", + "1.4.2", + "1.5.1", + "1.6.1", + "1.7.1", + "1.8.5", + "2.0.1", + "2.1.4", + "2.2.1", + "2.3.4", + "2.4.3", +] +MODES = ["hosted", "vendored", "agent", "agent-oot", "setup"] +SHAPES = ["direct", "populated", "crlf", "pep621"] + +PROJECT = """[tool.poetry] +name = "poetry-patch-fixture" +version = "0.1.0" +description = "" +authors = ["Socket "] + +[tool.poetry.dependencies] +python = ">=3.8" +urllib3 = "1.26.18" +""" +PROJECT_PEP621 = """[project] +name = "poetry-patch-fixture" +version = "0.1.0" +requires-python = ">=3.8" +dependencies = ["urllib3==1.26.18"] + +[tool.poetry] +package-mode = false +""" +ORACLE = """import hashlib,json,pathlib,sys,sysconfig +root=pathlib.Path(sysconfig.get_paths()['purelib']) +out={} +for name in json.loads(sys.argv[1]): + p=root/name + if p.is_file(): + d=p.read_bytes(); out[name]=hashlib.sha256(('blob %d\\0'%len(d)).encode()+d).hexdigest() + else: + out[name]=None +print(json.dumps(out)) +""" +PATCH_UUID = "e828efa5-5c6d-43f3-9909-03f5ac232b98" +PURL_BASE = "pkg:pypi/urllib3@1.26.18" + + +def vtuple(v): + return tuple(int(x) for x in v.split(".")) + + +def save(path, data): + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n") + + +DEFAULT_TIMEOUT = int(os.environ.get("BACKTEST_TIMEOUT", "900")) + + +class Run: + def __init__(self, cmd, cwd, env, log, timeout=None): + timeout = timeout or DEFAULT_TIMEOUT + self.cmd = [str(c) for c in cmd] + try: + r = subprocess.run( + self.cmd, + cwd=cwd, + env=env, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=timeout, + ) + self.rc, self.out, self.err = r.returncode, r.stdout, r.stderr + except subprocess.TimeoutExpired as e: + def text(b): + return b.decode("utf-8", "replace") if isinstance(b, bytes) else (b or "") + self.rc, self.out, self.err = 124, text(e.stdout), text(e.stderr) + "\nTIMEOUT after %ss" % timeout + Path(log).write_text( + "$ " + " ".join(self.cmd) + f"\n# exit {self.rc}\n--- stdout\n{self.out}\n--- stderr\n{self.err}" + ) + + def ok(self): + return self.rc == 0 + + def json(self): + i = self.out.find("{") + if i < 0: + raise RuntimeError("no JSON in output: " + (self.out + self.err)[-2000:]) + return json.loads(self.out[i:]) + + def json_or_empty(self): + try: + return self.json() + except Exception: + return {} + + +def require(r, what): + if not r.ok(): + raise RuntimeError(f"{what} failed (exit {r.rc}):\n{(r.out + r.err)[-4000:]}") + return r + + +def base_env(): + env = { + k: v + for k, v in os.environ.items() + if not k.startswith(("PYTHON", "PIP_", "POETRY_", "SOCKET_", "UV_")) and k != "VIRTUAL_ENV" + } + env.update( + SOCKET_NO_CONFIG="1", + SOCKET_TELEMETRY_DISABLED="1", + PIP_CONFIG_FILE=os.devnull, + PIP_DISABLE_PIP_VERSION_CHECK="1", + PYTHONDONTWRITEBYTECODE="1", + ) + return env + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("--cli", required=True, type=Path) + ap.add_argument("--cli-revision", required=True) + ap.add_argument("--output", required=True, type=Path) + ap.add_argument("--versions", nargs="+", default=VERSIONS) + ap.add_argument("--modes", nargs="+", default=MODES, choices=MODES) + ap.add_argument("--shapes", nargs="+", default=["direct", "populated", "crlf"], choices=SHAPES) + ap.add_argument("--jobs", type=int, default=4) + ap.add_argument("--render-doc-table", type=Path, metavar="SUMMARY_JSON") + args = ap.parse_args() + if args.render_doc_table: + summary = json.loads(args.render_doc_table.read_text()) + print(render_doc_table(summary)) + print() + print(render_table(summary)) + return + root = args.output.resolve() + root.mkdir(parents=True, exist_ok=True) + cli = args.cli.resolve() + env = base_env() + provenance = { + "capturedAt": datetime.now(timezone.utc).isoformat(), + "cliRevision": args.cli_revision, + "cliSha256": hashlib.sha256(cli.read_bytes()).hexdigest(), + "poetryVersions": args.versions, + "modes": args.modes, + "shapes": args.shapes, + "host": os.uname().sysname + " " + os.uname().machine, + } + save(root / "provenance.json", provenance) + + # Real hashes of the upstream artifacts, for the `populated` legacy shape. + with urllib.request.urlopen("https://pypi.org/pypi/urllib3/1.26.18/json", timeout=60) as r: + pypi = json.load(r) + upstream_files = [ + {"file": u["filename"], "hash": "sha256:" + u["digests"]["sha256"]} + for u in pypi["urls"] + if u["filename"].endswith((".whl", ".tar.gz")) + ] + + def python_for(version): + return "3.8.20" if version.startswith(("0.", "1.0.", "1.1.")) else "3.12.13" + + def prepare_tool(version): + tool = root / "tools" / version + if not (tool / "bin/poetry").exists(): + require(Run(["uv", "venv", "-q", "--python", python_for(version), tool], root, env, root / f"tool-{version}-venv.log"), "uv venv") + pkgs = ["poetry==" + version, "pip==24.0", "setuptools==69.5.1"] + if version == "1.2.2": + pkgs.append("cleo==1.0.0a5") + require(Run(["uv", "pip", "install", "-q", "--python", tool / "bin/python", *pkgs], root, env, root / f"tool-{version}-bootstrap.log"), "poetry bootstrap") + return tool + + log_lock = __import__("threading").Lock() + + def say(*a): + with log_lock: + print(*a, flush=True) + + def poetry_env(project, venv=None, cache=None, home=None): + e = dict(env) + e["POETRY_VIRTUALENVS_IN_PROJECT"] = "true" + e["POETRY_CACHE_DIR"] = str(cache or (project / ".poetry-cache")) + # Poetry <= 1.1 keeps its HTTP cache under ~/Library/Caches/pypoetry + # regardless of POETRY_CACHE_DIR, behind a single lockfile that wedges + # every parallel run (and stays wedged after a SIGKILL). Give each case + # its own HOME so legacy releases never share that lock. + h = home or (project.parent / "home") + h.mkdir(parents=True, exist_ok=True) + e["HOME"] = str(h) + if venv is not None: + e["VIRTUAL_ENV"] = str(venv) + return e + + def native_lock(version, tool, shape): + """Generate (once) the native lock for `version`/`shape`; return dir.""" + key = "pep621" if shape == "pep621" else "direct" + original = root / "original" / version / key + if not (original / "poetry.lock").exists(): + original.mkdir(parents=True, exist_ok=True) + (original / "pyproject.toml").write_text(PROJECT_PEP621 if key == "pep621" else PROJECT) + (original / "poetry_patch_fixture").mkdir(exist_ok=True) + (original / "poetry_patch_fixture/__init__.py").touch() + require(Run([tool / "bin/poetry", "lock", "-n"], original, poetry_env(original), original / "generation.log"), f"poetry {version} lock") + return original + + def derive_shape(version, original, shape, dest): + dest.mkdir(parents=True, exist_ok=True) + for f in ["pyproject.toml", "poetry.lock"]: + shutil.copyfile(original / f, dest / f) + (dest / "poetry_patch_fixture").mkdir(exist_ok=True) + (dest / "poetry_patch_fixture/__init__.py").touch() + lock = (dest / "poetry.lock").read_text() + if shape == "populated": + if version.startswith("0."): + hashes = ", ".join(json.dumps(f["hash"].split(":", 1)[1]) for f in upstream_files) + lock = re.sub(r"(?m)^urllib3 = \[\]$", f"urllib3 = [{hashes}]", lock) + else: + entries = ",\n".join( + " {file = %s, hash = %s}" % (json.dumps(f["file"]), json.dumps(f["hash"])) for f in upstream_files + ) + lock = re.sub(r"(?m)^urllib3 = \[\]$", f"urllib3 = [\n{entries},\n]", lock) + if "urllib3 = []" in lock: + raise RuntimeError("populated shape: could not fill hashes") + (dest / "poetry.lock").write_text(lock) + if shape == "crlf": + for f in ["pyproject.toml", "poetry.lock"]: + p = dest / f + p.write_bytes(p.read_text().replace("\r\n", "\n").replace("\n", "\r\n").encode()) + + def make_venv(tool, venv, cwd, log, packages=()): + require(Run(["uv", "venv", "-q", "--python", tool / "bin/python", venv], cwd, env, log), "uv venv") + pkgs = ["pip==24.0", "setuptools==69.5.1", *packages] + require(Run(["uv", "pip", "install", "-q", "--python", venv / "bin/python", *pkgs], cwd, env, str(log) + ".pip"), "venv bootstrap") + + def oracle(python, names, cwd, log): + r = Run([python, "-c", ORACLE, json.dumps(names)], cwd, env, log) + return json.loads(r.out) if r.ok() and r.out.strip() else {} + + def record_hashes(project, mode): + if mode == "hosted": + ledger = json.loads((project / ".socket/vendor/redirect-state.json").read_text()) + recs = ledger["records"] + else: + recs = json.loads((project / ".socket/manifest.json").read_text())["patches"] + rec = next(iter(recs.values())) + return ( + {n: i["afterHash"] for n, i in rec["files"].items()}, + {n: i["beforeHash"] for n, i in rec["files"].items() if i.get("beforeHash")}, + rec.get("uuid"), + ) + + def poetry_install_cmd(version, poetry): + cmd = [poetry, "install", "-n"] + if not version.startswith("0."): + cmd.append("--no-root") + return cmd + + def cli_cmd(project, *rest): + return [cli, *rest, "--cwd", project, "--json", "--yes", "--no-telemetry"] + + def applied_count(mode, envelope): + if mode == "hosted": + return envelope.get("redirect", {}).get("redirected", 0) + if mode == "vendored": + return envelope.get("vendor", {}).get("summary", {}).get("applied", 0) + return envelope.get("apply", {}).get("applied", 0) + + def lock_check(version, poetry, project, penv, log): + """Poetry's own lock consistency check, whichever spelling exists.""" + v = vtuple(version) + if v >= (1, 6): + r = Run([poetry, "check", "--lock", "-n"], project, penv, log) + return {"cmd": "check --lock", "exit": r.rc, "tail": (r.out + r.err)[-400:]} + if v >= (1, 2): + r = Run([poetry, "lock", "--check", "-n"], project, penv, log) + return {"cmd": "lock --check", "exit": r.rc, "tail": (r.out + r.err)[-400:]} + return {"cmd": None} + + def relock(version, poetry, project, penv, log): + v = vtuple(version) + if (1, 1) <= v < (2, 0): + cmd = [poetry, "lock", "--no-update", "-n"] + else: + cmd = [poetry, "lock", "-n"] + r = Run(cmd, project, penv, log, timeout=600) + return {"cmd": " ".join(cmd[1:]), "exit": r.rc, "tail": (r.out + r.err)[-400:]} + + def sync_cmd(version, poetry): + v = vtuple(version) + if v >= (2, 0): + return [poetry, "sync", "-n", "--no-root"] + if v >= (1, 2): + return [poetry, "install", "-n", "--no-root", "--sync"] + return None + + def backtest(job): + version, shape, mode = job + tool = root / "tools" / version + poetry = tool / "bin/poetry" + case = root / "captures" / f"{version}-{shape}-{mode}" + if case.exists(): + shutil.rmtree(case) + case.mkdir(parents=True) + original = native_lock(version, tool, shape) + pristine_dir = case / "pristine" + derive_shape(version, original, shape, pristine_dir) + project = case / "project" + shutil.copytree(pristine_dir, project) + pristine_lock = (pristine_dir / "poetry.lock").read_bytes() + pristine_pyproject = (pristine_dir / "pyproject.toml").read_bytes() + row = {"poetry": version, "shape": shape, "mode": mode, "checks": {}, "info": {}, "passed": None} + checks, info = row["checks"], row["info"] + v = vtuple(version) + + def check(name, value, note=None): + checks[name] = bool(value) + if note is not None: + info[name] = note + return bool(value) + + venv = project / ".venv" + python = venv / "bin/python" + + # ------------------------------------------------------------ setup + if mode == "setup": + senv = dict(env) + senv["PATH"] = str(tool / "bin") + os.pathsep + senv.get("PATH", "") + r = Run(cli_cmd(project, "setup"), project, senv, case / "setup.log") + info["setupExit"] = r.rc + try: + info["setupEnvelope"] = r.json() + except Exception: + info["setupOutput"] = (r.out + r.err)[-1500:] + info["pyprojectChanged"] = (project / "pyproject.toml").read_bytes() != pristine_pyproject + info["pyprojectDiff"] = (project / "pyproject.toml").read_text() + info["lockChanged"] = (project / "poetry.lock").read_bytes() != pristine_lock + # Can Poetry itself resolve the committed hook dependency? + rl = Run([poetry, "lock", "-n"] + (["--no-update"] if (1, 1) <= v < (2, 0) else []), project, poetry_env(project), case / "setup-relock.log") + info["poetryLockAfterSetup"] = {"exit": rl.rc, "tail": (rl.out + rl.err)[-600:]} + chk = Run(cli_cmd(project, "setup", "--check"), project, senv, case / "setup-check.log") + info["setupCheckExit"] = chk.rc + row["passed"] = r.rc == 0 and info["pyprojectChanged"] and rl.rc == 0 + row["expected"] = "informational: setup edits pyproject; poetry must resolve socket-patch[hook]" + return row + + # -------------------------------------------------------- agent-oot + if mode == "agent-oot": + penv = dict(env) + penv["POETRY_VIRTUALENVS_IN_PROJECT"] = "false" + penv["POETRY_VIRTUALENVS_PATH"] = str(case / "venvs") + penv["POETRY_CACHE_DIR"] = str(case / "poetry-cache") + require(Run(poetry_install_cmd(version, poetry), project, penv, case / "install-upstream.log"), "poetry install (out-of-tree)") + ep = Run([poetry, "env", "info", "-p"], project, penv, case / "env-info.log") + oot_venv = Path(ep.out.strip().splitlines()[-1]) if ep.ok() and ep.out.strip() else None + info["ootVenv"] = str(oot_venv) + if not oot_venv or not (oot_venv / "bin/python").exists(): + raise RuntimeError("could not locate Poetry's out-of-tree venv: " + ep.out + ep.err) + # 1. bare scan from the project dir, no VIRTUAL_ENV: does the CLI see the venv? + r1 = Run(cli_cmd(project, "scan", "--mode", "agent", "--dry-run"), project, env, case / "scan-bare-dryrun.log") + e1 = r1.json_or_empty() + paths = [p for p in (e1.get("paths") or [])] + pkgs = e1.get("packages") or [] + info["bareScan"] = { + "exit": r1.rc, + "scannedPackages": e1.get("scannedPackages"), + "packagesWithPatches": e1.get("packagesWithPatches"), + "paths": paths[:10], + "urllib3Found": any("urllib3" in (p.get("purl") or "") for p in pkgs), + "packageDirs": [pth for p in pkgs for pth in (p.get("paths") or [])][:10], + } + check("bareScanSeesPoetryVenv", any(str(oot_venv) in str(x) for x in json.dumps(e1).split('"')), "the CLI found the out-of-tree venv without help") + # 2. via `poetry run` (VIRTUAL_ENV set by Poetry) -> should patch the venv + r2 = Run([poetry, "run", *cli_cmd(project, "scan", "--mode", "agent")], project, penv, case / "scan-poetry-run.log") + e2 = r2.json_or_empty() + check("poetryRunScanApplied", applied_count("agent", e2) == 1, {"exit": r2.rc, "applied": applied_count("agent", e2)}) + after, before, _ = record_hashes(project, "agent") if (project / ".socket/manifest.json").exists() else ({}, {}, None) + res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-1.log") + check("patchedViaPoetryRun", bool(after) and all(res.get(n) == h for n, h in after.items()), res) + # 3. a repeat `poetry install` must not revert the in-place patch + require(Run(poetry_install_cmd(version, poetry), project, penv, case / "install-again.log"), "poetry install again") + res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-2.log") + check("survivesRepeatInstall", bool(after) and all(res.get(n) == h for n, h in after.items()), res) + sc = sync_cmd(version, poetry) + if sc: + rs = Run(sc, project, penv, case / "sync.log") + res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-3.log") + check("survivesSync", rs.ok() and bool(after) and all(res.get(n) == h for n, h in after.items()), {"exit": rs.rc, "oracle": res}) + # 4. rollback through poetry run + rb = Run([poetry, "run", *cli_cmd(project, "rollback")], project, penv, case / "rollback.log") + res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-4.log") + check("rollbackRestoresUpstream", rb.ok() and bool(before) and all(res.get(n) == h for n, h in before.items()), {"exit": rb.rc, "oracle": res}) + check("rollbackClearsManifest", not (project / ".socket/manifest.json").exists() or json.loads((project / ".socket/manifest.json").read_text()).get("patches") == {}) + row["passed"] = all(checks[k] for k in checks if k != "bareScanSeesPoetryVenv") + row["expected"] = "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass" + return row + + # ------------------------------------------------- hosted / vendored / agent + if mode == "vendored": + # Fresh-clone scenario first: nothing installed, lock only. + r0 = Run(cli_cmd(project, "scan", "--mode", "vendored"), project, env, case / "scan-lockonly.log") + e0 = r0.json_or_empty() + events = e0.get("vendor", {}).get("events", []) + info["lockOnlyVendor"] = { + "exit": r0.rc, + "applied": applied_count("vendored", e0), + "codes": sorted({ev.get("errorCode") for ev in events if ev.get("errorCode")}), + } + check("lockOnlyVendorApplies", applied_count("vendored", e0) == 1, info["lockOnlyVendor"]) + # reset any partial state + shutil.rmtree(project / ".socket", ignore_errors=True) + (project / "poetry.lock").write_bytes(pristine_lock) + + make_venv(tool, venv, project, case / "venv.log", packages=["urllib3==1.26.18"] if mode != "agent" else ()) + penv = poetry_env(project, venv=venv) + if mode == "agent": + require(Run(poetry_install_cmd(version, poetry), project, penv, case / "install-upstream.log"), "poetry install (upstream)") + + r = Run(cli_cmd(project, "scan", "--mode", mode), project, env, case / "scan.log") + info["scanExit"] = r.rc + try: + envelope = r.json() + except Exception as e: + raise RuntimeError(f"scan produced no JSON: {e}") + save(case / "cli-output.json", envelope) + applied = applied_count(mode, envelope) + info["applied"] = applied + warnings = envelope.get("redirect", {}).get("warnings", []) if mode == "hosted" else envelope.get("vendor", {}).get("events", []) + info["warnings"] = warnings[:8] + lock_after = (project / "poetry.lock").read_bytes() + check("pyprojectUnchanged", (project / "pyproject.toml").read_bytes() == pristine_pyproject) + + if mode == "hosted" and version.startswith("0."): + row["expected"] = "refused: Poetry 0.x ignores URL sources" + check("refusedWithWarning", applied == 0 and any("ignores URL sources" in json.dumps(w) for w in warnings), warnings[:3]) + check("lockUnchanged", lock_after == pristine_lock) + check("noLedger", not (project / ".socket/vendor/redirect-state.json").exists()) + row["passed"] = all(checks.values()) + return row + + check("appliedExactlyOne", applied == 1, {"applied": applied, "status": envelope.get("status"), "warnings": warnings[:4]}) + if not checks["appliedExactlyOne"]: + row["passed"] = False + return row + if mode == "agent": + check("lockUnchanged", lock_after == pristine_lock) + else: + check("lockRewritten", lock_after != pristine_lock) + if shape == "crlf": + check("crlfPreserved", b"\n" not in lock_after.replace(b"\r\n", b"")) + after, before, uuid = record_hashes(project, mode) + info["uuid"] = uuid + check("recordHasFiles", bool(after)) + if mode == "vendored": + wheel_dir = project / ".socket/vendor/pypi" / (uuid or "") + check("vendoredWheelPresent", wheel_dir.is_dir() and any(wheel_dir.glob("*.whl"))) + check("lockHasFileSource", b'type = "file"' in lock_after) + if mode == "hosted": + check("lockHasUrlSource", b'type = "url"' in lock_after and b"patch.socket.dev" in lock_after) + + # idempotent re-scan + r2 = Run(cli_cmd(project, "scan", "--mode", mode), project, env, case / "rescan.log") + e2 = r2.json_or_empty() + check("rescanIdempotent", r2.ok() and (project / "poetry.lock").read_bytes() == lock_after and (project / "pyproject.toml").read_bytes() == pristine_pyproject, {"exit": r2.rc, "applied": applied_count(mode, e2), "status": e2.get("status")}) + + if mode == "agent": + res = oracle(python, list(after), project, case / "oracle-1.log") + check("installedBytesPatched", all(res.get(n) == h for n, h in after.items()), res) + # repeat install must not revert; sync too + ri = Run(poetry_install_cmd(version, poetry), project, penv, case / "install-again.log") + res = oracle(python, list(after), project, case / "oracle-2.log") + check("survivesRepeatInstall", ri.ok() and all(res.get(n) == h for n, h in after.items()), {"exit": ri.rc, "oracle": res}) + sc = sync_cmd(version, poetry) + if sc: + rs = Run(sc, project, penv, case / "sync.log") + res = oracle(python, list(after), project, case / "oracle-3.log") + check("survivesSync", rs.ok() and all(res.get(n) == h for n, h in after.items()), {"exit": rs.rc, "oracle": res}) + else: + # Warm venv: upstream urllib3 is already installed. Does the + # redirected lock make Poetry replace it? (Poetry <= 1.1 compares + # name+version only and leaves the vulnerable copy in place.) + warm = Run(poetry_install_cmd(version, poetry), project, penv, case / "install-warm.log") + wres = oracle(python, list(after), project, case / "oracle-warm.log") + info["warmInstall"] = {"exit": warm.rc, "patched": bool(after) and all(wres.get(n) == h for n, h in after.items()), "tail": (warm.out + warm.err)[-300:]} + check("warmInstallReplacesUpstream", warm.ok() and info["warmInstall"]["patched"], info["warmInstall"]) + # Lock-driven install into the (now emptied) venv. + require(Run(["uv", "pip", "uninstall", "-q", "--python", python, "urllib3"], project, env, case / "uninstall.log"), "uninstall") + inst = Run(poetry_install_cmd(version, poetry), project, penv, case / "install.log") + res = oracle(python, list(after), project, case / "oracle-1.log") + check("poetryInstallExit0", inst.ok(), (inst.out + inst.err)[-600:]) + check("installedBytesPatched", all(res.get(n) == h for n, h in after.items()), res) + check("lockUnchangedByInstall", (project / "poetry.lock").read_bytes() == lock_after) + info["lockCheck"] = lock_check(version, poetry, project, penv, case / "lock-check.log") + # Fresh clone of the committed state (no venv, no caches) + fresh = case / "fresh" + shutil.copytree(project, fresh, ignore=shutil.ignore_patterns(".venv", ".poetry-cache", "__pycache__")) + make_venv(tool, fresh / ".venv", fresh, case / "fresh-venv.log") + fenv = poetry_env(fresh, venv=fresh / ".venv", cache=fresh / ".poetry-cache") + finst = Run(poetry_install_cmd(version, poetry), fresh, fenv, case / "fresh-install.log") + fres = oracle(fresh / ".venv/bin/python", list(after), fresh, case / "fresh-oracle.log") + check("freshCloneInstallsPatch", finst.ok() and all(fres.get(n) == h for n, h in after.items()), {"exit": finst.rc, "oracle": fres, "tail": (finst.out + finst.err)[-500:]}) + # vex over the installed, redirected/vendored tree + vx = Run([cli, "vex", "--cwd", project, "--no-telemetry"], project, env, case / "vex.log") + try: + vdoc = json.loads(vx.out[vx.out.find("{"):]) if vx.ok() else {} + info["vex"] = {"exit": vx.rc, "statements": len(vdoc.get("statements", []))} + except Exception: + info["vex"] = {"exit": vx.rc, "tail": (vx.out + vx.err)[-400:]} + # Tamper: corrupt the recorded hash, install must fail where the installer verifies. + if shape != "crlf": + require(Run(["uv", "pip", "uninstall", "-q", "--python", python, "urllib3"], project, env, case / "tamper-uninstall.log"), "uninstall") + corrupt = re.sub(rb"sha256[:=][a-f0-9]{64}", lambda m: m[0][:7] + b"0" * 64, lock_after) + if version.startswith("0."): + corrupt = re.sub(rb'"[a-f0-9]{64}"', b'"' + b"0" * 64 + b'"', corrupt) + (project / "poetry.lock").write_bytes(corrupt) + tam = Run(poetry_install_cmd(version, poetry), project, poetry_env(project, venv=venv, cache=case / "tamper-cache"), case / "tamper-install.log") + tres = oracle(python, list(after), project, case / "tamper-oracle.log") + (project / "poetry.lock").write_bytes(lock_after) + expects_reject = mode == "hosted" or v >= (1, 4) + info["tamper"] = {"installExit": tam.rc, "installedPatchedAnyway": all(tres.get(n) == h for n, h in after.items()), "expectsReject": expects_reject} + check("tamperBehaviorAsDocumented", (tam.rc != 0) == expects_reject, info["tamper"]) + # reinstall the good state for the remaining steps + Run(["uv", "pip", "uninstall", "-q", "--python", python, "urllib3"], project, env, case / "tamper-uninstall2.log") + require(Run(poetry_install_cmd(version, poetry), project, penv, case / "reinstall.log"), "reinstall") + # Relock: does Poetry's own relock keep the patch source? (informational) + rl = relock(version, poetry, project, penv, case / "relock.log") + relocked = (project / "poetry.lock").read_bytes() + marker = b"patch.socket.dev" if mode == "hosted" else b".socket/vendor/pypi" + rl.update(lockBytesUnchanged=relocked == lock_after, patchSourceKept=marker in relocked, pyprojectUnchanged=(project / "pyproject.toml").read_bytes() == pristine_pyproject) + info["relock"] = rl + (project / "poetry.lock").write_bytes(lock_after) + + # Rollback restores every byte and clears the ledgers. + rb = Run(cli_cmd(project, "rollback"), project, env, case / "rollback.log") + erb = rb.json_or_empty() + check("rollbackExit0", rb.ok(), (rb.out + rb.err)[-600:] if not rb.ok() else None) + check("rollbackRestoresLockBytes", (project / "poetry.lock").read_bytes() == pristine_lock) + check("rollbackKeepsPyproject", (project / "pyproject.toml").read_bytes() == pristine_pyproject) + if mode == "hosted": + check("rollbackClearsRedirectLedger", not (project / ".socket/vendor/redirect-state.json").exists() or not json.loads((project / ".socket/vendor/redirect-state.json").read_text()).get("records")) + if mode == "vendored": + check("rollbackRemovesVendoredWheel", not (project / ".socket/vendor/pypi" / (uuid or "x")).exists()) + if mode == "agent": + res = oracle(python, list(after), project, case / "oracle-rollback.log") + check("rollbackRestoresUpstreamBytes", bool(before) and all(res.get(n) == h for n, h in before.items()), res) + mf = project / ".socket/manifest.json" + check("rollbackClearsManifest", not mf.exists() or json.loads(mf.read_text()).get("patches") in ({}, None)) + info["rollbackEnvelope"] = {k: erb.get(k) for k in ("status", "rolledBack", "failed", "hosted", "vendoredReverted", "manifest") if k in erb} + informational = {"lockOnlyVendorApplies", "warmInstallReplacesUpstream"} + row["passed"] = all(val for k, val in checks.items() if k not in informational) + return row + + prepared = {} + with concurrent.futures.ThreadPoolExecutor(max_workers=args.jobs) as pool: + futs = {pool.submit(prepare_tool, v): v for v in args.versions} + for f in concurrent.futures.as_completed(futs): + v = futs[f] + try: + prepared[v] = f.result() + say("bootstrapped poetry", v) + except Exception as e: + say("BOOTSTRAP FAILED", v, str(e)[-800:]) + + def wanted(version, shape, mode): + v = vtuple(version) + if version not in prepared: + return False + if shape == "populated" and not version.startswith(("0.", "1.0.", "1.1.")): + return False + if shape == "pep621" and v < (2, 0): + return False + if shape in ("crlf", "pep621") and mode in ("agent", "agent-oot", "setup"): + return False + if shape == "populated" and mode in ("agent", "agent-oot", "setup"): + return False + if mode == "agent-oot" and version.startswith("0."): + return False + if mode == "setup" and version not in ("1.1.15", "1.8.5", "2.4.3"): + return False + return True + + jobs = [(v, s, m) for v in args.versions for s in args.shapes for m in args.modes if wanted(v, s, m)] + say(f"{len(jobs)} cases") + results, errors = [], [] + # Generate native locks serially per version first (the pool would race on the shared dir). + for v in args.versions: + if v in prepared: + for shape in {("pep621" if s == "pep621" else "direct") for s in args.shapes if any(wanted(v, s, m) for m in args.modes)}: + try: + native_lock(v, prepared[v], shape) + except Exception as e: + say("LOCK GENERATION FAILED", v, shape, str(e)[-800:]) + errors.append({"poetry": v, "shape": shape, "error": "lock generation: " + str(e)[-1500:]}) + with concurrent.futures.ThreadPoolExecutor(max_workers=args.jobs) as pool: + pending = {pool.submit(backtest, job): job for job in jobs} + for fut in concurrent.futures.as_completed(pending): + job = pending[fut] + try: + row = fut.result() + results.append(row) + failed = [k for k, ok in row["checks"].items() if not ok] + say(*job, "PASS" if row["passed"] else "FAIL", ",".join(failed)) + except Exception as e: + errors.append({"poetry": job[0], "shape": job[1], "mode": job[2], "error": str(e)[-3000:], "trace": traceback.format_exc()[-1500:]}) + say(*job, "ERROR", str(e)[-300:].replace("\n", " ")) + save(root / "summary.json", {"provenance": provenance, "results": sorted(results, key=lambda r: (vtuple(r["poetry"]), r["shape"], r["mode"])), "errors": errors}) + summary = json.loads((root / "summary.json").read_text()) if (root / "summary.json").exists() else {"provenance": provenance, "results": results, "errors": errors} + (root / "summary.md").write_text(render_table(summary)) + say(render_table(summary)) + if errors or any(not r["passed"] for r in results): + sys.exit(1) + + +def render_doc_table(summary): + """Per-version compatibility table for docs/testing/poetry-compatibility.md.""" + rows = summary["results"] + by = {} + for r in rows: + by.setdefault(r["poetry"], []).append(r) + lines = [ + "| Poetry | hosted | vendored | agent (in-project venv) | agent (`poetry run`, out-of-tree venv) | tamper rejected (hosted / vendored) | warm venv re-installed (hosted / vendored) | relock keeps patch (hosted / vendored) | lock-only vendored |", + "| --- | --- | --- | --- | --- | --- | --- | --- | --- |", + ] + + def cell(cases): + if not cases: + return "n/a" + ok = sum(1 for c in cases if c["passed"]) + shapes = ",".join(sorted({c["shape"] for c in cases})) + return ("pass" if ok == len(cases) else f"{ok}/{len(cases)}") + f" ({shapes})" + + def flag(cases, key, sub=None): + vals = set() + for c in cases: + i = c.get("info", {}).get(key) + if isinstance(i, dict): + vals.add(i.get(sub)) + vals.discard(None) + return "/".join(sorted(str(v).lower() for v in vals)) or "n/a" + + for version in sorted(by, key=vtuple): + cs = by[version] + m = lambda mode: [c for c in cs if c["mode"] == mode] + hosted, vendored = m("hosted"), m("vendored") + refused = any(c.get("expected", "").startswith("refused") for c in hosted) + hosted_cell = "refused (0.x ignores URL sources)" if refused else cell(hosted) + direct_h = [c for c in hosted if c["shape"] == "direct" and "tamper" in c["info"]] + direct_v = [c for c in vendored if c["shape"] == "direct" and "tamper" in c["info"]] + tamper = f"{'yes' if any(c['info']['tamper']['installExit'] != 0 for c in direct_h) else ('n/a' if not direct_h else 'no')} / {'yes' if any(c['info']['tamper']['installExit'] != 0 for c in direct_v) else ('n/a' if not direct_v else 'no')}" + relock = f"{flag([c for c in hosted if c['shape']=='direct'], 'relock', 'patchSourceKept')} / {flag([c for c in vendored if c['shape']=='direct'], 'relock', 'patchSourceKept')}" + warm = f"{flag([c for c in hosted if c['shape']=='direct'], 'warmInstall', 'patched')} / {flag([c for c in vendored if c['shape']=='direct'], 'warmInstall', 'patched')}" + lockonly = flag(vendored, "lockOnlyVendor", "applied") + lockonly = {"0": "refused", "1": "yes"}.get(lockonly, lockonly) + lines.append( + f"| {version} | {hosted_cell} | {cell(vendored)} | {cell(m('agent'))} | {cell(m('agent-oot'))} | {tamper} | {warm} | {relock} | {lockonly} |" + ) + return "\n".join(lines) + + +def render_table(summary): + rows = summary["results"] + lines = ["| Poetry | shape | mode | passed | failed checks | notes |", "| --- | --- | --- | --- | --- | --- |"] + for r in sorted(rows, key=lambda r: (vtuple(r["poetry"]), r["shape"], r["mode"])): + failed = ", ".join(k for k, ok in r["checks"].items() if not ok) + notes = [] + info = r.get("info", {}) + if "relock" in info: + notes.append(f"relock({info['relock'].get('cmd')}) exit {info['relock'].get('exit')} keeps patch={info['relock'].get('patchSourceKept')}") + if "lockCheck" in info and info["lockCheck"].get("cmd"): + notes.append(f"{info['lockCheck']['cmd']} exit {info['lockCheck']['exit']}") + if "tamper" in info: + notes.append(f"tamper install exit {info['tamper']['installExit']} (expects reject={info['tamper']['expectsReject']})") + if "lockOnlyVendor" in info: + notes.append(f"lock-only vendor applied={info['lockOnlyVendor']['applied']} {info['lockOnlyVendor']['codes']}") + if "bareScan" in info: + notes.append(f"bare scan sees venv={r['checks'].get('bareScanSeesPoetryVenv')}") + if "vex" in info: + notes.append(f"vex exit {info['vex'].get('exit')} stmts={info['vex'].get('statements')}") + if "poetryLockAfterSetup" in info: + notes.append(f"poetry lock after setup exit {info['poetryLockAfterSetup']['exit']}") + lines.append(f"| {r['poetry']} | {r['shape']} | {r['mode']} | {'PASS' if r['passed'] else 'FAIL'} | {failed} | {'; '.join(notes)} |") + for e in summary.get("errors", []): + lines.append(f"| {e.get('poetry')} | {e.get('shape')} | {e.get('mode')} | ERROR | {e['error'][-160:].replace(chr(10), ' ')} | |") + return "\n".join(lines) + + +if __name__ == "__main__": + main() From 64c7a2962313109f412e630a36715e6c2f20ffeb Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:22:16 -0400 Subject: [PATCH 07/19] docs(poetry): document measured installer boundaries, warning codes and the matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CHANGELOG [Unreleased] entry for hosted + legacy Poetry support (the uv precedent had one; this PR did not). - poetry-compatibility.md rewritten around the measured matrix: per-generation rewrite shapes, the Poetry < 1.4 warm-virtualenv and hash-verification boundaries, which Poetry commands drop the patch source (with content-hash unchanged, so `poetry check --lock` cannot tell), the 0.12/1.0 cwd-relative file-source caveat, agent-mode discovery of Poetry's out-of-tree virtualenv, the lock-only vendored limitation, the harness recipe and the generated results table. - CLI_CONTRACT: poetry.lock joins the hosted candidate files; the vendored rows cover every lock generation; the new `redirect_poetry_*` and `pypi_poetry_integrity_unverified` codes are listed. - hosted-production-e2e.md no longer says Poetry locks are not rewritten by hosted mode; README no longer says hosted mode has no CLI revert (`rollback` unwinds it since the scan↔rollback duality change). Co-Authored-By: Claude Fable 5.1 --- CHANGELOG.md | 25 ++++ README.md | 13 +- crates/socket-patch-cli/CLI_CONTRACT.md | 9 +- docs/testing/hosted-production-e2e.md | 8 +- docs/testing/poetry-compatibility.md | 177 +++++++++++++++++++++--- 5 files changed, 204 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac44cccc..fdf41ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,31 @@ into the new version's section — see docs/releasing.md. ### Added +- **Poetry projects take hosted patches, and vendored patches now cover every + `poetry.lock` generation.** `scan --mode hosted` rewrites `poetry.lock` to a + `[package.source] type = "url"` pointing at the Socket-hosted, SHA-256-pinned + wheel (Poetry 1.0 through 2.x; Poetry 0.12 ignores URL sources and is refused + with `redirect_poetry_lock_unsupported`), and `scan --mode vendored` accepts + the legacy `[metadata.hashes]` (0.12) and `[metadata.files]` (lock 1.0/1.1) + layouts next to the 2.x `files` arrays, CRLF locks included. The rewrite keeps + every other byte of the lock — dependency metadata, groups, markers, extras + and the pyproject `content-hash` — and records independent rollback fragments + per patch, so `rollback` restores the recorded originals in any order. + Verified end-to-end against real Poetry 0.12.17, 1.0.10, 1.1.15, 1.2.2, + 1.3.2, 1.4.2, 1.5.1, 1.6.1, 1.7.1, 1.8.5, 2.0.1, 2.1.4, 2.2.1, 2.3.4 and + 2.4.3 in hosted, vendored and agent mode — see + `docs/testing/poetry-compatibility.md` and `scripts/backtest-poetry.py`. + Poetry releases before 1.4 neither verify local wheel hashes nor replace an + already-installed package at the same version; both modes surface that as an + advisory (`pypi_poetry_integrity_unverified`, `redirect_poetry_stale_install_risk`) + keyed on the lock's writer, and the hosted rewriter warns + `redirect_poetry_entry_not_found` when a lock has no entry for a granted + patch (uv parity). A rotated grant token or republished patch supersedes the + earlier hosted URL in place instead of being refused as a foreign source, + a future `lock-version = "2."` is rewritten like 2.1 on every path + (the vendored loader already accepted it), and a malformed + `[metadata.files]` / `[metadata.hashes]` value is refused instead of + panicking the scan. (#241) - **Python patches survive uv lockfiles in both hosted and vendored modes.** `scan --mode hosted|vendored` now rewrites native `uv.lock` together with the paired `pyproject.toml` source and metadata, PEP 723 script locks diff --git a/README.md b/README.md index 093b07dc..5f2d91af 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ The same patched bytes can reach your build three different ways. The modes diff |------|----------------------|--------------------------|-----------| | **agent** — `scan --mode agent` (or [`apply`](#apply)) | `.socket/` manifest + blobs, committed; the CLI re-applies after each install | The `socket-patch` CLI must run (install hook via [`setup`](#setup), or an `apply` step in CI) | Small repo footprint (per-file blobs, not whole packages); no lockfile edits; the only mode that needs CI / install-hook changes | | **vendored** — `scan --mode vendored` (or [`vendor`](#vendor)) | Patched packages committed under `.socket/vendor/`; the lockfile is rewired to consume them | **None** — the package manager installs the committed bytes | Fully airgapped and hermetic, at the cost of repo size | -| **hosted** — `scan --mode hosted` | No patched bytes in your repo: the lockfile is rewritten so **only** the patched dependencies resolve to Socket-hosted, integrity-pinned packages on `patch.socket.dev`; the edits + patch records are ledgered in `.socket/vendor/redirect-state.json` (commit it — [`vex`](#vex) reads it, and it records the pre-redirect originals a future revert feature will need; hosted has no CLI revert yet, see [Undo things](#undo-things)) | Installs must be able to reach `patch.socket.dev` (no CLI, no install hook) | Smallest possible diff (lockfile + ledger); not for airgapped installs | +| **hosted** — `scan --mode hosted` | No patched bytes in your repo: the lockfile is rewritten so **only** the patched dependencies resolve to Socket-hosted, integrity-pinned packages on `patch.socket.dev`; the edits + patch records are ledgered in `.socket/vendor/redirect-state.json` (commit it — [`vex`](#vex) reads it, and [`rollback`](#rollback) replays its recorded pre-redirect originals to unwind the redirect, see [Undo things](#undo-things)) | Installs must be able to reach `patch.socket.dev` (no CLI, no install hook) | Smallest possible diff (lockfile + ledger); not for airgapped installs | Every mode pins the patched bytes: in agent mode the CLI verifies every file on each apply; vendored and hosted modes lean on your package manager's own lockfile integrity @@ -356,11 +356,12 @@ and repair; pick by what you want back: And `setup --remove` reverts the install hooks that `setup` added. -> Hosted mode has no CLI revert yet: `scan --mode hosted` makes plain lockfile / -> registry-config edits, so undo them with your version control (e.g. -> `git checkout -- `) and delete the `.socket/vendor/redirect-state.json` -> ledger — once you've reverted by hand, its recorded original fragments are stale, and -> a leftover ledger would still let [`vex`](#vex) attest the removed redirects. +> Hosted mode is unwound by [`rollback`](#rollback), which replays the original +> lockfile / registry-config fragments recorded in `.socket/vendor/redirect-state.json` +> and drops the redirect records. If you revert a hosted edit by hand instead (e.g. +> `git checkout -- `), also delete that ledger — its recorded originals are +> then stale, and a leftover ledger would still let [`vex`](#vex) attest the removed +> redirects. ## Command reference diff --git a/crates/socket-patch-cli/CLI_CONTRACT.md b/crates/socket-patch-cli/CLI_CONTRACT.md index b0a730a1..137f6997 100644 --- a/crates/socket-patch-cli/CLI_CONTRACT.md +++ b/crates/socket-patch-cli/CLI_CONTRACT.md @@ -120,7 +120,7 @@ For a **9.0 root lock**, the CLI ensures `pnpm-workspace.yaml` carries `trustLoc `scan --mode hosted` (== `--redirect`) swaps the in-place apply for the registry-redirect pipeline: discover → resolve hosted-patch references (grant token + integrity + per-dep registry override) → rewrite ONLY the patched dependencies' lockfile / registry-config entries to point at the hosted packages. A dep counts as **redirected** only when its hosted-artifact URL (or per-dep registry index URL, or — for golang — the `patch.socket.dev/gopatch/` module path) actually landed in a project file — a granted reference whose rewriter found nothing to edit is neither recorded nor attested. Re-runs over already-rewritten output record zero new edits. JSON output gains a `redirect` sub-object: `{ mode: "hosted", redirected, rewrittenFiles, skipped, warnings, dryRun }` (`mode` is additive so consumers can dispatch without inferring it). Rewriter warnings carry stable `redirect_*` codes (e.g. `redirect_npm_no_lockfile`, `redirect_gradle_manual_snippet`, `redirect_golang_unsupported`); new codes are additive (MINOR). Refusals stay fail-closed with a diagnosis that names the actual cause: a yarn-berry lock entry resolving through a non-`npm:` protocol keeps `redirect_yarn_berry_unsupported_protocol` with the entry's ACTUAL protocol in the detail — except socket-patch's OWN vendored wiring (a `file:` range into `.socket/vendor/`), which gets the distinct `redirect_yarn_berry_vendored_entry` code whose detail names the retirement path (`remove ` per package, or `vendor --revert` which unwinds every vendored package, then re-run `scan --mode hosted`). Both leave the entry byte-identical; neither changes exit code or status. -The rewriter reads a fixed set of candidate files from the project root: the npm-family locks (`package-lock.json`, `npm-shrinkwrap.json`, `pnpm-lock.yaml`, `shrinkwrap.yaml`, `yarn.lock`, plus `.yarnrc.yml` for the berry cache-config gate and `bun.lock`), `requirements.txt` / `uv.lock`, `Cargo.toml` / `Cargo.lock` / `.cargo/config.toml` (plus the legacy extensionless `.cargo/config` — cargo reads that spelling in preference when both exist, so the managed `[registries.…]` block is written into whichever one is present), `composer.lock`, `nuget.config` / `packages.lock.json`, `Gemfile` / `Gemfile.lock`, `pom.xml` (+ `.mvn/maven.config` / `.mvn/checksums/checksums.sha256` for maven Trusted Checksums merge, and the Gradle build scripts read only to trigger the manual-snippet warning). **npm-family flavor coverage**: package-lock / npm-shrinkwrap, pnpm (root OR any nested `*/pnpm-lock.yaml`), yarn classic, **yarn berry** (`yarn.lock` entry only — `resolution: ::__archiveUrl=` + `yarnBerry10c0` checksum; cacheKey `10c0` and `.yarnrc.yml compressionLevel 0` gated by `redirect_yarn_berry_cache_unsupported`), and **bun** (text `bun.lock` lockfileVersion 1 or 2 — bun 1.3/1.4 share one emitted grammar; a binary `bun.lockb` with no text lock is auto-migrated to text via `bun install --save-text-lockfile --frozen-lockfile --lockfile-only` before the read, recorded as a `removed` FileEdit; `redirect_bun_lockb_would_migrate` on `--dry-run`, `redirect_bun_lockb_unsupported` when the migration is unavailable). **Rush monorepos**: when `rush.json` is present the rewriter also reads `common/config/rush/pnpm-lock.yaml` and each `common/config/subspaces//pnpm-lock.yaml` (sorted for determinism) under their repo-relative keys and repoints them in place; editing them emits `redirect_rush_repo_state_stale` when `common/config/rush/repo-state.json` exists (the `pnpmShrinkwrapHash` desync is refreshed by `rush update`, which the redirect survives). **maven** is fail-closed via version suffixing: a `mavenSuffixedVersion` + `mavenPomSha256` override pins the Socket-only `-socket.` by rewriting the literal `` (`redirect_maven_dep_version`) or adding a `` entry (`redirect_maven_dep_management_added`), plus optional Trusted Checksums (`redirect_maven_trusted_checksums`, conflicts as `redirect_maven_trusted_checksums_conflict`); a `${property}` version is refused (`redirect_maven_dep_unpinned`), a non-matching literal skipped (`redirect_maven_dep_version_mismatch`), and an override without a suffixed version falls back to same-GAV repository injection (`redirect_maven_same_gav_fallback`, NOT fail-closed). +The rewriter reads a fixed set of candidate files from the project root: the npm-family locks (`package-lock.json`, `npm-shrinkwrap.json`, `pnpm-lock.yaml`, `shrinkwrap.yaml`, `yarn.lock`, plus `.yarnrc.yml` for the berry cache-config gate and `bun.lock`), `requirements.txt` / `uv.lock` / `poetry.lock` (every Poetry lock generation from 1.0 on — the 0.12 `[metadata.hashes]` layout is refused because that installer ignores URL sources; a Poetry < 1.4 writer additionally gets `redirect_poetry_stale_install_risk`, see `docs/testing/poetry-compatibility.md`), `Cargo.toml` / `Cargo.lock` / `.cargo/config.toml` (plus the legacy extensionless `.cargo/config` — cargo reads that spelling in preference when both exist, so the managed `[registries.…]` block is written into whichever one is present), `composer.lock`, `nuget.config` / `packages.lock.json`, `Gemfile` / `Gemfile.lock`, `pom.xml` (+ `.mvn/maven.config` / `.mvn/checksums/checksums.sha256` for maven Trusted Checksums merge, and the Gradle build scripts read only to trigger the manual-snippet warning). **npm-family flavor coverage**: package-lock / npm-shrinkwrap, pnpm (root OR any nested `*/pnpm-lock.yaml`), yarn classic, **yarn berry** (`yarn.lock` entry only — `resolution: ::__archiveUrl=` + `yarnBerry10c0` checksum; cacheKey `10c0` and `.yarnrc.yml compressionLevel 0` gated by `redirect_yarn_berry_cache_unsupported`), and **bun** (text `bun.lock` lockfileVersion 1 or 2 — bun 1.3/1.4 share one emitted grammar; a binary `bun.lockb` with no text lock is auto-migrated to text via `bun install --save-text-lockfile --frozen-lockfile --lockfile-only` before the read, recorded as a `removed` FileEdit; `redirect_bun_lockb_would_migrate` on `--dry-run`, `redirect_bun_lockb_unsupported` when the migration is unavailable). **Rush monorepos**: when `rush.json` is present the rewriter also reads `common/config/rush/pnpm-lock.yaml` and each `common/config/subspaces//pnpm-lock.yaml` (sorted for determinism) under their repo-relative keys and repoints them in place; editing them emits `redirect_rush_repo_state_stale` when `common/config/rush/repo-state.json` exists (the `pnpmShrinkwrapHash` desync is refreshed by `rush update`, which the redirect survives). **maven** is fail-closed via version suffixing: a `mavenSuffixedVersion` + `mavenPomSha256` override pins the Socket-only `-socket.` by rewriting the literal `` (`redirect_maven_dep_version`) or adding a `` entry (`redirect_maven_dep_management_added`), plus optional Trusted Checksums (`redirect_maven_trusted_checksums`, conflicts as `redirect_maven_trusted_checksums_conflict`); a `${property}` version is refused (`redirect_maven_dep_unpinned`), a non-matching literal skipped (`redirect_maven_dep_version_mismatch`), and an override without a suffixed version falls back to same-GAV repository injection (`redirect_maven_same_gav_fallback`, NOT fail-closed). **Gem stale-install guard (additive warning — the canonical narrative; other mentions point here)**: the gem hosted rewrite is pure Gemfile/lock text, so a gem ALREADY materialized under the project's bundle paths keeps its upstream bytes — the next `bundle install` prints `Using ` and never refetches, on **every** bundler major (live-verified 2026-08-19 on 1.17.3 / 2.7.2 / 4.0.18: bundler 4's CHECKSUMS verify at download time only, and nothing is downloaded; `bundle install --force`/`--redownload` re-install from the stale cached `.gem` instead of re-fetching — bundler 1 silently, bundler 4 with an exit-37 checksum refusal that still leaves the upstream bytes installed; the **verified** remedy is removing the installed dir + cache `.gem` + `specifications` entry, then `bundle install`). After the rewrite, a hosted run therefore probes the installed-gem discovery paths (the same ruby-crawler discovery `apply` uses, honoring `--global`/`--global-prefix` like scan's own discovery) for each confirmed gem redirect and judges the materialization against the patch record's `afterHash` file map. Judgment rules: records are found **by uuid** — this run's fetched records first, then the redirect ledger's persisted ones, so a transiently failed `/patches/view` fetch cannot retire the warning (it re-fires on every re-scan until the stale materialization is gone); a materialization with every file at `afterHash` is already patched and never warns (an agent→hosted migration stays quiet by construction), and when several confirmed variant purls resolve to one installed dir, ANY of them judging it patched keeps it quiet; staleness needs **positive evidence** — at least one record file whose bytes were actually read and hash to neither state's expectation — so missing or unreadable files never produce a warning. Warnings emit `redirect_gem_stale_install` (JSON `redirect.warnings[]` + a code-tagged stderr line) in three flavors: a PROJECT-LOCAL dir gets the verified delete-list remedy (installed dir, cache `.gem`, `specifications` entry — plus the project's committed `vendor/cache/.gem` when present and not proven to be the patched artifact, since bundler installs from `vendor/cache` in preference to fetching); a SHARED gem-env home gets a caveat that the home is shared machine-wide and prefers migrating the project to a local bundle path over deleting shared files; and a committed `vendor/cache` archive whose sha256 differs from the patched artifact's warns standalone even with no installed dir at all (a fresh checkout with a committed stale cache re-materializes the upstream bytes forever). A stale-flagged purl is additionally **excluded from the same run's `--vex` `assume_applied` set** — the envelope must never attest a CVE its own warning says is live; the purl falls back to normal installed-tree verification (a patched install still attests, a stale one is omitted). The probe is read-only (nothing is deleted) and skipped on `--dry-run` — deliberately explicit, since nothing was rewritten but the ledger fallback could otherwise judge an already-redirected project. Exit code and `status` are unchanged (warning-only, the hosted-refusal posture); a same-run `--vex` may still fail on "nothing to attest" per the embedded-VEX contract. @@ -573,7 +573,7 @@ to **six flavors**. | composer | package dir `/@/` | `composer.lock` only: entry's `dist` → `{type: "path", url, reference: null}`, `source` removed, `transport-options: {symlink: false}` added. `content-hash` unaffected; `composer.json` untouched | `composer install` (from the lock alone, real copy not symlink, works under `--network none`). `composer update ` reverts it | | gem | gem dir `-/` + gemspec materialized from `specifications/` | **Gemfile + Gemfile.lock pair**: the `gem` line gains `path:` (or a managed block for transitive deps); the lock's spec block moves GEM→PATH and the DEPENDENCIES entry becomes ` (= )!`, in bundler's exact canonical form | `bundle install` (normal **and** `BUNDLE_FROZEN=true`), byte-stable lock. Lock-only edits are a silent unpatch — hence the mandatory pair | | pypi / uv (uv.lock) | rebuilt wheel (canonical PEP 427 filename; RECORD regenerated) | `[tool.uv.sources] = {path}` in pyproject + surgical uv.lock rewrite; transitive deps via `[tool.uv] override-dependencies` | `uv sync --locked` / `--frozen --offline` (hash-verified, byte-stable lock) | -| pypi / poetry (poetry.lock 2.0/2.1) | (rebuilt wheel) | lock-only: the target `[[package]]` gets `[package.source] type="file"` + `files = [{file, hash: sha256-of-our-wheel}]`. pyproject + `metadata.content-hash` untouched | `poetry check --lock && poetry sync`, cold cache (hash fail-closed; byte-stable lock) | +| pypi / poetry (poetry.lock: legacy `[metadata.hashes]`, lock 1.0/1.1 `[metadata.files]`, 2.x `files`) | (rebuilt wheel) | lock-only: the target `[[package]]` gets `[package.source] type="file"` (+ `reference = ""` on the 0.12/1.0 layouts, which read it unconditionally) and the single `{file, hash: sha256-of-our-wheel}` entry in whichever table the generation keeps it. pyproject + `metadata.content-hash` untouched; CRLF locks keep their line endings. A lock written by Poetry < 1.4 emits `pypi_poetry_integrity_unverified` (that installer verifies no local hashes and skips an already-installed version) | `poetry check --lock && poetry sync`, cold cache (hash fail-closed from Poetry 1.4; byte-stable lock) — see `docs/testing/poetry-compatibility.md` | | pypi / pdm (pdm.lock) | (rebuilt wheel) | lock-only: the `[[package]]` gains the local-file `path` + `files[]` hash. pyproject + `content_hash` untouched. Non-fixture `[metadata] strategy` / hash-less locks refused | `pdm sync` (+ `pdm install --check`), cold cache | | pypi / pipenv (Pipfile.lock) | (rebuilt wheel) | lock-only: the `default`/`develop` entry → `{file, hashes:[sha256-of-our-wheel]}`. Pipfile + `_meta.hash` untouched. Emits `vendor_integrity_unverified` — pipenv does not hash-check file entries; the committed wheel bytes are the protection | `pipenv install --deploy` (+ `pipenv verify`), cold cache | | pypi / requirements.txt (pip / `uv pip`) | (rebuilt wheel) | pin line → `./ --hash=sha256:` (markers carried over; transitive deps appended) | `pip install -r` / `uv pip install -r` **run from the project root** (both resolve bare paths against the CWD) | @@ -606,7 +606,7 @@ worse, lets a warm cache silently serve unpatched bytes): | npm / bun | the packages-entry trailing `sha512-…` | recomputed from the tarball; tamper fails the frozen install | | gem | `CHECKSUMS` section (bundler ≥ 2.6 opt-in) | the vendored gem's entry rewritten to bundler's own path-gem form (bare `name (ver)`, sha256 token stripped) so re-locks stay byte-stable; original line in the ledger | | pypi / uv | `wheels[].hash`, `sdist.hash`, requires-dist specifiers | single `{filename, hash: sha256-of-our-wheel}`; sdist dropped; dropped specifiers ledgered for revert | -| pypi / poetry | `files = [{file, hash}]` | replaced with a single `{file, hash: sha256-of-our-wheel}` (poetry verifies the artifact against one listed hash; stale registry hashes removed) | +| pypi / poetry | `files = [{file, hash}]` (2.x) / `[metadata.files]` entry (1.0/1.1) / `[metadata.hashes]` entry (0.12) | replaced with a single `{file, hash: sha256-of-our-wheel}` (or the bare hash for 0.12) in the generation's own table (Poetry ≥ 1.4 verifies the artifact against one listed hash; older writers are flagged `pypi_poetry_integrity_unverified`; stale registry hashes removed) | | pypi / pdm | `[[package]].files[]` hashes | replaced with our wheel's sha256; hash-less locks refused (`pypi_pdm_lock_no_hashes`) | | pypi / pipenv | per-entry `hashes[]` | replaced with `["sha256:"]` — but pipenv does **not** enforce hashes on file entries (`vendor_integrity_unverified` warning); the committed wheel bytes are the actual protection | | pypi / requirements | `--hash=sha256:` | fresh hash of the rebuilt wheel always emitted (turns on pip's hash-checking for the line) | @@ -1071,6 +1071,9 @@ Every `--json` invocation emits a single JSON object that follows the **unified | `vendor_lock_checksums_unsupported` / `vendor_stale_lock_checksum` | `failed` | vendor (gem): an ambiguous/platform CHECKSUMS entry, or a v1-wired lock whose stale token blocks the hot path (run `vendor --revert` + re-vendor). | | `redirect_gem_stale_install` | `redirect.warnings[]` (warning) | scan `--mode hosted` (gem): a stale UNPATCHED materialization (installed gem, or committed `vendor/cache` archive) that `bundle install` will reuse instead of fetching the redirected patch; the detail carries the verified remedy. Full rules and flavors: the "Gem stale-install guard" section. | | `pypi_{poetry,pdm,pipenv}_no_lockfile` | `failed` | vendor (pypi): a lock-less tool marker with no `requirements.txt` fallback — run ` lock`. | +| `pypi_poetry_integrity_unverified` | `skipped` (warning) | vendor (pypi / poetry): the lock was written by Poetry < 1.4 (0.12 `[metadata.hashes]`, lock 1.0/1.1, or a 2.0 lock without a `@generated by Poetry X.Y.Z` header — 1.3 wrote those). That installer does not verify local wheel hashes (the committed wheel bytes are the protection) and does not replace an already-installed package at the same version; recreate the virtualenv or `pip uninstall` the package before `poetry install`, or upgrade Poetry. | +| `redirect_poetry_stale_install_risk` | `redirect.warnings[]` (warning) | scan `--mode hosted` (poetry): same writer test as above — a warm virtualenv keeps the upstream package after the redirect on Poetry < 1.4 (1.4+ re-installs from the new source); fresh installs pick up the patched wheel. Emitted once per rewritten lock, only on the run that rewrites it. | +| `redirect_poetry_entry_not_found` / `redirect_poetry_missing_sha256` / `redirect_poetry_lock_unsupported` | `redirect.warnings[]` (warning) | scan `--mode hosted` (poetry): the lock has no `[[package]]` at the granted version (uv-parity twin of `redirect_uv_entry_not_found`); the grant carries no SHA-256 (gated once per dep, not per lock); the lock is refused — Poetry 0.12 layout (URL sources ignored), an unsupported `lock-version`, a forked package listed at several versions, a user-authored `[package.source]` on another origin (an earlier Socket URL for the same wheel is superseded in place), a malformed `[metadata.files]`/`[metadata.hashes]`, or a wheel whose filename does not match the locked package. Exit code and `status` unchanged (hosted-refusal posture). | | `vendor_prebuilt_stub_invalid` | `failed` / `skipped` (warning) | vendor (gem, `--vendor-source`): the served stub gemspec fails the rubygems `summary`/`authors` bar, so bundler would refuse the vendored path source at install time. `service`: refusal naming the missing attributes; `auto`: loud warning + local-build fallback — or, when the gem is also not installed locally (no stub to derive), a refusal naming the served defect and the install-the-gem remedy. | | `gem_spec_invalid` | `failed` | vendor (gem): the LOCAL `specifications/` stub gemspec fails the same rubygems `summary`/`authors` bar (a corrupted or hand-edited gem home); the refusal names the file — reinstall the gem (`gem pristine ` / fresh `bundle install`). | | `vendor_*` / `pypi_*` / `gemfile_*` / `lock_*` / `locked_version_mismatch` / `user_authored_*` / `native_extensions_unsupported` / `platform_gem_unsupported` | `failed`/`skipped` | vendor: per-ecosystem refusal + drift vocabulary; see the Vendor command contract section. New tags are additive (MINOR). | diff --git a/docs/testing/hosted-production-e2e.md b/docs/testing/hosted-production-e2e.md index b0817063..53aae87b 100644 --- a/docs/testing/hosted-production-e2e.md +++ b/docs/testing/hosted-production-e2e.md @@ -101,9 +101,13 @@ history of this demotion shows every piece to restore (catalog constants, preflight registration, the install-proof leg, and these tables) in both production suites. -PyPI's poetry / pdm / pipenv locks are **not** rewritten by hosted mode (see the +PyPI's pdm / pipenv locks are **not** rewritten by hosted mode (see the [matrix](../ecosystems.md#mode--ecosystem-matrix)); those flavors are vendored-mode -only, so there is no hosted leg to write for them. +only, so there is no hosted leg to write for them. `poetry.lock` IS rewritten +(Poetry 1.0+); its live coverage is the per-release matrix in +[poetry-compatibility.md](poetry-compatibility.md) (`scripts/backtest-poetry.py`), +which installs the redirected lock with every Poetry release rather than one +pinned installer, so it is not duplicated as a leg here. Two supported hosted shapes are deliberately **not** covered here: diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index fb7fd763..82091291 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -1,28 +1,171 @@ -# Poetry patches +# Poetry compatibility and production backtests -Hosted mode rewrites `poetry.lock` to a URL source. Vendored mode writes a local wheel source. Both retain the package version, dependencies, groups, markers, extras, and the pyproject content hash. No pyproject edits are required. Repeated scans leave the lock unchanged; rollback restores the recorded originals. A forked target, an existing unrelated source, an unsupported format, or a wheel/package mismatch is refused before writing. +`socket-patch` supports hosted and vendored Python patches in every +`poetry.lock` generation Poetry has written, and agent mode (in-place +patching of the project's virtualenv) on every Poetry release. The tests use +real Poetry releases bootstrapped with uv, real PyPI artifacts, and the public +Socket patch service. Successful rewriting alone is not an installation result: +the backtest reinstalls from the rewritten lock and compares the installed bytes +with the published patch. -The committed native locks cover Poetry 0.12.17, 1.0.10, 1.1.15, 1.2.2, 1.3.2, 1.4.2, 1.5.1, 1.6.1, 1.7.1, 1.8.5, 2.0.1, 2.1.4, 2.2.1, 2.3.4, and 2.4.3. They cover legacy `metadata.hashes`, `metadata.files` in lock 1.0/1.1, and package `files` in lock 2.0/2.1. +This supplements the [hosted](hosted-production-e2e.md) and +[vendored](vendored-production-e2e.md) production suites and mirrors the +[uv matrix](uv-compatibility.md). See the +[ecosystem matrix](../ecosystems.md#mode--ecosystem-matrix) for other package +managers. -| Poetry | Vendored | Hosted | Installer integrity | -| --- | --- | --- | --- | -| 0.12 | Supported | Refused: the installer ignores URL sources | Local wheel hashes are not checked by Poetry | -| 1.0 | Supported | Supported with a SHA-256 URL fragment | Hosted hashes are checked by pip; local wheel hashes are not checked | -| 1.1–1.3 | Supported | Supported | Hosted hashes are checked; local wheel hashes are not checked | -| 1.4–1.8 | Supported | Supported | Both modes reject mismatched lock hashes | -| 2.0–2.4 | Supported | Supported | Both modes reject mismatched lock hashes | +## Formats and rewrite behavior -Poetry 1.0 requires a `source.reference` even for archive sources and appends `#egg` unconditionally. Its hosted URL fragment therefore ends with a separator to preserve the SHA-256 parameter. Poetry 1.2 drops URL hashes from `metadata.files`; lock 1.1 hosted rewrites also write `package.files`, while retaining `metadata.files` for Poetry 1.1. +| Lock generation (writer) | Hosted (`scan --mode hosted`) | Vendored (`scan --mode vendored`) | +| --- | --- | --- | +| `[metadata.hashes]`, no `lock-version` (Poetry 0.12) | **Refused** (`redirect_poetry_lock_unsupported`): the installer ignores `[package.source] type = "url"` and installs the registry artifact, so a rewrite would attest a patch that never lands. | `[package.source] type = "file"` + `reference = ""` (read unconditionally by 0.12) and the wheel's SHA-256 in `[metadata.hashes]`. | +| `lock-version = "1.0"` (Poetry 1.0) | `type = "url"` + `reference = ""`; the URL carries `#sha256=&` because Poetry 1.0 appends `#egg=` unconditionally and pip ≥ 22 would otherwise read `#egg=…` as the digest. pip verifies the fragment; the `[metadata.files]` entry is written for consistency but is not consulted for URL sources. | `type = "file"` + `reference = ""`; `[metadata.files]` entry replaced. | +| `lock-version = "1.1"` (Poetry 1.1, 1.2) | `type = "url"`; the patched hash is written to BOTH `[metadata.files]` (what Poetry 1.1 verifies) and the package's own `files` (what Poetry 1.2 verifies — it drops URL hashes from `[metadata.files]`). | `type = "file"`; `[metadata.files]` entry replaced. | +| `lock-version = "2.0"` / `"2.1"` / any `"2."` (Poetry 1.3+) | `type = "url"`; `files = [{file, hash}]` replaced with the single patched wheel. | `type = "file"`; `files` replaced. LF 2.x locks keep Poetry's own multi-line `files` formatting; CRLF locks and legacy formats go through the shared toml_edit rewriter, which writes a single-line inline array. Both are valid TOML and byte-stable under `poetry check --lock`. | -The vendor warning `pypi_poetry_integrity_unverified` is emitted for lock formats readable by Poetry before 1.4. Upgrade the installer to at least 1.4 for local wheel hash enforcement. These older installers still install the patched bytes; the live backtest verifies the installed files against the patch record's SHA-256 Git blob hashes and separately records their inability to reject a changed lock hash. +Both modes retain the package version, dependencies, groups, markers, extras +and the pyproject `content-hash`; no pyproject edit is required. A repeated +scan leaves the lock unchanged. Rollback restores the recorded original +fragments — one per patch (plus the integrity-table entry on legacy formats), +so either of two patches can be rolled back first and unrelated edits survive. +Refused before any write: a `[[package]]` listed at several versions (marker +fork), a user-authored `[package.source]` on another origin (an earlier Socket +URL for the same wheel is superseded in place, e.g. after a grant-token +rotation), an unsupported `lock-version`, a malformed `[metadata.files]` / +`[metadata.hashes]` value, and a wheel whose filename does not match the +locked package. -Run the local Rust coverage: +## Installer boundaries (measured) + +| Poetry | Hosted | Vendored | Verifies the lock hash on install | Replaces an already-installed same-version package | +| --- | --- | --- | --- | --- | +| 0.12 | refused (URL sources ignored) | supported | no | no | +| 1.0 | supported (`#sha256=…&` fragment) | supported | hosted: yes (pip fragment); vendored: no | no | +| 1.1 – 1.3 | supported | supported | hosted: yes; vendored: no | **no** | +| 1.4 – 1.8 | supported | supported | yes / yes | yes | +| 2.0 – 2.4 | supported | supported | yes / yes | yes | + +Two consequences for Poetry releases before 1.4: + +- A **warm virtualenv keeps the upstream package** after the lock is rewritten: + `poetry install` compares installed packages by name and version only and + prints "No dependencies to install or update". Recreate the virtualenv (or + `pip uninstall` the package) before installing, or upgrade Poetry. Fresh + installs pick up the patched wheel on every release. The CLI flags this as + `redirect_poetry_stale_install_risk` (hosted) and + `pypi_poetry_integrity_unverified` (vendored), keyed on the lock's writer: + formats 0 / 1.0 / 1.1 are only written by pre-1.4 releases, and a lock 2.0 + whose header lacks a `@generated by Poetry X.Y.Z` version was written by 1.3 + (1.4+ stamp their version). A 2.0 lock stamped 1.4–1.8 is not flagged. +- Local (vendored) wheel hashes are **not verified**; the committed wheel bytes + are the protection — review them. Hosted URL hashes are verified on every + release from 1.0 on by the default installer (Poetry's deprecated pip backend, + `experimental.new-installer = false`, verifies nothing). + +Other measured details: + +- `poetry lock --no-update` (1.1–1.8) and bare `poetry lock` (2.x) keep the + patch source. Bare `poetry lock` on 0.12 / 1.0 (no `--no-update`), + `poetry lock --regenerate` (2.x), `poetry update` (with or without `--lock`) + and `poetry update ` — even when the version does not + change — drop the source and restore the registry hashes on every release. + `metadata.content-hash` is unchanged by that, so `poetry check --lock` / + `poetry lock --check` cannot detect the loss: re-run + `socket-patch scan --mode …` after any of them, or gate CI on `socket-patch vex`. +- Poetry 0.12 and 1.0 resolve a relative `type = "file"` path against the + shell's working directory, not the project root; run `poetry install` from + the project root on those releases. +- Poetry ≤ 1.1 stores its HTTP cache under the user cache directory regardless + of `POETRY_CACHE_DIR`, behind one lockfile that wedges parallel runs and stays + wedged after a SIGKILL; the harness gives each legacy case its own `HOME`. + +## Mode notes + +- **Agent mode** patches the interpreter the crawler finds: `VIRTUAL_ENV`, + `./.venv`, `./venv`, else — for a project directory — the global interpreter's + site-packages. Poetry's default virtualenv lives outside the project + (`virtualenvs.in-project` unset), so run the CLI as `poetry run socket-patch + scan` (Poetry exports `VIRTUAL_ENV`), export `VIRTUAL_ENV=$(poetry env info -p)`, + or pass `--global-prefix `; the matrix's out-of-tree leg + uses `poetry run`. A bare `socket-patch rollback` outside that context does not + see the venv either. Patched bytes survive `poetry install`, `poetry sync` and + `poetry install --sync` on every release (same version → no reinstall). +- **Vendored mode needs the package installed** (in the discovered virtualenv) + when it runs: the `poetry.lock` inventory is discovery-only, so a + lock-only checkout is skipped with `vendor_fetch_unverifiable` + + `package_not_installed` (uv's lock inventory carries integrity and vendors + lock-only). Commit the `.socket/vendor/` tree and rewired lock from the + machine that ran the scan; fresh clones then install from the committed wheel + with no CLI at all (verified by the matrix's fresh-clone leg). +- **Hosted mode works lock-only** (`redirected: 1` with no virtualenv). + +## Running the matrix ```sh -cargo test -p socket-patch-core --lib vendor::pypi_poetry -cargo test -p socket-patch-core --test poetry_hosted +cargo build -p socket-patch-cli +cp target/debug/socket-patch /tmp/socket-patch-under-test # rebuilds must not swap it mid-run +python3 scripts/backtest-poetry.py \ + --cli /tmp/socket-patch-under-test \ + --cli-revision "$(git rev-parse --short HEAD)" \ + --output /tmp/socket-patch-poetry-backtest \ + --modes hosted vendored agent agent-oot setup \ + --shapes direct populated crlf pep621 +python3 scripts/backtest-poetry.py --render-doc-table /tmp/socket-patch-poetry-backtest/summary.json ``` -The live installer harness is `tools/pipeline/poetry-patch-backtest.py` in SocketDev/depscan. It uses public PyPI and the real patch API, bootstraps the actual Poetry versions with uv, captures both CLI modes, checks repeat scans and unchanged lockfiles, verifies installed patch bytes, and tests tampered hashes. Its additional shapes cover dev dependencies, selected and excluded optional extras, Python markers, groups, PEP 621, transitive requests dependencies, and CRLF files. The edge inputs are derived from native locks; their content hashes are computed by the matching Poetry library before running the real installer. +The harness bootstraps every release in `VERSIONS` with uv (Python 3.8.20 for +0.12–1.1, 3.12.13 for 1.2+; Poetry 1.2.2 needs `cleo==1.0.0a5`), generates a +native lock for a one-dependency project (`urllib3 = "1.26.18"`, whose public +free-tier patch needs no token), and for each mode checks: exactly one patch +applied, pyproject untouched, idempotent re-scan, `poetry install` into an +emptied virtualenv installs bytes matching the patch record's `afterHash`, +`poetry check --lock`, a fresh clone of the committed state installs the patch, +`socket-patch vex` attests it, a corrupted hash is rejected where the installer +verifies, Poetry's own relock keeps the source, and `rollback` restores every +byte and clears the ledgers. Shapes: `direct` (the committed native fixture), +`populated` (legacy locks with real upstream hashes filled in — today's PyPI +JSON API leaves old Poetry's `[metadata.files]` empty), `crlf`, and `pep621` +(2.x `[project]` tables with `package-mode = false`). Modes `agent-oot` +(Poetry's default out-of-tree virtualenv via `poetry run`) and `setup` +(`socket-patch setup` on a Poetry project, then `poetry lock`) are +informational. + +Rust coverage of the rewriters: `cargo test -p socket-patch-core --lib +utils::poetry_lock vendor::pypi_poetry` and `cargo test -p socket-patch-core +--test poetry_hosted`. The committed native locks under +`crates/socket-patch-core/tests/fixtures/poetry//` are the harness's +`original/` inputs (same pyproject, same `content-hash`). + +## Results + + +| Poetry | hosted | vendored | agent (in-project venv) | agent (`poetry run`, out-of-tree venv) | tamper rejected (hosted / vendored) | warm venv re-installed (hosted / vendored) | relock keeps patch (hosted / vendored) | lock-only vendored | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0.12.17 | refused (0.x ignores URL sources) | pass (crlf,direct,populated) | pass (direct) | n/a | n/a / no | n/a / false | n/a / false | refused | +| 1.0.10 | pass (crlf,direct,populated) | pass (crlf,direct,populated) | pass (direct) | pass (direct) | yes / no | false / false | false / false | refused | +| 1.1.15 | pass (crlf,direct,populated) | pass (crlf,direct,populated) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused | +| 1.2.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused | +| 1.3.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused | +| 1.4.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 1.5.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 1.6.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 1.7.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 1.8.5 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 2.0.1 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 2.1.4 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 2.2.1 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 2.3.4 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 2.4.3 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | + -`poetry update` and lock regeneration can replace a patch source with an upstream source. Re-run Socket Patch after changing the dependency resolution. +Captured 2026-09-17 on macOS arm64 against the CLI at the PR head; 108 cases, +all passing (the `pass`/`refused` cells are the asserted outcomes, the +`tamper` / `warm venv` / `relock` / `lock-only vendored` columns are the +measured installer facts the sections above describe). The +[machine-readable results](poetry-compatibility/results.json) carry every +check, the CLI envelopes' relevant fields and the per-step exit codes. +`poetry lock` on 0.12 / 1.0 is bare (no `--no-update`), hence +`relock keeps patch = false` there. The companion SBOM annotation work and its +own capture set live in SocketDev/depscan (`tools/pipeline/poetry-patch-backtest.py`). From e72e679baeaf9dbe58071d0c516bf6770a91aa28 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:31:46 -0400 Subject: [PATCH 08/19] fix(pypi): discover Poetry's out-of-tree virtualenv in agent mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Poetry keeps a project's virtualenv OUTSIDE the project by default (`{cache-dir}/virtualenvs/--py`), so after a plain `poetry install` the crawler found no VIRTUAL_ENV / .venv / venv and fell through to the global interpreter's site-packages: `scan --mode agent` patched nothing for the project's dependencies (or the wrong interpreter) and reported success, and a bare `rollback` pruned the manifest while the venv stayed patched — measured on real Poetry 1.1.15, 1.8.5 and 2.4.3. The crawler now reproduces Poetry's own placement without running Poetry: `virtualenvs.create` / `in-project` / `path` and `cache-dir` from the `POETRY_*` environment, the project's `poetry.toml` and the user `config.toml` (Poetry's precedence), the platform default cache dir, the `{cache-dir}` / `{project-dir}` / `~` placeholders, and `EnvManager.generate_env_name` (lowercased sanitized name, 42-char cap, first 8 chars of url-safe base64 sha256 of normcase(realpath(cwd))) — unchanged from Poetry 1.0 through 2.x and pinned by known-answer vectors. Every `-py` sibling is scanned. A project-local venv still wins; a project that opted into in-project venvs or disabled creation is left to the existing paths. The matrix harness's out-of-tree leg now applies and rolls back BARE when the crawler sees the venv (falling back to `poetry run` otherwise) and records which path it took. Co-Authored-By: Claude Fable 5.1 --- .../src/crawlers/python_crawler.rs | 491 ++++++++++++++++++ scripts/backtest-poetry.py | 36 +- 2 files changed, 520 insertions(+), 7 deletions(-) diff --git a/crates/socket-patch-core/src/crawlers/python_crawler.rs b/crates/socket-patch-core/src/crawlers/python_crawler.rs index 88384486..be22628d 100644 --- a/crates/socket-patch-core/src/crawlers/python_crawler.rs +++ b/crates/socket-patch-core/src/crawlers/python_crawler.rs @@ -244,6 +244,8 @@ async fn find_site_packages_under( /// 1. `VIRTUAL_ENV` environment variable /// 2. `.venv` directory in `cwd` /// 3. `venv` directory in `cwd` +/// 4. Poetry's out-of-tree virtualenv(s) for a Poetry project (see +/// [`find_poetry_virtualenv_site_packages`]) pub async fn find_local_venv_site_packages(cwd: &Path) -> Vec { let mut results = Vec::new(); @@ -264,6 +266,320 @@ pub async fn find_local_venv_site_packages(cwd: &Path) -> Vec { results.extend(matches); } + // 3. Poetry keeps its virtualenv OUTSIDE the project by default, so a plain + // `poetry install` leaves nothing above to find and the crawl used to fall + // through to the global interpreter (patching the wrong site-packages, or + // nothing, and reporting success). + if results.is_empty() { + results.extend(find_poetry_virtualenv_site_packages(cwd).await); + } + + results +} + +/// Poetry's `virtualenvs.*` settings that decide where a project's virtualenv +/// lives. Precedence mirrors Poetry's: `POETRY_VIRTUALENVS_*` environment +/// variables, then the project-local `poetry.toml`, then the user +/// `config.toml`, then the defaults. +#[derive(Debug, Default, Clone, PartialEq, Eq)] +struct PoetryVirtualenvConfig { + /// `virtualenvs.create` — `false` means Poetry installs into the + /// interpreter it runs under (a container's system Python), which the + /// project-marker global fallback already covers. + create: Option, + /// `virtualenvs.in-project` — `true` means `./.venv`, already probed. + in_project: Option, + /// `virtualenvs.path` — may carry Poetry's `{cache-dir}` / + /// `{project-dir}` placeholders and a leading `~`. + path: Option, + /// `cache-dir` — the parent of the default `virtualenvs` root. + cache_dir: Option, +} + +impl PoetryVirtualenvConfig { + /// Layer `other` (lower precedence) under `self`: only unset keys take + /// the lower layer's value. + fn or(mut self, other: PoetryVirtualenvConfig) -> Self { + self.create = self.create.or(other.create); + self.in_project = self.in_project.or(other.in_project); + self.path = self.path.or(other.path); + self.cache_dir = self.cache_dir.or(other.cache_dir); + self + } + + fn from_env(var: impl Fn(&str) -> Option) -> Self { + let flag = |name: &str| { + var(name).map(|v| { + let v = v.trim().to_ascii_lowercase(); + matches!(v.as_str(), "1" | "true" | "yes" | "on") + }) + }; + Self { + create: flag("POETRY_VIRTUALENVS_CREATE"), + in_project: flag("POETRY_VIRTUALENVS_IN_PROJECT"), + path: var("POETRY_VIRTUALENVS_PATH").filter(|v| !v.trim().is_empty()), + cache_dir: var("POETRY_CACHE_DIR").filter(|v| !v.trim().is_empty()), + } + } + + /// `[virtualenvs]` (poetry.toml / config.toml) and the top-level + /// `cache-dir` key. A file that does not parse contributes nothing. + fn from_toml(text: &str) -> Self { + let Ok(doc) = text.parse::() else { + return Self::default(); + }; + let venvs = doc.get("virtualenvs").and_then(toml_edit::Item::as_table_like); + let get_bool = |key: &str| { + venvs.and_then(|t| t.get(key)).and_then(|item| { + item.as_bool().or_else(|| { + item.as_str().map(|s| { + matches!(s.trim().to_ascii_lowercase().as_str(), "1" | "true" | "yes" | "on") + }) + }) + }) + }; + Self { + create: get_bool("create"), + in_project: get_bool("in-project"), + path: venvs + .and_then(|t| t.get("path")) + .and_then(toml_edit::Item::as_str) + .map(str::to_string), + cache_dir: doc + .get("cache-dir") + .and_then(toml_edit::Item::as_str) + .map(str::to_string), + } + } +} + +/// The user-level Poetry config file, per Poetry's own lookup: +/// `$POETRY_CONFIG_DIR/config.toml`, else the platform config dir +/// (`~/Library/Application Support/pypoetry` on macOS, `$XDG_CONFIG_HOME` or +/// `~/.config` + `/pypoetry` elsewhere on unix, `%APPDATA%\pypoetry` on +/// Windows). +fn poetry_user_config_path(var: &impl Fn(&str) -> Option) -> Option { + if let Some(dir) = var("POETRY_CONFIG_DIR").filter(|v| !v.trim().is_empty()) { + return Some(PathBuf::from(dir).join("config.toml")); + } + let home = var("HOME").or_else(|| var("USERPROFILE")).map(PathBuf::from); + let dir = if cfg!(windows) { + var("APPDATA") + .map(PathBuf::from) + .or_else(|| home.map(|h| h.join("AppData").join("Roaming")))? + .join("pypoetry") + } else if cfg!(target_os = "macos") { + home?.join("Library").join("Application Support").join("pypoetry") + } else { + var("XDG_CONFIG_HOME") + .filter(|v| !v.trim().is_empty()) + .map(PathBuf::from) + .or_else(|| home.map(|h| h.join(".config")))? + .join("pypoetry") + }; + Some(dir.join("config.toml")) +} + +/// Poetry's default `cache-dir`: `~/Library/Caches/pypoetry` (macOS), +/// `$XDG_CACHE_HOME`/`~/.cache` + `/pypoetry` (other unix), +/// `%LOCALAPPDATA%\pypoetry\Cache` (Windows). +fn poetry_default_cache_dir(var: &impl Fn(&str) -> Option) -> Option { + let home = var("HOME").or_else(|| var("USERPROFILE")).map(PathBuf::from); + if cfg!(windows) { + Some( + var("LOCALAPPDATA") + .map(PathBuf::from) + .or_else(|| home.map(|h| h.join("AppData").join("Local")))? + .join("pypoetry") + .join("Cache"), + ) + } else if cfg!(target_os = "macos") { + Some(home?.join("Library").join("Caches").join("pypoetry")) + } else { + Some( + var("XDG_CACHE_HOME") + .filter(|v| !v.trim().is_empty()) + .map(PathBuf::from) + .or_else(|| home.map(|h| h.join(".cache")))? + .join("pypoetry"), + ) + } +} + +/// Poetry's virtualenv directory name for a project, minus the `-py` +/// suffix — `EnvManager.generate_env_name(name, cwd)`, unchanged from Poetry +/// 1.0 through 2.x: the lowercased project name with shell-hostile characters +/// replaced by `_` and truncated to 42 chars, a dash, then the first 8 chars +/// of the URL-safe base64 sha256 of `os.path.normcase(os.path.realpath(cwd))`. +/// `realpath` is resolved by the caller (`normalized_cwd` is the already +/// canonical path) so the pure function stays testable with fixed vectors. +fn poetry_env_name_prefix(project_name: &str, normalized_cwd: &str) -> String { + use base64::Engine as _; + use sha2::{Digest, Sha256}; + + let lowered = project_name.to_lowercase(); + let sanitized: String = lowered + .chars() + .map(|c| { + if matches!(c, ' ' | '$' | '`' | '!' | '*' | '@' | '"' | '\\' | '\r' | '\n' | '\t') { + '_' + } else { + c + } + }) + .take(42) + .collect(); + let digest = Sha256::digest(normalized_cwd.as_bytes()); + let hash = base64::engine::general_purpose::URL_SAFE.encode(digest); + format!("{sanitized}-{}", &hash[..8]) +} + +/// `os.path.normcase(os.path.realpath(cwd))` as Poetry hashes it: symlinks +/// resolved; on Windows lowercased with forward slashes turned into +/// backslashes, elsewhere unchanged. +fn poetry_normalized_cwd(cwd: &Path) -> String { + let real = std::fs::canonicalize(cwd).unwrap_or_else(|_| cwd.to_path_buf()); + let text = real.to_string_lossy().into_owned(); + if cfg!(windows) { + text.replace('/', "\\").to_lowercase() + } else { + text + } +} + +/// The project name Poetry derives its virtualenv name from: `[tool.poetry] +/// name`, else PEP 621 `[project] name`. Poetry canonicalizes it (PEP 503) — +/// both spellings are returned so a lock written before that normalization +/// still matches. +fn poetry_project_names(pyproject: &str) -> Vec { + let Ok(doc) = pyproject.parse::() else { + return Vec::new(); + }; + let raw = doc + .get("tool") + .and_then(|t| t.get("poetry")) + .and_then(|p| p.get("name")) + .and_then(toml_edit::Item::as_str) + .or_else(|| { + doc.get("project") + .and_then(|p| p.get("name")) + .and_then(toml_edit::Item::as_str) + }); + let Some(raw) = raw else { + return Vec::new(); + }; + let mut names = vec![canonicalize_pypi_name(raw)]; + if !names.contains(&raw.to_string()) { + names.push(raw.to_string()); + } + names +} + +/// The root directory Poetry would place this project's virtualenvs under, +/// or `None` when Poetry would not create one (`virtualenvs.create = false`, +/// `virtualenvs.in-project = true`, or no home to resolve the default against). +fn poetry_virtualenvs_root( + cwd: &Path, + config: &PoetryVirtualenvConfig, + var: &impl Fn(&str) -> Option, +) -> Option { + if config.create == Some(false) || config.in_project == Some(true) { + return None; + } + let cache_dir = config + .cache_dir + .as_deref() + .map(|c| expand_home(c, var)) + .or_else(|| poetry_default_cache_dir(var))?; + match config.path.as_deref() { + Some(template) => { + let expanded = template + .replace("{cache-dir}", &cache_dir.to_string_lossy()) + .replace("{project-dir}", &cwd.to_string_lossy()); + let path = expand_home(&expanded, var); + Some(if path.is_absolute() { + path + } else { + cwd.join(path) + }) + } + None => Some(cache_dir.join("virtualenvs")), + } +} + +fn expand_home(raw: &str, var: &impl Fn(&str) -> Option) -> PathBuf { + if let Some(rest) = raw.strip_prefix("~/").or_else(|| raw.strip_prefix("~\\")) { + if let Some(home) = var("HOME").or_else(|| var("USERPROFILE")) { + return PathBuf::from(home).join(rest); + } + } + if raw == "~" { + if let Some(home) = var("HOME").or_else(|| var("USERPROFILE")) { + return PathBuf::from(home); + } + } + PathBuf::from(raw) +} + +/// `site-packages` of every virtualenv Poetry created for the project at +/// `cwd` under its `virtualenvs.path` (`--py`; one per +/// interpreter minor the user ran `poetry env use` with). Empty for +/// non-Poetry projects and whenever Poetry's configuration says the +/// virtualenv is in-project, disabled, or unresolvable. Read-only: nothing is +/// executed, no `poetry` binary is needed. +pub async fn find_poetry_virtualenv_site_packages(cwd: &Path) -> Vec { + let var = |name: &str| std::env::var(name).ok(); + let has = |leaf: &str| cwd.join(leaf).is_file(); + let pyproject = match tokio::fs::read_to_string(cwd.join("pyproject.toml")).await { + Ok(text) => text, + Err(_) => return Vec::new(), + }; + let poetry_project = has("poetry.lock") || has("poetry.toml") || pyproject.contains("[tool.poetry"); + if !poetry_project { + return Vec::new(); + } + let names = poetry_project_names(&pyproject); + if names.is_empty() { + return Vec::new(); + } + let local = match tokio::fs::read_to_string(cwd.join("poetry.toml")).await { + Ok(text) => PoetryVirtualenvConfig::from_toml(&text), + Err(_) => PoetryVirtualenvConfig::default(), + }; + let user = match poetry_user_config_path(&var) { + Some(path) => match tokio::fs::read_to_string(&path).await { + Ok(text) => PoetryVirtualenvConfig::from_toml(&text), + Err(_) => PoetryVirtualenvConfig::default(), + }, + None => PoetryVirtualenvConfig::default(), + }; + let config = PoetryVirtualenvConfig::from_env(var).or(local).or(user); + let Some(root) = poetry_virtualenvs_root(cwd, &config, &var) else { + return Vec::new(); + }; + let normalized = poetry_normalized_cwd(cwd); + let prefixes: Vec = names + .iter() + .map(|name| format!("{}-py", poetry_env_name_prefix(name, &normalized))) + .collect(); + let Ok(mut entries) = tokio::fs::read_dir(&root).await else { + return Vec::new(); + }; + let mut venvs = Vec::new(); + while let Ok(Some(entry)) = entries.next_entry().await { + let file_name = entry.file_name(); + let Some(name) = file_name.to_str() else { + continue; + }; + if prefixes.iter().any(|prefix| name.starts_with(prefix)) { + venvs.push(entry.path()); + } + } + venvs.sort(); + let mut results = Vec::new(); + for venv in venvs { + results.extend(find_site_packages_under(&venv, "site-packages").await); + } results } @@ -739,6 +1055,181 @@ mod tests { use super::*; use crate::utils::purl::parse_pypi_purl; + // ── Poetry out-of-tree virtualenv discovery ───────────────────────────── + + /// Known-answer vectors computed with Poetry's own algorithm + /// (`EnvManager.generate_env_name`): lowercase, shell-hostile characters + /// to `_`, 42-char cap, `-`, first 8 chars of url-safe-b64(sha256(cwd)). + #[test] + fn poetry_env_name_prefix_matches_poetry_generate_env_name() { + assert_eq!( + poetry_env_name_prefix("poetry-patch-fixture", "/tmp/socket-patch-poetry-fixture"), + "poetry-patch-fixture-SmzYEVFn" + ); + assert_eq!( + poetry_env_name_prefix("My.Project", "/Users/dev/My Project"), + "my.project-0aTnNZ0w" + ); + let long = "a".repeat(60); + let prefix = poetry_env_name_prefix(&format!("we ird$name`{long}"), "/x"); + assert!(prefix.starts_with("we_ird_name_")); + assert_eq!(prefix.rsplit_once('-').unwrap().0.chars().count(), 42); + assert_eq!(prefix.rsplit_once('-').unwrap().1.len(), 8); + } + + #[test] + fn poetry_project_names_prefer_tool_poetry_and_return_both_spellings() { + assert_eq!( + poetry_project_names("[tool.poetry]\nname = \"Flask_Login\"\n[project]\nname = \"other\"\n"), + vec!["flask-login".to_string(), "Flask_Login".to_string()] + ); + assert_eq!( + poetry_project_names("[project]\nname = \"my-app\"\n[tool.poetry]\npackage-mode = false\n"), + vec!["my-app".to_string()] + ); + assert!(poetry_project_names("[tool.poetry]\nversion = \"1\"\n").is_empty()); + assert!(poetry_project_names("not toml [").is_empty()); + } + + #[test] + fn poetry_virtualenv_config_layers_and_templates() { + let local = PoetryVirtualenvConfig::from_toml( + "[virtualenvs]\nin-project = false\npath = \"{cache-dir}/venvs\"\n", + ); + let user = PoetryVirtualenvConfig::from_toml("cache-dir = \"/srv/poetry-cache\"\n[virtualenvs]\ncreate = false\n"); + let env = PoetryVirtualenvConfig::from_env(|k| match k { + "POETRY_VIRTUALENVS_CREATE" => Some("true".into()), + _ => None, + }); + let merged = env.or(local).or(user); + assert_eq!(merged.create, Some(true), "env beats config.toml"); + assert_eq!(merged.in_project, Some(false)); + assert_eq!(merged.path.as_deref(), Some("{cache-dir}/venvs")); + assert_eq!(merged.cache_dir.as_deref(), Some("/srv/poetry-cache")); + let var = |k: &str| match k { + "HOME" => Some("/home/dev".to_string()), + _ => None, + }; + let cwd = Path::new("/home/dev/proj"); + assert_eq!( + poetry_virtualenvs_root(cwd, &merged, &var), + Some(PathBuf::from("/srv/poetry-cache/venvs")) + ); + let project_local = PoetryVirtualenvConfig { + path: Some("{project-dir}/.envs".into()), + ..Default::default() + }; + assert_eq!( + poetry_virtualenvs_root(cwd, &project_local, &var), + Some(PathBuf::from("/home/dev/proj/.envs")) + ); + let tilde = PoetryVirtualenvConfig { + path: Some("~/venvs".into()), + ..Default::default() + }; + assert_eq!(poetry_virtualenvs_root(cwd, &tilde, &var), Some(PathBuf::from("/home/dev/venvs"))); + for disabled in [ + PoetryVirtualenvConfig { create: Some(false), ..Default::default() }, + PoetryVirtualenvConfig { in_project: Some(true), ..Default::default() }, + ] { + assert_eq!(poetry_virtualenvs_root(cwd, &disabled, &var), None); + } + // Defaults resolve against the platform cache dir; with no home at all + // there is nothing to resolve against. + let default = PoetryVirtualenvConfig::default(); + assert!(poetry_virtualenvs_root(cwd, &default, &var).is_some()); + assert_eq!(poetry_virtualenvs_root(cwd, &default, &|_: &str| None), None); + } + + /// End to end against the filesystem: a Poetry project with no `.venv` + /// finds the virtualenv(s) Poetry placed under `virtualenvs.path`, every + /// interpreter minor, and stops looking once the project opts into + /// `in-project` venvs. + #[tokio::test] + #[serial_test::serial] + async fn poetry_out_of_tree_virtualenvs_are_discovered_without_a_dot_venv() { + struct Guard(Vec<(&'static str, Option)>); + impl Guard { + fn new(overrides: &[(&'static str, Option<&str>)]) -> Self { + let prev = overrides + .iter() + .map(|(k, v)| { + let old = std::env::var(k).ok(); + match v { + Some(v) => std::env::set_var(k, v), + None => std::env::remove_var(k), + } + (*k, old) + }) + .collect(); + Guard(prev) + } + } + impl Drop for Guard { + fn drop(&mut self) { + for (k, old) in &self.0 { + match old { + Some(v) => std::env::set_var(k, v), + None => std::env::remove_var(k), + } + } + } + } + let tmp = tempfile::tempdir().unwrap(); + let project = tmp.path().join("proj"); + std::fs::create_dir_all(&project).unwrap(); + std::fs::write( + project.join("pyproject.toml"), + "[tool.poetry]\nname = \"Poetry_Patch.Fixture\"\nversion = \"0.1.0\"\n", + ) + .unwrap(); + std::fs::write(project.join("poetry.lock"), "[[package]]\nname = \"six\"\nversion = \"1.16.0\"\n[metadata]\nlock-version = \"2.1\"\n").unwrap(); + let venvs = tmp.path().join("venvs"); + let prefix = poetry_env_name_prefix("poetry-patch-fixture", &poetry_normalized_cwd(&project)); + let site = |venv: &Path, minor: &str| { + if cfg!(windows) { + venv.join("Lib").join("site-packages") + } else { + venv.join("lib").join(format!("python{minor}")).join("site-packages") + } + }; + let venv312 = venvs.join(format!("{prefix}-py3.12")); + let venv311 = venvs.join(format!("{prefix}-py3.11")); + let other = venvs.join("someone-else-AAAAAAAA-py3.12"); + for (venv, minor) in [(&venv312, "3.12"), (&venv311, "3.11"), (&other, "3.12")] { + std::fs::create_dir_all(site(venv, minor)).unwrap(); + } + let _guard = Guard::new(&[ + ("VIRTUAL_ENV", None), + ("POETRY_VIRTUALENVS_PATH", Some(venvs.to_str().unwrap())), + ("POETRY_VIRTUALENVS_IN_PROJECT", None), + ("POETRY_VIRTUALENVS_CREATE", None), + ("POETRY_CACHE_DIR", None), + ("POETRY_CONFIG_DIR", Some(tmp.path().join("no-config").to_str().unwrap())), + ]); + + let found = find_local_venv_site_packages(&project).await; + assert_eq!(found, vec![site(&venv311, "3.11"), site(&venv312, "3.12")], "{found:?}"); + + // A project-local `.venv` wins and the out-of-tree probe is skipped. + std::fs::create_dir_all(site(&project.join(".venv"), "3.12")).unwrap(); + assert_eq!(find_local_venv_site_packages(&project).await, vec![site(&project.join(".venv"), "3.12")]); + std::fs::remove_dir_all(project.join(".venv")).unwrap(); + + // `poetry.toml` opting into in-project venvs (or disabling creation) + // means Poetry never used the shared root: nothing is probed. + std::fs::write(project.join("poetry.toml"), "[virtualenvs]\nin-project = true\n").unwrap(); + assert!(find_local_venv_site_packages(&project).await.is_empty()); + std::fs::write(project.join("poetry.toml"), "[virtualenvs]\ncreate = false\n").unwrap(); + assert!(find_local_venv_site_packages(&project).await.is_empty()); + std::fs::remove_file(project.join("poetry.toml")).unwrap(); + + // Not a Poetry project (no lock, no [tool.poetry]): untouched. + std::fs::write(project.join("pyproject.toml"), "[project]\nname = \"poetry-patch-fixture\"\n").unwrap(); + std::fs::remove_file(project.join("poetry.lock")).unwrap(); + assert!(find_local_venv_site_packages(&project).await.is_empty()); + } + #[test] fn test_canonicalize_pypi_name_basic() { assert_eq!(canonicalize_pypi_name("Requests"), "requests"); diff --git a/scripts/backtest-poetry.py b/scripts/backtest-poetry.py index 02df804b..e383a98e 100755 --- a/scripts/backtest-poetry.py +++ b/scripts/backtest-poetry.py @@ -400,7 +400,13 @@ def check(name, value, note=None): if not oot_venv or not (oot_venv / "bin/python").exists(): raise RuntimeError("could not locate Poetry's out-of-tree venv: " + ep.out + ep.err) # 1. bare scan from the project dir, no VIRTUAL_ENV: does the CLI see the venv? - r1 = Run(cli_cmd(project, "scan", "--mode", "agent", "--dry-run"), project, env, case / "scan-bare-dryrun.log") + # The CLI inherits the user's Poetry configuration (the custom + # virtualenvs path below is configuration, not an activation) but + # not VIRTUAL_ENV — that is exactly what `poetry run` would add. + bare_env = dict(env) + for key in ("POETRY_VIRTUALENVS_PATH", "POETRY_CACHE_DIR", "POETRY_VIRTUALENVS_IN_PROJECT"): + bare_env[key] = penv[key] + r1 = Run(cli_cmd(project, "scan", "--mode", "agent", "--dry-run"), project, bare_env, case / "scan-bare-dryrun.log") e1 = r1.json_or_empty() paths = [p for p in (e1.get("paths") or [])] pkgs = e1.get("packages") or [] @@ -412,11 +418,25 @@ def check(name, value, note=None): "urllib3Found": any("urllib3" in (p.get("purl") or "") for p in pkgs), "packageDirs": [pth for p in pkgs for pth in (p.get("paths") or [])][:10], } - check("bareScanSeesPoetryVenv", any(str(oot_venv) in str(x) for x in json.dumps(e1).split('"')), "the CLI found the out-of-tree venv without help") - # 2. via `poetry run` (VIRTUAL_ENV set by Poetry) -> should patch the venv - r2 = Run([poetry, "run", *cli_cmd(project, "scan", "--mode", "agent")], project, penv, case / "scan-poetry-run.log") + # Did the bare dry-run see the package inside Poetry's venv (not + # merely list it lockfile-only)? A crawler that finds the venv reports + # urllib3 as installed with a patch to add; one that does not falls + # through to the global interpreter and reports it not installed. + sees = any( + "urllib3" in (p.get("purl") or "") and not p.get("notInstalled") + for p in pkgs + ) and e1.get("apply", {}).get("found", 0) >= 1 and not any( + ev.get("errorCode") == "package_not_installed" for ev in e1.get("apply", {}).get("patches", []) + ) + check("bareScanSeesPoetryVenv", sees, {"scannedPackages": e1.get("scannedPackages"), "found": e1.get("apply", {}).get("found")}) + # 2. apply for real: BARE when the crawler found the venv (the fixed + # CLI), else via `poetry run` (Poetry exports VIRTUAL_ENV). + bare = bool(sees) + info["applyPath"] = "bare" if bare else "poetry run" + cmd = cli_cmd(project, "scan", "--mode", "agent") if bare else [poetry, "run", *cli_cmd(project, "scan", "--mode", "agent")] + r2 = Run(cmd, project, bare_env if bare else penv, case / "scan-apply.log") e2 = r2.json_or_empty() - check("poetryRunScanApplied", applied_count("agent", e2) == 1, {"exit": r2.rc, "applied": applied_count("agent", e2)}) + check("poetryRunScanApplied", applied_count("agent", e2) == 1, {"exit": r2.rc, "applied": applied_count("agent", e2), "path": info["applyPath"]}) after, before, _ = record_hashes(project, "agent") if (project / ".socket/manifest.json").exists() else ({}, {}, None) res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-1.log") check("patchedViaPoetryRun", bool(after) and all(res.get(n) == h for n, h in after.items()), res) @@ -429,8 +449,10 @@ def check(name, value, note=None): rs = Run(sc, project, penv, case / "sync.log") res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-3.log") check("survivesSync", rs.ok() and bool(after) and all(res.get(n) == h for n, h in after.items()), {"exit": rs.rc, "oracle": res}) - # 4. rollback through poetry run - rb = Run([poetry, "run", *cli_cmd(project, "rollback")], project, penv, case / "rollback.log") + # 4. rollback the same way the patch was applied (bare when the + # crawler sees the venv; a bare rollback that cannot see it would + # prune the manifest while the venv stays patched) + rb = Run(cli_cmd(project, "rollback") if bare else [poetry, "run", *cli_cmd(project, "rollback")], project, bare_env if bare else penv, case / "rollback.log") res = oracle(oot_venv / "bin/python", list(after), project, case / "oracle-4.log") check("rollbackRestoresUpstream", rb.ok() and bool(before) and all(res.get(n) == h for n, h in before.items()), {"exit": rb.rc, "oracle": res}) check("rollbackClearsManifest", not (project / ".socket/manifest.json").exists() or json.loads((project / ".socket/manifest.json").read_text()).get("patches") == {}) From e44a53460528067a03a01b030dec82507bda2172 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:36:00 -0400 Subject: [PATCH 09/19] fix(pypi): vendor Poetry projects from a lock-only checkout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `scan --mode vendored` on a fresh clone (pyproject + poetry.lock, nothing installed) was skipped with `vendor_fetch_unverifiable` + `package_not_installed` although the lock records the wheel's sha256 — the poetry.lock inventory was discovery-only (`LockIntegrity::None`), so the fetch gate refused before the vendor engine ever ran, while the identical uv.lock scenario vendored fine. That broke the CI story for Poetry: the machine that vendors had to have the package installed. The inventory now carries the pure-Python (`-none-any.whl`) wheel's sha256 from `files` (lock 2.x) or `[metadata.files]` (lock 1.0/1.1), lowercased, and the pypi fetcher resolves a hash-only entry through PyPI's JSON API (`urls[].digests.sha256`, `SOCKET_PYPI_JSON_API` overrides the endpoint) and verifies the download against the same digest, exactly like uv's lock-only path. Poetry 0.12's bare `[metadata.hashes]` names no wheel, and platform-only wheels offer no platform-independent choice, so those stay discovery-only. Measured on the fixed CLI: lock-only vendoring now applies on Poetry 1.0 (populated lock), 1.2, 1.8 and 2.4 fixtures (`vendor_fetched_missing` + `vendor_prebuilt_downloaded`), and the resulting checkout installs the patched wheel with every release. Co-Authored-By: Claude Fable 5.1 --- .../src/vendor/lock_inventory.rs | 100 +++++++++++- .../src/vendor/registry_fetch.rs | 150 ++++++++++++++++-- 2 files changed, 236 insertions(+), 14 deletions(-) diff --git a/crates/socket-patch-core/src/vendor/lock_inventory.rs b/crates/socket-patch-core/src/vendor/lock_inventory.rs index 8ee9a9d0..5ba45798 100644 --- a/crates/socket-patch-core/src/vendor/lock_inventory.rs +++ b/crates/socket-patch-core/src/vendor/lock_inventory.rs @@ -1249,12 +1249,65 @@ fn python_lock_inventory(text: &str) -> Option> { Some(out) } -/// poetry.lock: `[[package]]` blocks with `name`/`version` — discovery -/// only (file hashes exist but carry no URLs and no platform choice). +/// The sha256 of each package's pure-Python (`-none-any.whl`) wheel as the +/// lock records it — `files = [...]` inside `[[package]]` (lock 2.x) or the +/// `[metadata.files]` entry (lock 1.0/1.1). Poetry 0.12's `[metadata.hashes]` +/// lists bare digests without filenames, so no wheel can be chosen there. +/// Keyed by canonical name. An unparseable lock contributes nothing (the +/// line-based name/version walk below still runs). +fn poetry_pure_wheel_hashes(text: &str) -> HashMap { + fn pure_wheel_sha(files: &Item) -> Option { + let files = files.as_array()?; + files + .iter() + .filter_map(TomlValue::as_inline_table) + .find_map(|entry| { + let file = entry.get("file")?.as_str()?; + if !file.ends_with("-none-any.whl") { + return None; + } + let sha = entry.get("hash")?.as_str()?.strip_prefix("sha256:")?; + is_hex_of_len(sha, 64).then(|| sha.to_ascii_lowercase()) + }) + } + let mut out = HashMap::new(); + let Ok(document) = text.parse::() else { + return out; + }; + if let Some(packages) = document.get("package").and_then(Item::as_array_of_tables) { + for package in packages.iter() { + let Some(name) = package.get("name").and_then(Item::as_str) else { + continue; + }; + if let Some(sha) = package.get("files").and_then(pure_wheel_sha) { + out.entry(canonicalize_pypi_name(name)).or_insert(sha); + } + } + } + if let Some(files) = document + .get("metadata") + .and_then(|m| m.get("files")) + .and_then(Item::as_table_like) + { + for (name, entry) in files.iter() { + if let Some(sha) = pure_wheel_sha(entry) { + out.entry(canonicalize_pypi_name(name)).or_insert(sha); + } + } + } + out +} + +/// poetry.lock: `[[package]]` blocks with `name`/`version`. The lock records +/// file hashes but no URLs and no platform choice, so an entry carries the +/// pure-Python wheel's sha256 when the lock lists one (the pypi fetcher then +/// resolves the matching file through PyPI's JSON API) and stays +/// discovery-only otherwise. async fn inventory_poetry_lock(project_root: &Path) -> Option> { let text = read_regular_to_string(&project_root.join("poetry.lock")) .await .ok()?; + let hashes = poetry_pure_wheel_hashes(&text); let mut out = Vec::new(); let mut in_package = false; let mut name: Option = None; @@ -1280,13 +1333,17 @@ async fn inventory_poetry_lock(project_root: &Path) -> Option if path_safety::is_safe_single_segment(&n) && path_safety::is_safe_single_segment(&v) { + let integrity = hashes + .get(&n) + .map(|sha| LockIntegrity::Sha256Hex(sha.clone())) + .unwrap_or(LockIntegrity::None); out.push(LockfileEntry { ecosystem: "pypi", purl: format!("pkg:pypi/{n}@{v}"), name: n, version: v, resolved: None, - integrity: LockIntegrity::None, + integrity, }); } } @@ -3225,6 +3282,43 @@ source = { editable = "." } assert_eq!(entries[0].purl, "pkg:pypi/requests@2.28.0"); } + /// A lock that lists a pure-Python wheel carries its sha256 (lock 2.x + /// `files`, lock 1.x `[metadata.files]`), so a lock-only checkout can + /// vendor like uv does; platform wheels only, or 0.12's bare + /// `[metadata.hashes]`, stay discovery-only. + #[tokio::test] + async fn poetry_lock_carries_the_pure_wheel_sha256_when_listed() { + let sha = "34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"; + let lock2 = format!( + "[[package]]\nname = \"urllib3\"\nversion = \"1.26.18\"\nfiles = [\n {{file = \"urllib3-1.26.18.tar.gz\", hash = \"sha256:{}\"}},\n {{file = \"urllib3-1.26.18-py2.py3-none-any.whl\", hash = \"sha256:{sha}\"}},\n]\n\n[[package]]\nname = \"numpy\"\nversion = \"2.0.0\"\nfiles = [\n {{file = \"numpy-2.0.0-cp312-cp312-macosx_11_0_arm64.whl\", hash = \"sha256:{}\"}},\n]\n\n[metadata]\nlock-version = \"2.1\"\n", + "f".repeat(64), + "e".repeat(64) + ); + let tmp = tempfile::tempdir().unwrap(); + write(tmp.path(), "poetry.lock", &lock2).await; + let entries = inventory_pypi_locks(tmp.path()).await.unwrap(); + assert_eq!(entry(&entries, "urllib3").integrity, LockIntegrity::Sha256Hex(sha.into())); + assert_eq!(entry(&entries, "urllib3").resolved, None); + assert_eq!(entry(&entries, "numpy").integrity, LockIntegrity::None); + + let lock1 = format!( + "[[package]]\nname = \"urllib3\"\nversion = \"1.26.18\"\n\n[metadata]\nlock-version = \"1.1\"\n\n[metadata.files]\nurllib3 = [\n {{file = \"urllib3-1.26.18-py2.py3-none-any.whl\", hash = \"sha256:{}\"}},\n]\n", + sha.to_uppercase() + ); + let tmp = tempfile::tempdir().unwrap(); + write(tmp.path(), "poetry.lock", &lock1).await; + let entries = inventory_pypi_locks(tmp.path()).await.unwrap(); + assert_eq!(entry(&entries, "urllib3").integrity, LockIntegrity::Sha256Hex(sha.into()), "lowercased"); + + let lock0 = format!( + "[[package]]\nname = \"urllib3\"\nversion = \"1.26.18\"\n\n[metadata]\ncontent-hash = \"x\"\n\n[metadata.hashes]\nurllib3 = [\"{sha}\"]\n" + ); + let tmp = tempfile::tempdir().unwrap(); + write(tmp.path(), "poetry.lock", &lock0).await; + let entries = inventory_pypi_locks(tmp.path()).await.unwrap(); + assert_eq!(entry(&entries, "urllib3").integrity, LockIntegrity::None, "bare digests name no wheel"); + } + #[tokio::test] async fn pnp_layouts_propagate_the_diagnosis_instead_of_yielding_none() { // PnP marker wins over any lockfile — and the diagnosis must diff --git a/crates/socket-patch-core/src/vendor/registry_fetch.rs b/crates/socket-patch-core/src/vendor/registry_fetch.rs index c87b4d22..c67b7048 100644 --- a/crates/socket-patch-core/src/vendor/registry_fetch.rs +++ b/crates/socket-patch-core/src/vendor/registry_fetch.rs @@ -290,16 +290,85 @@ async fn fetch_gem( /// wheel IS a site-packages layout (package dirs + `.dist-info/RECORD` at /// the root), which is exactly the shape the pypi vendor backend stages /// from. +/// PyPI's JSON API base; override with `SOCKET_PYPI_JSON_API` (tests point it +/// at a mock). Used only to turn a lock's file hash into a download URL for +/// locks that record hashes without URLs (poetry.lock). +pub const DEFAULT_PYPI_JSON_API: &str = "https://pypi.org/pypi"; + +fn pypi_json_api_base() -> String { + std::env::var("SOCKET_PYPI_JSON_API") + .ok() + .map(|v| v.trim_end_matches('/').to_string()) + .filter(|v| !v.is_empty()) + .unwrap_or_else(|| DEFAULT_PYPI_JSON_API.to_string()) +} + +/// Resolve the download URL of the release file whose sha256 the lock +/// records, via `GET ///json` → `urls[].digests.sha256`. +/// The hash, not the filename, selects the file, so a lock that names a wheel +/// PyPI has since re-uploaded under the same name cannot be satisfied by +/// different bytes — the download is still verified against the same hash. +async fn resolve_pypi_url_by_hash( + entry: &LockfileEntry, + sha256: &str, + client: &reqwest::Client, +) -> Result { + let api = format!( + "{}/{}/{}/json", + pypi_json_api_base(), + entry.name, + entry.version + ); + let resp = client.get(&api).send().await.map_err(|e| { + FetchError::Failed(format!("PyPI JSON API request for {} failed: {e}", entry.purl)) + })?; + if !resp.status().is_success() { + return Err(FetchError::Failed(format!( + "PyPI JSON API returned HTTP {} for {}", + resp.status(), + entry.purl + ))); + } + let body: serde_json::Value = resp.json().await.map_err(|e| { + FetchError::Failed(format!("PyPI JSON API response for {} is not JSON: {e}", entry.purl)) + })?; + body.get("urls") + .and_then(serde_json::Value::as_array) + .into_iter() + .flatten() + .find(|file| { + file.get("digests") + .and_then(|d| d.get("sha256")) + .and_then(serde_json::Value::as_str) + .is_some_and(|d| d.eq_ignore_ascii_case(sha256)) + }) + .and_then(|file| file.get("url").and_then(serde_json::Value::as_str)) + .map(str::to_string) + .ok_or_else(|| { + FetchError::Unverifiable(format!( + "no PyPI release file for {}@{} matches the lockfile's sha256 {sha256}", + entry.name, entry.version + )) + }) +} + async fn fetch_pypi( entry: &LockfileEntry, client: &reqwest::Client, ) -> Result { - let Some(url) = entry.resolved.clone() else { - return Err(FetchError::Unverifiable(format!( - "the lockfile records no platform-independent wheel URL for {}@{} (only uv.lock \ - carries fetchable wheel resolutions today)", - entry.name, entry.version - ))); + let url = match (&entry.resolved, &entry.integrity) { + (Some(url), _) => url.clone(), + // poetry.lock records the wheel's hash but no URL: look the file up + // by that hash (verified again after download). + (None, LockIntegrity::Sha256Hex(sha256)) => { + resolve_pypi_url_by_hash(entry, sha256, client).await? + } + (None, _) => { + return Err(FetchError::Unverifiable(format!( + "the lockfile records no platform-independent wheel URL or sha256 for {}@{}", + entry.name, entry.version + ))); + } }; let bytes = download(client, &url).await.map_err(FetchError::Failed)?; verify_integrity(&bytes, &entry.integrity)?; @@ -1747,14 +1816,71 @@ mod tests { .join("requests-2.28.0.dist-info/RECORD") .is_file()); - // No recorded wheel URL (poetry/requirements) → Unverifiable. + } + + /// poetry.lock records wheel hashes but no URLs: the fetcher resolves the + /// file through PyPI's JSON API by sha256 and still verifies the bytes. + #[tokio::test] + #[serial_test::serial] + async fn pypi_hash_only_entry_is_resolved_through_the_json_api() { + let wheel = make_zip(&[ + ("requests/__init__.py", b"__version__ = '2.28.0'\n"), + ("requests-2.28.0.dist-info/RECORD", b"requests/__init__.py,sha256=abc,24\n"), + ]); + let sha = hex::encode(Sha256::digest(&wheel)); + let mock = MockServer::start().await; + Mock::given(method("GET")) + .and(url_path("/packages/requests-2.28.0-py3-none-any.whl")) + .respond_with(ResponseTemplate::new(200).set_body_bytes(wheel)) + .mount(&mock) + .await; + Mock::given(method("GET")) + .and(url_path("/pypi/requests/2.28.0/json")) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "urls": [ + {"filename": "requests-2.28.0.tar.gz", "url": format!("{}/packages/requests-2.28.0.tar.gz", mock.uri()), "digests": {"sha256": "0".repeat(64)}}, + {"filename": "requests-2.28.0-py3-none-any.whl", "url": format!("{}/packages/requests-2.28.0-py3-none-any.whl", mock.uri()), "digests": {"sha256": sha.to_uppercase()}}, + ] + }))) + .mount(&mock) + .await; + let saved = std::env::var("SOCKET_PYPI_JSON_API").ok(); + std::env::set_var("SOCKET_PYPI_JSON_API", format!("{}/pypi/", mock.uri())); + let restore = || match &saved { + Some(v) => std::env::set_var("SOCKET_PYPI_JSON_API", v), + None => std::env::remove_var("SOCKET_PYPI_JSON_API"), + }; let entry = LockfileEntry { + ecosystem: "pypi", + name: "requests".into(), + version: "2.28.0".into(), + purl: "pkg:pypi/requests@2.28.0".into(), resolved: None, - integrity: LockIntegrity::Sha256Hex("0".repeat(64)), + integrity: LockIntegrity::Sha256Hex(sha.clone()), + }; + let fetched = fetch_and_stage(&entry, &build_registry_client()).await; + // A hash no release file carries is refused before any download. + let unknown = LockfileEntry { + integrity: LockIntegrity::Sha256Hex("1".repeat(64)), + ..entry.clone() + }; + let missing = fetch_and_stage(&unknown, &build_registry_client()).await; + // No hash at all: nothing to resolve by. + let bare = LockfileEntry { + integrity: LockIntegrity::Sri("sha512-x".into()), ..entry }; - match fetch_and_stage(&entry, &build_registry_client()).await { - Err(FetchError::Unverifiable(msg)) => assert!(msg.contains("wheel"), "{msg}"), + let bare_result = fetch_and_stage(&bare, &build_registry_client()).await; + restore(); + let fetched = fetched.unwrap(); + assert!(fetched.dir().join("requests/__init__.py").is_file()); + assert!(fetched.url.ends_with("requests-2.28.0-py3-none-any.whl")); + match missing { + Err(FetchError::Unverifiable(msg)) => assert!(msg.contains("matches"), "{msg}"), + other => panic!("expected Unverifiable, got {other:?}"), + } + match bare_result { + Err(FetchError::Unverifiable(msg)) => assert!(msg.contains("sha256"), "{msg}"), other => panic!("expected Unverifiable, got {other:?}"), } } @@ -1928,13 +2054,15 @@ mod tests { #[tokio::test] async fn pypi_no_wheel_url_message_is_single_spaced() { + // No URL and no sha256 to resolve one by (a sha256 would consult the + // PyPI JSON API — `pypi_hash_only_entry_is_resolved_through_the_json_api`). let entry = LockfileEntry { ecosystem: "pypi", name: "requests".into(), version: "2.28.0".into(), purl: "pkg:pypi/requests@2.28.0".into(), resolved: None, - integrity: LockIntegrity::Sha256Hex("0".repeat(64)), + integrity: LockIntegrity::Sri("sha512-x".into()), }; match fetch_and_stage(&entry, &build_registry_client()).await { Err(FetchError::Unverifiable(msg)) => assert!( From b7fbd98a974f199b38847678bcdfe52c416daced Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:36:00 -0400 Subject: [PATCH 10/19] docs(poetry): describe automatic virtualenv discovery and lock-only vendoring CHANGELOG Fixed bullets for the two pre-existing gaps the Poetry matrix surfaced (out-of-tree venv discovery, lock-only vendoring), the contract's pypi discovery-root sentence and `vendor_fetched_missing` row, and the compatibility doc's mode notes. Co-Authored-By: Claude Fable 5.1 --- CHANGELOG.md | 21 +++++++++++++ crates/socket-patch-cli/CLI_CONTRACT.md | 4 +-- docs/testing/poetry-compatibility.md | 39 +++++++++++++++---------- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdf41ff5..6170917b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -193,6 +193,27 @@ into the new version's section — see docs/releasing.md. ### Fixed +- **Agent mode finds Poetry's out-of-tree virtualenv.** Poetry keeps a + project's virtualenv under `{cache-dir}/virtualenvs/--py` + by default, so after a plain `poetry install` the crawler saw no + `VIRTUAL_ENV` / `.venv` / `venv` and fell through to the global interpreter: + `scan --mode agent` patched nothing for the project's dependencies (or the + wrong interpreter) while reporting success, and a bare `rollback` pruned the + manifest while the venv stayed patched. The crawler now reproduces Poetry's + own placement — `virtualenvs.create` / `in-project` / `path` and `cache-dir` + from `POETRY_*`, the project's `poetry.toml` and the user `config.toml`, the + platform default cache dir, and Poetry's env-name hash — without running + Poetry, and scans every `-py` sibling. `poetry run socket-patch …` and + `VIRTUAL_ENV` keep working as before. +- **`scan --mode vendored` works from a lock-only Poetry checkout.** The + `poetry.lock` inventory was discovery-only, so a fresh clone with nothing + installed was skipped with `vendor_fetch_unverifiable` even though the lock + records the wheel's sha256 (uv's lock vendored fine in the same scenario). + The inventory now carries the pure-Python wheel's sha256 from `files` (lock + 2.x) or `[metadata.files]` (lock 1.0/1.1), and the pypi fetcher resolves a + hash-only entry through PyPI's JSON API by that digest (verified again after + download; `SOCKET_PYPI_JSON_API` overrides the endpoint). Poetry 0.12's bare + `[metadata.hashes]` names no wheel and still needs an installed copy. - **`remove` no longer drops the manifest entry of a drift-kept vendored purl.** When the vendored revert keeps the artifact (`kept_artifact` — the lockfile drifted), the manifest entry is now kept too diff --git a/crates/socket-patch-cli/CLI_CONTRACT.md b/crates/socket-patch-cli/CLI_CONTRACT.md index 137f6997..1aea53e6 100644 --- a/crates/socket-patch-cli/CLI_CONTRACT.md +++ b/crates/socket-patch-cli/CLI_CONTRACT.md @@ -296,7 +296,7 @@ the model is **not uniform** today: One repo-root invocation discovers and configures every member. *Single level only* — see property 9's nested-workspace gap. - **cwd-only (single project):** gem, pypi, composer. The crawler inspects only the project - rooted at `--cwd` (pypi looks at `/.venv`; composer at the vendor tree); it does **not** + rooted at `--cwd` (pypi looks at `$VIRTUAL_ENV`, `/.venv` / `venv`, then a Poetry project's out-of-tree virtualenv(s) under Poetry's `virtualenvs.path`; composer at the vendor tree); it does **not** descend into sibling subprojects. A monorepo with several independent lockfiles in subdirectories (`backend/Gemfile.lock` + `frontend/Gemfile.lock`, multiple `.venv`, multiple `go.mod` / `composer.json`) is handled by invoking the tool **once per subproject** (`--cwd` each), as a @@ -1058,7 +1058,7 @@ Every `--json` invocation emits a single JSON object that follows the **unified | `vendor_override_conflict` | `failed` | vendor (pnpm/yarn-berry): a user-authored override/resolution for the package already exists. | | `vendor_integrity_unverified` | `skipped` (warning) | vendor (pipenv): the lockfile format does not hash-check file entries; the committed wheel bytes are the protection. | | `vendor_content_mismatch_overwritten` | `skipped` (warning) | vendor: a staged file matched NEITHER beforeHash nor afterHash (patch built against different bytes, or local edits); the stage was overwritten with the verified patched content and the vendor succeeded. | -| `vendor_fetched_missing` | `skipped` (warning) | vendor: the package was not installed; its pristine artifact was fetched per the lockfile resolution (or staged from the committed vendor artifact), integrity-verified, and vendored — the project tree was not touched. | +| `vendor_fetched_missing` | `skipped` (warning) | vendor: the package was not installed; its pristine artifact was fetched per the lockfile resolution (or staged from the committed vendor artifact), integrity-verified, and vendored — the project tree was not touched. For `poetry.lock` (which records hashes but no URLs) the pure-Python wheel's sha256 selects the file through PyPI's JSON API (`SOCKET_PYPI_JSON_API` overrides the endpoint); Poetry 0.12's bare `[metadata.hashes]` names no wheel, so those locks still need an installed copy (`vendor_fetch_unverifiable`). | | `vendor_fetch_failed` | `failed` | vendor: the lockfile-resolved fetch was attempted and failed (HTTP error, size cap, integrity mismatch, or a PRESENT-but-corrupt committed artifact — pointed at `socket-patch repair`). A MISSING committed artifact no longer lands here: it falls through to the ledger-recovered registry fetch. Suppresses the duplicate `package_not_installed` skip. | | `vendor_fetch_unverifiable` | `skipped` (warning) | vendor: the lockfile records no usable integrity for the missing package; nothing was fetched (fail-closed) and the `package_not_installed` skip follows. | | `vendor_artifact_missing` | `skipped` (warning) / `failed` | vendor: the committed artifact is gone — the registry resolution is recovered from the ledger and the artifact rebuilt (warning); repair `--offline` with no local source surfaces it as the per-entry failure instead. | diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index 82091291..62eb341d 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -82,21 +82,30 @@ Other measured details: ## Mode notes - **Agent mode** patches the interpreter the crawler finds: `VIRTUAL_ENV`, - `./.venv`, `./venv`, else — for a project directory — the global interpreter's - site-packages. Poetry's default virtualenv lives outside the project - (`virtualenvs.in-project` unset), so run the CLI as `poetry run socket-patch - scan` (Poetry exports `VIRTUAL_ENV`), export `VIRTUAL_ENV=$(poetry env info -p)`, - or pass `--global-prefix `; the matrix's out-of-tree leg - uses `poetry run`. A bare `socket-patch rollback` outside that context does not - see the venv either. Patched bytes survive `poetry install`, `poetry sync` and - `poetry install --sync` on every release (same version → no reinstall). -- **Vendored mode needs the package installed** (in the discovered virtualenv) - when it runs: the `poetry.lock` inventory is discovery-only, so a - lock-only checkout is skipped with `vendor_fetch_unverifiable` + - `package_not_installed` (uv's lock inventory carries integrity and vendors - lock-only). Commit the `.socket/vendor/` tree and rewired lock from the - machine that ran the scan; fresh clones then install from the committed wheel - with no CLI at all (verified by the matrix's fresh-clone leg). + `./.venv`, `./venv`, then — for a Poetry project — the virtualenv(s) Poetry + placed under its `virtualenvs.path` (`--py`; every + interpreter minor), reproducing Poetry's own placement from `POETRY_*`, the + project's `poetry.toml`, the user `config.toml` and the platform default + cache dir without running Poetry; else — for a project directory — the global + interpreter's site-packages. So a bare `socket-patch scan --mode agent` / + `rollback` in a default-configured Poetry checkout works; `poetry run + socket-patch …`, `VIRTUAL_ENV=$(poetry env info -p)` and + `--global-prefix ` keep working. `virtualenvs.create = false` + (containers) means Poetry installed into the system interpreter, which the + project-marker global fallback covers. Patched bytes survive + `poetry install`, `poetry sync` and `poetry install --sync` on every release + (same version → no reinstall). +- **Vendored mode works lock-only** for locks that list a pure-Python + (`-none-any.whl`) wheel for the package — lock 2.x `files`, lock 1.0/1.1 + `[metadata.files]`: the inventory carries that sha256 and the fetcher + resolves the file through PyPI's JSON API by digest, verifying the bytes + again, exactly like uv's lock-only path. Poetry 0.12's bare + `[metadata.hashes]` names no wheel, and a package that ships only platform + wheels has no platform-independent choice: those still need the package + installed in the discovered virtualenv (`vendor_fetch_unverifiable` + + `package_not_installed`). Fresh clones of the committed `.socket/vendor/` + tree and rewired lock install from the committed wheel with no CLI at all + (the matrix's fresh-clone leg). - **Hosted mode works lock-only** (`redirected: 1` with no virtualenv). ## Running the matrix From 6803e1334d5a1021a509692080a3776334e878a2 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:44:22 -0400 Subject: [PATCH 11/19] fix(poetry): verify lock-1.0 hosted wheels on Poetry >= 1.2 and name the pip window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - A lock-version 1.0 hosted rewrite only carried the patched hash in `[metadata.files]` and the URL fragment. Poetry >= 1.2 (which still reads 1.0 locks) verifies url sources against the package's own `files` and ignores `metadata.files` hashes, so it installed the hosted wheel with no hash check at all (measured on 1.2.2: every hash tampered, install exit 0). Write the package `files` entry for 1.0 too — Poetry 1.0.10 ignores the extra key (measured), 1.2.2 then rejects a tampered hash. - Poetry 1.0 installs url sources through pip, reading the hash from the URL fragment that Poetry suffixes with `#egg=`. Sweeping pip 20.3–25.0 with real Poetry 1.0.10: the `#sha256=&` spelling installs and verifies on pip <= 22.2 and >= 23.1; pip 22.3 and 23.0 (what Python 3.8's ensurepip seeds) take the rest of the fragment as part of the digest and refuse (fail-closed); without the `&` every pip >= 22.3 refuses. The spelling stays; the lock-1.0 hosted advisory now names the pip window and the compatibility doc records the sweep. - Pin each generation's hosted shape in `poetry_hosted` (1.0 fragment + reference + dual files, 1.1 dual files, 2.x metadata untouched) and drop duplicated lines from a vendored test. Co-Authored-By: Claude Fable 5.1 --- .../src/patch/redirect/poetry.rs | 57 ++++++++++++------- .../src/utils/poetry_lock.rs | 12 ++-- .../src/vendor/pypi_poetry.rs | 2 - .../socket-patch-core/tests/poetry_hosted.rs | 50 ++++++++++++++++ docs/testing/poetry-compatibility.md | 13 ++++- 5 files changed, 106 insertions(+), 28 deletions(-) diff --git a/crates/socket-patch-core/src/patch/redirect/poetry.rs b/crates/socket-patch-core/src/patch/redirect/poetry.rs index 96d395d9..5e9b7d23 100644 --- a/crates/socket-patch-core/src/patch/redirect/poetry.rs +++ b/crates/socket-patch-core/src/patch/redirect/poetry.rs @@ -18,14 +18,16 @@ use crate::utils::poetry_lock::{ /// serving the upstream bytes after the redirect. Formats `0`/`1.0`/`1.1` are /// only written by such releases; lock `2.0` is written by 1.3 through 1.8, so /// the `@generated by Poetry X.Y.Z` header (present from 1.4) decides there. -fn pre_1_4_writer(lock_text: &str) -> bool { - let Ok(lock) = lock_text.parse::() else { - return false; - }; +fn pre_1_4_writer(lock_text: &str) -> Option<&'static str> { + let lock = lock_text.parse::().ok()?; match lock_version(&lock) { - Ok("0" | "1.0" | "1.1") => true, - Ok("2.0") => !matches!(generated_by_version(lock_text), Some(v) if v >= (1, 4)), - _ => false, + Ok("0") => Some("0"), + Ok("1.0") => Some("1.0"), + Ok("1.1") => Some("1.1"), + Ok("2.0") if !matches!(generated_by_version(lock_text), Some(v) if v >= (1, 4)) => { + Some("2.0") + } + _ => None, } } @@ -89,19 +91,34 @@ pub(super) fn rewrite_poetry( } } content = rewritten; - if !stale_warned && pre_1_4_writer(&content) { - stale_warned = true; - result.warnings.push(RewriteWarning { - code: "redirect_poetry_stale_install_risk".into(), - detail: format!( - "{path} was written by Poetry < 1.4, which does not replace an \ - already-installed package at the same version: an existing \ - virtualenv keeps the upstream {} until it is recreated (or the \ - package is `pip uninstall`ed) before `poetry install`; fresh \ - installs pick up the patched wheel", - dep.name - ), - }); + if !stale_warned { + if let Some(format) = pre_1_4_writer(&content) { + stale_warned = true; + // Poetry 1.0 installs url sources through pip, which reads + // the hash from the URL fragment; pip 22.3–23.0 take the + // rest of the fragment (`&#egg=`, appended by Poetry) + // as part of the digest and refuse the install (measured; + // pip <= 22.2 and >= 23.1 install and verify). + let pip_note = if format == "1.0" { + " Poetry 1.0 installs through pip: pip 22.3–23.0 misparse the \ + hash fragment and refuse the install (fail-closed) — use pip \ + <= 22.2 or >= 23.1 in the virtualenv." + } else { + "" + }; + result.warnings.push(RewriteWarning { + code: "redirect_poetry_stale_install_risk".into(), + detail: format!( + "{path} was written by Poetry < 1.4, which does not replace \ + an already-installed package at the same version: an \ + existing virtualenv keeps the upstream {} until it is \ + recreated (or the package is `pip uninstall`ed) before \ + `poetry install`; fresh installs pick up the patched \ + wheel.{pip_note}", + dep.name + ), + }); + } } } // Already redirected to this artifact (idempotent re-scan). diff --git a/crates/socket-patch-core/src/utils/poetry_lock.rs b/crates/socket-patch-core/src/utils/poetry_lock.rs index ce21edeb..5a71cd2f 100644 --- a/crates/socket-patch-core/src/utils/poetry_lock.rs +++ b/crates/socket-patch-core/src/utils/poetry_lock.rs @@ -202,10 +202,14 @@ pub fn rewrite_poetry_lock( source.insert("reference", value("")); } package.insert("source", Item::Table(source)); - if format == "1.1" && source_type == "url" { - // Poetry 1.2 (a lock-1.1 writer) verifies url sources against the - // package's own `files`, Poetry 1.1 against `metadata.files` — write - // both so either installer enforces the patched hash. + if matches!(format.as_str(), "1.0" | "1.1") && source_type == "url" { + // Poetry >= 1.2 verifies url sources against the package's own + // `files` (it never reads `metadata.files` hashes for them), Poetry + // 1.0/1.1 against `metadata.files` — write both so whichever installer + // consumes this legacy lock enforces the patched hash. Poetry 1.0/1.1 + // ignore the extra package key (measured on 1.0.10; 1.2.2 rejects a + // tampered package `files` hash on a lock-1.0 file only when it is + // present). package.insert("files", value(files.clone())); } if format.starts_with('2') { diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index 34d9ec6b..2599f560 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -956,8 +956,6 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 second["version"] = toml_edit::value("1.16.0"); second.set_position(None); second.remove("extras"); - second.set_position(None); - second.remove("extras"); packages.push(second); for field in ["files", "hashes"] { if let Some(entries) = lock["metadata"].get_mut(field) { diff --git a/crates/socket-patch-core/tests/poetry_hosted.rs b/crates/socket-patch-core/tests/poetry_hosted.rs index 0cf77aa4..76cc3140 100644 --- a/crates/socket-patch-core/tests/poetry_hosted.rs +++ b/crates/socket-patch-core/tests/poetry_hosted.rs @@ -96,6 +96,56 @@ async fn native_lock_generations_redirect_idempotently_and_restore_every_byte() } } +/// The per-generation hosted shapes real Poetry releases were measured to +/// need: lock 1.0 gets `reference = ""` and the `#sha256=&` fragment +/// (Poetry 1.0 reads `reference` unconditionally and appends `#egg=`); lock +/// 1.1 gets the patched hash in BOTH the package `files` (what Poetry 1.2 +/// verifies) and `[metadata.files]` (what Poetry 1.1 verifies); 2.x gets the +/// package `files` only, with `[metadata]` untouched. +#[test] +fn hosted_shapes_match_each_lock_generations_installer() { + let sha = "a".repeat(64); + let lock10 = rewrite_registry_redirect( + &BTreeMap::from([("poetry.lock".to_string(), original("1.0.10"))]), + &[patch()], + ) + .files["poetry.lock"] + .clone(); + assert!(lock10.contains(&format!("url = \"{URL}#sha256={sha}&\"")), "{lock10}"); + assert!(lock10.contains("reference = \"\""), "{lock10}"); + assert!(lock10.contains(&format!("urllib3 = [{{ file = \"{WHEEL}\", hash = \"sha256:{sha}\" }}]")), "{lock10}"); + // Poetry >= 1.2 consuming this 1.0 lock verifies the package `files` + // entry, so it is written too (1.0 ignores the extra key). + assert_eq!(lock10.matches(&format!("sha256:{sha}")).count(), 2, "{lock10}"); + let doc: toml_edit::DocumentMut = lock10.parse().unwrap(); + assert!(doc["package"][0]["files"].is_array(), "{lock10}"); + + let lock11 = rewrite_registry_redirect( + &BTreeMap::from([("poetry.lock".to_string(), original("1.2.2"))]), + &[patch()], + ) + .files["poetry.lock"] + .clone(); + assert_eq!(lock11.matches(&format!("sha256:{sha}")).count(), 2, "package files + metadata.files:\n{lock11}"); + assert!(lock11.contains(&format!("url = \"{URL}\"")), "no fragment on 1.1"); + assert!(!lock11.contains("reference"), "{lock11}"); + let doc: toml_edit::DocumentMut = lock11.parse().unwrap(); + assert!(doc["package"][0]["files"].is_array()); + assert!(doc["metadata"]["files"]["urllib3"].is_array()); + + let lock21 = rewrite_registry_redirect( + &BTreeMap::from([("poetry.lock".to_string(), original("2.4.3"))]), + &[patch()], + ) + .files["poetry.lock"] + .clone(); + assert_eq!(lock21.matches(&format!("sha256:{sha}")).count(), 1, "{lock21}"); + assert!(!lock21.contains("reference")); + let pristine: toml_edit::DocumentMut = original("2.4.3").parse().unwrap(); + let doc: toml_edit::DocumentMut = lock21.parse().unwrap(); + assert_eq!(doc["metadata"].to_string(), pristine["metadata"].to_string(), "[metadata] untouched on 2.x"); +} + #[test] fn every_native_lock_generation_supports_file_sources() { for version in VERSIONS { diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index 62eb341d..6f21c42e 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -19,7 +19,7 @@ managers. | Lock generation (writer) | Hosted (`scan --mode hosted`) | Vendored (`scan --mode vendored`) | | --- | --- | --- | | `[metadata.hashes]`, no `lock-version` (Poetry 0.12) | **Refused** (`redirect_poetry_lock_unsupported`): the installer ignores `[package.source] type = "url"` and installs the registry artifact, so a rewrite would attest a patch that never lands. | `[package.source] type = "file"` + `reference = ""` (read unconditionally by 0.12) and the wheel's SHA-256 in `[metadata.hashes]`. | -| `lock-version = "1.0"` (Poetry 1.0) | `type = "url"` + `reference = ""`; the URL carries `#sha256=&` because Poetry 1.0 appends `#egg=` unconditionally and pip ≥ 22 would otherwise read `#egg=…` as the digest. pip verifies the fragment; the `[metadata.files]` entry is written for consistency but is not consulted for URL sources. | `type = "file"` + `reference = ""`; `[metadata.files]` entry replaced. | +| `lock-version = "1.0"` (Poetry 1.0) | `type = "url"` + `reference = ""`; the URL carries `#sha256=&` because Poetry 1.0 appends `#egg=` unconditionally (see the pip caveat below). pip verifies the fragment; the patched hash is also written to `[metadata.files]` (consistency) and to the package's own `files` (what Poetry ≥ 1.2 verifies when it consumes a 1.0 lock; 1.0 ignores the extra key). | `type = "file"` + `reference = ""`; `[metadata.files]` entry replaced. | | `lock-version = "1.1"` (Poetry 1.1, 1.2) | `type = "url"`; the patched hash is written to BOTH `[metadata.files]` (what Poetry 1.1 verifies) and the package's own `files` (what Poetry 1.2 verifies — it drops URL hashes from `[metadata.files]`). | `type = "file"`; `[metadata.files]` entry replaced. | | `lock-version = "2.0"` / `"2.1"` / any `"2."` (Poetry 1.3+) | `type = "url"`; `files = [{file, hash}]` replaced with the single patched wheel. | `type = "file"`; `files` replaced. LF 2.x locks keep Poetry's own multi-line `files` formatting; CRLF locks and legacy formats go through the shared toml_edit rewriter, which writes a single-line inline array. Both are valid TOML and byte-stable under `poetry check --lock`. | @@ -40,7 +40,7 @@ locked package. | Poetry | Hosted | Vendored | Verifies the lock hash on install | Replaces an already-installed same-version package | | --- | --- | --- | --- | --- | | 0.12 | refused (URL sources ignored) | supported | no | no | -| 1.0 | supported (`#sha256=…&` fragment) | supported | hosted: yes (pip fragment); vendored: no | no | +| 1.0 | supported (`#sha256=…&` fragment; pip ≤ 22.2 or ≥ 23.1) | supported | hosted: yes (pip fragment); vendored: no | no | | 1.1 – 1.3 | supported | supported | hosted: yes; vendored: no | **no** | | 1.4 – 1.8 | supported | supported | yes / yes | yes | | 2.0 – 2.4 | supported | supported | yes / yes | yes | @@ -57,6 +57,15 @@ Two consequences for Poetry releases before 1.4: formats 0 / 1.0 / 1.1 are only written by pre-1.4 releases, and a lock 2.0 whose header lacks a `@generated by Poetry X.Y.Z` version was written by 1.3 (1.4+ stamp their version). A 2.0 lock stamped 1.4–1.8 is not flagged. +- **Poetry 1.0 installs URL sources through pip**, which reads the hash from the + URL fragment. Poetry appends `#egg=` to every URL, so the rewrite ends the + fragment with `&` to keep `sha256=` intact. Measured across pip releases: + pip 20.3 – 22.2 and 23.1+ install and verify the patched wheel with that + spelling; pip 22.3 and 23.0 (the pip Python 3.8's `ensurepip` seeds) treat the + trailing `&#egg=…` as part of the digest and refuse the install (fail-closed, + nothing installed) — no fragment spelling satisfies them, so upgrade or + downgrade pip inside the virtualenv. Without the `&`, every pip ≥ 22.3 refuses. + The hosted advisory names this window for lock 1.0. - Local (vendored) wheel hashes are **not verified**; the committed wheel bytes are the protection — review them. Hosted URL hashes are verified on every release from 1.0 on by the default installer (Poetry's deprecated pip backend, From b7a4254f60c0e4ff3b84ac68adaf8123facfc7b3 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:44:22 -0400 Subject: [PATCH 12/19] fix(vex): attest same-run hosted redirects whose ledger purl carries a qualifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `scan --mode hosted --vex` exempts the purls the run just confirmed from installed-tree verification and attests them from the redirect ledger (`assume_applied`). The confirmed purls come from the grant reference unqualified (`pkg:pypi/urllib3@1.26.18`) while the ledger records the API's artifact-qualified purl (`…?artifact_id=py2-py3-none-any-whl`), so for pypi redirects nothing matched: a lock-only Poetry (or uv) checkout redirected the lock and then exited 1 with `no_applicable_patches`. Match on the qualifier-stripped purl on both sides. Adds the first CLI-level Poetry hosted test: a lock-only project is redirected, attested in the same run, re-scanned idempotently, and rolled back byte for byte against a mocked API. Co-Authored-By: Claude Fable 5.1 --- crates/socket-patch-cli/src/commands/vex.rs | 23 +- .../tests/in_process_redirect_poetry.rs | 233 ++++++++++++++++++ 2 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 crates/socket-patch-cli/tests/in_process_redirect_poetry.rs diff --git a/crates/socket-patch-cli/src/commands/vex.rs b/crates/socket-patch-cli/src/commands/vex.rs index beda9b55..9e7d5015 100644 --- a/crates/socket-patch-cli/src/commands/vex.rs +++ b/crates/socket-patch-cli/src/commands/vex.rs @@ -397,12 +397,23 @@ async fn generate_vex( // record the run did not re-confirm (a reverted lockfile or a withdrawn // patch must not keep attesting). if !params.assume_applied.is_empty() { - let exempt: std::collections::HashSet<&str> = - params.assume_applied.iter().map(|s| s.as_str()).collect(); - outcome.failed.retain(|f| !exempt.contains(f.purl.as_str())); - for purl in ¶ms.assume_applied { - if manifest.patches.contains_key(purl) && !outcome.applied.iter().any(|p| p == purl) { - outcome.applied.push(purl.clone()); + use socket_patch_core::utils::purl::strip_purl_qualifiers; + // The confirmed purls come from the grant reference (unqualified — + // `pkg:pypi/urllib3@1.26.18`) while the ledger records the API's + // artifact-qualified purl (`…?artifact_id=py2-py3-none-any-whl`), so + // match on the qualifier-stripped form: a lock-only pypi redirect used + // to attest nothing and fail the same-run `--vex` with + // `no_applicable_patches`. + let exempt: std::collections::HashSet<&str> = params + .assume_applied + .iter() + .map(|s| strip_purl_qualifiers(s)) + .collect(); + let is_exempt = |purl: &str| exempt.contains(strip_purl_qualifiers(purl)); + outcome.failed.retain(|f| !is_exempt(&f.purl)); + for key in manifest.patches.keys() { + if is_exempt(key) && !outcome.applied.iter().any(|p| p == key) { + outcome.applied.push(key.clone()); } } } diff --git a/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs b/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs new file mode 100644 index 00000000..46d1cd3d --- /dev/null +++ b/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs @@ -0,0 +1,233 @@ +//! In-process CLI test for `scan --mode hosted` on a Poetry project: mocks the +//! API (discovery + reference + view) via wiremock, lays down a native +//! `poetry.lock` (the committed Poetry 2.4.3 fixture) with NO installed +//! package — the lock-only fresh-checkout / CI shape — and asserts the lock is +//! repointed at the hosted wheel, the redirect ledger is written, the same-run +//! `--vex` attests the redirect, a re-scan is idempotent, and `rollback` +//! restores every byte. The rewriter bytes themselves are pinned by the core +//! `poetry_hosted` tests; this covers the CLI wiring around them. + +use std::path::Path; + +use serial_test::serial; +use socket_patch_cli::args::GlobalArgs; +use socket_patch_cli::commands::rollback::{self, RollbackArgs}; +use socket_patch_cli::commands::scan::{run, ScanArgs}; +use socket_patch_cli::commands::vex::VexEmbedArgs; +use wiremock::matchers::{method, path, path_regex}; +use wiremock::{Mock, MockServer, ResponseTemplate}; + +const ORG: &str = "test-org"; +/// Discovery names the base purl (the lockfile supplement's spelling)… +const PURL: &str = "pkg:pypi/urllib3@1.26.18"; +/// …while the patch record carries the API's artifact-qualified purl, which +/// is what the redirect ledger is keyed by. +const RECORD_PURL: &str = "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl"; +const UUID: &str = "e828efa5-5c6d-43f3-9909-03f5ac232b98"; +const HOSTED_URL: &str = "http://patch.test/patch/pypi/urllib3/1.26.18/22222222-2222-4222-8222-222222222222/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl"; +const GHSA: &str = "GHSA-gm62-xv2j-4w53"; + +const LOCK: &str = include_str!("../../socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock"); +const PYPROJECT: &str = + include_str!("../../socket-patch-core/tests/fixtures/poetry/2.4.3/pyproject.toml"); + +fn sha256() -> String { + "c".repeat(64) +} + +fn global(cwd: &Path, api_url: String) -> GlobalArgs { + GlobalArgs { + cwd: cwd.to_path_buf(), + org: Some(ORG.to_string()), + api_token: Some("fake".to_string()), + api_url: Some(api_url), + json: true, + yes: true, + ..GlobalArgs::default() + } +} + +fn hosted_args(cwd: &Path, api_url: String, vex: Option<&Path>) -> ScanArgs { + ScanArgs { + paths: Vec::new(), + common: global(cwd, api_url), + batch_size: 100, + apply: false, + prune: false, + sync: false, + vendor: false, + detached: false, + redirect: true, + mode: None, + all_releases: false, + vex: VexEmbedArgs { + vex: vex.map(Path::to_path_buf), + ..Default::default() + }, + } +} + +async fn mock_api(server: &MockServer) { + Mock::given(method("POST")) + .and(path(format!("/v0/orgs/{ORG}/patches/batch"))) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "packages": [{ + "purl": PURL, + "patches": [{ + "uuid": UUID, "purl": RECORD_PURL, "tier": "free", + "cveIds": ["CVE-2025-66418"], "ghsaIds": [GHSA], "severity": "HIGH", + "title": "poetry redirect fixture" + }] + }], + "canAccessPaidPatches": false, + }))) + .mount(server) + .await; + Mock::given(method("GET")) + .and(path_regex(format!("^/v0/orgs/{ORG}/patches/by-package/.+$"))) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "patches": [{ + "uuid": UUID, "purl": RECORD_PURL, + "publishedAt": "2026-07-29T20:20:47Z", + "description": "x", "license": "MIT", "tier": "free", + "vulnerabilities": {} + }], + "canAccessPaidPatches": false, + }))) + .mount(server) + .await; + Mock::given(method("POST")) + .and(path(format!("/v0/orgs/{ORG}/patches/package"))) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "results": { + UUID: { + "status": "granted", + "url": HOSTED_URL, + "purl": PURL, + "artifacts": [{ + "kind": "tarball", + "url": HOSTED_URL, + "integrity": { "sha256": sha256() } + }], + "registryOverride": null + } + } + }))) + .mount(server) + .await; + Mock::given(method("GET")) + .and(path(format!("/v0/orgs/{ORG}/patches/view/{UUID}"))) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "uuid": UUID, + "purl": RECORD_PURL, + "publishedAt": "2026-07-29T20:20:47Z", + "files": { + "urllib3/response.py": { + "beforeHash": "a".repeat(64), + "afterHash": "b".repeat(64), + } + }, + "vulnerabilities": { + GHSA: { + "cves": ["CVE-2025-66418"], + "summary": "poetry redirect vex fixture", + "severity": "HIGH", + "description": "d" + } + }, + "description": "x", "license": "MIT", "tier": "free" + }))) + .mount(server) + .await; +} + +/// A Poetry project with nothing installed: the lock is the only source of +/// the dependency. An EMPTY in-project venv keeps the crawl hermetic (without +/// it the project-marker fallback would walk this machine's global +/// interpreters). +fn write_project(root: &Path) { + std::fs::write(root.join("pyproject.toml"), PYPROJECT).unwrap(); + std::fs::write(root.join("poetry.lock"), LOCK).unwrap(); + let site = if cfg!(windows) { + root.join(".venv").join("Lib").join("site-packages") + } else { + root.join(".venv").join("lib").join("python3.12").join("site-packages") + }; + std::fs::create_dir_all(site).unwrap(); +} + +fn read(path: &Path) -> String { + std::fs::read_to_string(path).unwrap() +} + +#[tokio::test] +#[serial] +async fn lock_only_poetry_project_redirects_attests_rescans_and_rolls_back() { + let server = MockServer::start().await; + mock_api(&server).await; + let tmp = tempfile::tempdir().unwrap(); + write_project(tmp.path()); + let lock_path = tmp.path().join("poetry.lock"); + let vex_path = tmp.path().join("out.vex.json"); + + // 1. Hosted redirect with same-run --vex on the lock-only checkout. + let code = run(hosted_args(tmp.path(), server.uri(), Some(&vex_path))).await; + assert_eq!(code, 0, "hosted redirect + same-run vex must succeed"); + let redirected = read(&lock_path); + assert!(redirected.contains(HOSTED_URL), "{redirected}"); + assert!( + redirected.contains(&format!("hash = \"sha256:{}\"", sha256())), + "{redirected}" + ); + assert!(redirected.contains("type = \"url\""), "{redirected}"); + assert_eq!(read(&tmp.path().join("pyproject.toml")), PYPROJECT, "pyproject untouched"); + let ledger: serde_json::Value = + serde_json::from_str(&read(&tmp.path().join(".socket/vendor/redirect-state.json"))) + .unwrap(); + assert!( + ledger["records"][RECORD_PURL].is_object(), + "ledger keyed by the artifact-qualified purl: {ledger}" + ); + assert_eq!( + ledger["edits"][0]["kind"].as_str(), + Some("redirect_poetry_lock_package"), + "{ledger}" + ); + // The redirect is attested from the ledger (assume_applied) even though + // the base purl the run confirmed differs from the record's qualified + // purl only by its `?artifact_id=` qualifier. + let vex: serde_json::Value = serde_json::from_str(&read(&vex_path)).unwrap(); + let statements = vex["statements"].as_array().expect("statements"); + assert_eq!(statements.len(), 1, "{vex}"); + assert_eq!( + statements[0]["vulnerability"]["name"].as_str(), + Some(GHSA), + "{vex}" + ); + + // 2. Idempotent re-scan: no further edits, lock byte-identical. + let code = run(hosted_args(tmp.path(), server.uri(), None)).await; + assert_eq!(code, 0); + assert_eq!(read(&lock_path), redirected, "re-scan must not touch the lock"); + + // 3. rollback unwinds the redirect and drops the record. + let code = rollback::run(RollbackArgs { + targets: Vec::new(), + common: global(tmp.path(), server.uri()), + one_off: false, + preserve_state: false, + }) + .await; + assert_eq!(code, 0, "rollback must succeed"); + assert_eq!(read(&lock_path), LOCK, "rollback must restore the pristine lock byte for byte"); + let ledger_path = tmp.path().join(".socket/vendor/redirect-state.json"); + if ledger_path.exists() { + let ledger: serde_json::Value = serde_json::from_str(&read(&ledger_path)).unwrap(); + assert!( + ledger["records"] + .as_object() + .is_none_or(|records| records.is_empty()), + "no redirect record may survive rollback: {ledger}" + ); + } +} From 08030bd15224f25d9e89ec91c49e3e7ea4e6e31c Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:47:55 -0400 Subject: [PATCH 13/19] fix(vendor): let only fragment drift hold the atomic lock revert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `revert_lock_fragment_splice_atomic` held the write whenever ANY warning was raised, so a record this build cannot replay (a newer ledger's unknown kind, or a foreign file skipped by the allowlist) blocked restoring the fragments it does understand — the lock stayed fully wired while the revert reported success. Track drift separately: a drifted fragment still holds the whole write (a half-restored legacy lock is uninstallable), forward-compat skips only warn. Also documents that `poetry lock --no-update` on Poetry 1.1/1.2 reshapes a hosted entry and drops the package-level files Poetry >= 1.2 verifies against. Co-Authored-By: Claude Fable 5.1 --- crates/socket-patch-core/src/vendor/common.rs | 17 ++++- .../src/vendor/pypi_poetry.rs | 74 +++++++++++++++++++ docs/testing/poetry-compatibility.md | 5 ++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/crates/socket-patch-core/src/vendor/common.rs b/crates/socket-patch-core/src/vendor/common.rs index 1442735c..2e23077d 100644 --- a/crates/socket-patch-core/src/vendor/common.rs +++ b/crates/socket-patch-core/src/vendor/common.rs @@ -402,6 +402,13 @@ pub(crate) async fn revert_lock_fragment_splice( .await } +/// [`revert_lock_fragment_splice`] for backends whose records are COUPLED +/// (poetry's legacy formats write the `[package.source]` table and the +/// `[metadata.files]` entry as two fragments): when any recorded fragment has +/// drifted, nothing is written — a half-restored lock (registry hashes with a +/// vendored source, or the reverse) is worse than the wired one. Records this +/// build does not recognize are skipped with a warning as usual and do not +/// hold the write. pub(crate) async fn revert_lock_fragment_splice_atomic( entry: &VendorEntry, root: &Path, @@ -442,6 +449,13 @@ async fn revert_lock_fragment_splice_inner( Err(e) => return RevertOutcome::failed(format!("cannot read {lock_file}: {e}")), }; let mut warnings: Vec = Vec::new(); + // Set when a recorded fragment is neither present nor already restored: + // the only condition under which the atomic flavor must hold the write + // (restoring the source table while its integrity entry stays patched, or + // vice versa, would leave a lock Poetry cannot install). A record this + // build does not understand (foreign file, unknown kind) is skipped with a + // warning but must not veto restoring the fragments it does understand. + let mut drifted = false; for rec in entry.wiring.iter().rev() { // SECURITY: `rec.file` comes verbatim from the committed, tamper-able @@ -483,6 +497,7 @@ async fn revert_lock_fragment_splice_inner( if original_text.is_some_and(|orig| lock_text.contains(orig)) { continue; } + drifted = true; warnings.push(VendorWarning::new( "vendor_lock_entry_drifted", format!( @@ -494,7 +509,7 @@ async fn revert_lock_fragment_splice_inner( } } - if !dry_run && (!atomic || warnings.is_empty()) { + if !dry_run && (!atomic || !drifted) { // Mode-preserving: the lock is a user-owned file we merely edit, so // the swapped-in inode must keep its permission bits rather than // reset them to umask defaults. diff --git a/crates/socket-patch-core/src/vendor/pypi_poetry.rs b/crates/socket-patch-core/src/vendor/pypi_poetry.rs index 2599f560..c2c7e736 100644 --- a/crates/socket-patch-core/src/vendor/pypi_poetry.rs +++ b/crates/socket-patch-core/src/vendor/pypi_poetry.rs @@ -900,6 +900,80 @@ content-hash = "4b42a89b7ff7b26511b06acdc458dbd85312e5083db8f212b017482bc68cdd01 } } + /// A newer ledger's record this build cannot replay (unknown kind / + /// foreign file) is skipped with a warning; it must NOT hold the atomic + /// write hostage — the fragments this build does understand are restored. + #[tokio::test] + async fn atomic_revert_ignores_unknown_records_but_holds_on_drift() { + let native = + include_str!("../../tests/fixtures/poetry/1.2.2/poetry.lock").replace("\r\n", "\n"); + let tmp = write_project(&native, PYPROJECT_DIRECT).await; + let project = load_poetry_project(tmp.path()).await.unwrap(); + let wheel = "urllib3-1.26.18-py2.py3-none-any.whl"; + let path = format!(".socket/vendor/pypi/{UUID}/{wheel}"); + let (mut wiring, meta) = wire_poetry( + &project, + tmp.path(), + "urllib3", + "1.26.18", + &path, + wheel, + WHEEL_SHA, + UUID, + ) + .await + .unwrap(); + assert_eq!(wiring.len(), 2, "source table + metadata.files entry"); + wiring.push(record( + "poetry.lock", + "poetry_future_kind", + WiringAction::Rewritten, + "urllib3", + Some("x".into()), + "y".into(), + )); + wiring.push(record( + "pyproject.toml", + KIND_LOCK_PACKAGE, + WiringAction::Rewritten, + "urllib3", + Some("x".into()), + "y".into(), + )); + let outcome = revert_poetry(&entry_for(wiring.clone(), meta.clone()), tmp.path(), false).await; + assert!(outcome.success); + assert_eq!(outcome.warnings.len(), 2, "{:?}", outcome.warnings); + assert!(outcome + .warnings + .iter() + .all(|w| w.code == "vendor_lock_entry_drifted")); + assert_eq!(read_lock(tmp.path()).await, native, "known fragments restored"); + + // Re-wire, then drift one fragment: now the atomic write must hold. + let project = load_poetry_project(tmp.path()).await.unwrap(); + let (wiring, meta) = wire_poetry( + &project, + tmp.path(), + "urllib3", + "1.26.18", + &path, + wheel, + WHEEL_SHA, + UUID, + ) + .await + .unwrap(); + let drifted = read_lock(tmp.path()) + .await + .replace("HTTP library", "Edited description"); + tokio::fs::write(tmp.path().join("poetry.lock"), &drifted) + .await + .unwrap(); + let outcome = revert_poetry(&entry_for(wiring, meta), tmp.path(), false).await; + assert!(!outcome.warnings.is_empty()); + assert_eq!(read_lock(tmp.path()).await, drifted, "half-restore refused"); + } + #[tokio::test] async fn legacy_revert_keeps_source_and_hash_together_on_drift() { let native = diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index 6f21c42e..f30942d2 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -81,6 +81,11 @@ Other measured details: `metadata.content-hash` is unchanged by that, so `poetry check --lock` / `poetry lock --check` cannot detect the loss: re-run `socket-patch scan --mode …` after any of them, or gate CI on `socket-patch vex`. +- `poetry lock --no-update` on Poetry 1.1 / 1.2 keeps the hosted source but + rewrites the entry in its own lock-1.1 shape, dropping the package-level + `files` the rewrite added for Poetry ≥ 1.2's hash check; a lock relocked by + 1.1 and then installed by 1.2+ installs the hosted wheel unverified. Re-run + `socket-patch scan --mode hosted` after relocking on those releases. - Poetry 0.12 and 1.0 resolve a relative `type = "file"` path against the shell's working directory, not the project root; run `poetry install` from the project root on those releases. From e419c42ebec39b6c000e8df673cbdfcc740b427c Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 14:57:00 -0400 Subject: [PATCH 14/19] test(poetry): regenerate the matrix results on the fixed CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 108/108 cases pass on the fix-branch head. The rerun records the fixes' effects: lock-only vendoring applies wherever the lock names a pure-Python wheel hash (1.0/1.1 populated, 1.2+), the out-of-tree agent leg applies and rolls back BARE on every 1.x/2.x release (the crawler finds Poetry's venv), and the pre-1.4 hosted advisory fires for 1.0–1.3 locks only. The table renderer reports the lock-only column per shape. Co-Authored-By: Claude Fable 5.1 --- docs/testing/poetry-compatibility.md | 38 +- .../testing/poetry-compatibility/results.json | 2053 +++++++++++------ scripts/backtest-poetry.py | 15 +- 3 files changed, 1405 insertions(+), 701 deletions(-) diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index f30942d2..7f8a6af5 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -167,28 +167,30 @@ utils::poetry_lock vendor::pypi_poetry` and `cargo test -p socket-patch-core | Poetry | hosted | vendored | agent (in-project venv) | agent (`poetry run`, out-of-tree venv) | tamper rejected (hosted / vendored) | warm venv re-installed (hosted / vendored) | relock keeps patch (hosted / vendored) | lock-only vendored | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 0.12.17 | refused (0.x ignores URL sources) | pass (crlf,direct,populated) | pass (direct) | n/a | n/a / no | n/a / false | n/a / false | refused | -| 1.0.10 | pass (crlf,direct,populated) | pass (crlf,direct,populated) | pass (direct) | pass (direct) | yes / no | false / false | false / false | refused | -| 1.1.15 | pass (crlf,direct,populated) | pass (crlf,direct,populated) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused | -| 1.2.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused | -| 1.3.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused | -| 1.4.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 1.5.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 1.6.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 1.7.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 1.8.5 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 2.0.1 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 2.1.4 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 2.2.1 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 2.3.4 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | -| 2.4.3 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | refused | +| 1.0.10 | pass (crlf,direct,populated) | pass (crlf,direct,populated) | pass (direct) | pass (direct) | yes / no | false / false | false / false | refused (crlf), refused (direct), yes (populated) | +| 1.1.15 | pass (crlf,direct,populated) | pass (crlf,direct,populated) | pass (direct) | pass (direct) | yes / no | false / false | true / true | refused (crlf), refused (direct), yes (populated) | +| 1.2.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / no | false / false | true / true | yes | +| 1.3.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / no | false / false | true / true | yes | +| 1.4.2 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 1.5.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 1.6.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 1.7.1 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 1.8.5 | pass (crlf,direct) | pass (crlf,direct) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 2.0.1 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 2.1.4 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 2.2.1 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 2.3.4 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | +| 2.4.3 | pass (crlf,direct,pep621) | pass (crlf,direct,pep621) | pass (direct) | pass (direct) | yes / yes | true / true | true / true | yes | -Captured 2026-09-17 on macOS arm64 against the CLI at the PR head; 108 cases, -all passing (the `pass`/`refused` cells are the asserted outcomes, the +Captured 2026-09-17 on macOS arm64 against the fix-branch head; 108 cases, +all passing (the `pass`/`refused` cells are the asserted outcomes; the `tamper` / `warm venv` / `relock` / `lock-only vendored` columns are the measured installer facts the sections above describe). The [machine-readable results](poetry-compatibility/results.json) carry every check, the CLI envelopes' relevant fields and the per-step exit codes. `poetry lock` on 0.12 / 1.0 is bare (no `--no-update`), hence -`relock keeps patch = false` there. The companion SBOM annotation work and its -own capture set live in SocketDev/depscan (`tools/pipeline/poetry-patch-backtest.py`). +`relock keeps patch = false` there; `lock-only vendored = refused` on 0.12 and +on the unpopulated 1.0/1.1 fixtures (`urllib3 = []`) because those locks name +no wheel hash. The companion SBOM annotation work and its own capture set live +in SocketDev/depscan (`tools/pipeline/poetry-patch-backtest.py`). diff --git a/docs/testing/poetry-compatibility/results.json b/docs/testing/poetry-compatibility/results.json index aaee0a18..ac1a4350 100644 --- a/docs/testing/poetry-compatibility/results.json +++ b/docs/testing/poetry-compatibility/results.json @@ -1,9 +1,9 @@ { "errors": [], "provenance": { - "capturedAt": "2026-09-17T17:42:39.168405+00:00", - "cliRevision": "2ac2436", - "cliSha256": "ce223a4e26e9536d8aa87c8044e437def508245d37ebefc79372b695923eb3dc", + "capturedAt": "2026-09-17T18:48:19.509655+00:00", + "cliRevision": "08030bd", + "cliSha256": "b2d6bbda707ce09fc578ff7115e0425e15da2dac98d63700b6076e9cbeaae1e9", "host": "Darwin arm64", "modes": [ "hosted", @@ -12,7 +12,7 @@ "agent-oot", "setup" ], - "note": "Merged from three harness runs on the same CLI build (full matrix; legacy-version rerun after a harness timeout bug; warm-install pass).", + "note": "Single harness run on the fix branch head (all fixes applied); every case passed.", "poetryVersions": [ "0.12.17", "1.0.10", @@ -86,7 +86,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -108,7 +109,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -187,6 +188,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" + }, "warnings": [ { "action": "applied", @@ -202,7 +213,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -354,7 +365,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -448,6 +459,11 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" + }, "warnings": [ { "action": "applied", @@ -463,7 +479,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -526,7 +542,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -548,7 +565,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -637,6 +654,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNothing to install or update\n\n - Installing poetry-patch-fixture (0.1.0)\n" + }, "warnings": [ { "action": "applied", @@ -652,7 +679,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -684,14 +711,20 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel. Poetry 1.0 installs through pip: pip 22.3\u201323.0 misparse the hash fragment and refuse the install (fail-closed) \u2014 use pip <= 22.2 or >= 23.1 in the virtualenv." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, @@ -744,7 +777,22 @@ "exit": 0, "statements": 1 }, - "warnings": [] + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel. Poetry 1.0 installs through pip: pip 22.3\u201323.0 misparse the hash fragment and refuse the install (fail-closed) \u2014 use pip <= 22.2 or >= 23.1 in the virtualenv." + } + ] }, "mode": "hosted", "passed": true, @@ -770,7 +818,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -792,7 +841,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -871,6 +920,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, "warnings": [ { "action": "applied", @@ -886,7 +945,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -969,7 +1028,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -978,22 +1037,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 3, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-rerun/captures/1.0.10-direct-agent-oot/venvs/poetry-patch-fixture-hXmFHJiT-py3.8", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 3 + }, + "ootVenv": "/matrix-final/captures/1.0.10-direct-agent-oot/venvs/poetry-patch-fixture-jHpS9Azl-py3.8", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -1035,7 +1099,12 @@ "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel. Poetry 1.0 installs through pip: pip 22.3\u201323.0 misparse the hash fragment and refuse the install (fail-closed) \u2014 use pip <= 22.2 or >= 23.1 in the virtualenv." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, @@ -1103,7 +1172,17 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" }, - "warnings": [] + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel. Poetry 1.0 installs through pip: pip 22.3\u201323.0 misparse the hash fragment and refuse the install (fail-closed) \u2014 use pip <= 22.2 or >= 23.1 in the virtualenv." + } + ] }, "mode": "hosted", "passed": true, @@ -1152,7 +1231,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -1246,6 +1325,11 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, "warnings": [ { "action": "applied", @@ -1261,7 +1345,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -1293,14 +1377,20 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel. Poetry 1.0 installs through pip: pip 22.3\u201323.0 misparse the hash fragment and refuse the install (fail-closed) \u2014 use pip <= 22.2 or >= 23.1 in the virtualenv." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, @@ -1363,7 +1453,22 @@ "exit": 0, "statements": 1 }, - "warnings": [] + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel. Poetry 1.0 installs through pip: pip 22.3\u201323.0 misparse the hash fragment and refuse the install (fail-closed) \u2014 use pip <= 22.2 or >= 23.1 in the virtualenv." + } + ] }, "mode": "hosted", "passed": true, @@ -1376,7 +1481,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -1389,7 +1494,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -1411,7 +1517,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -1435,20 +1541,22 @@ "cmd": null }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "poetryInstallExit0": "Installing dependencies from lock file\n\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 .socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { @@ -1500,6 +1608,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n\n" + }, "warnings": [ { "action": "applied", @@ -1515,7 +1633,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -1547,14 +1665,20 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, @@ -1607,7 +1731,22 @@ "exit": 0, "statements": 1 }, - "warnings": [] + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -1633,7 +1772,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -1655,7 +1795,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -1670,7 +1810,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -1694,7 +1834,7 @@ ], "exit": 1 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -1734,6 +1874,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, "warnings": [ { "action": "applied", @@ -1749,7 +1899,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -1832,7 +1982,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -1841,22 +1991,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 4, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-rerun/captures/1.1.15-direct-agent-oot/venvs/poetry-patch-fixture-3wcEJDxH-py3.8", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 4 + }, + "ootVenv": "/matrix-final/captures/1.1.15-direct-agent-oot/venvs/poetry-patch-fixture-dufSn_8E-py3.8", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -1898,7 +2053,12 @@ "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, @@ -1966,7 +2126,17 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" }, - "warnings": [] + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -1980,7 +2150,7 @@ "lockChanged": true, "poetryLockAfterSetup": { "exit": 0, - "tail": "Creating virtualenv poetry-patch-fixture in /matrix-rerun/captures/1.1.15-direct-setup/project/.venv\nResolving dependencies...\n" + "tail": "Creating virtualenv poetry-patch-fixture in /matrix-final/captures/1.1.15-direct-setup/project/.venv\nResolving dependencies...\n\nWriting lock file\n" }, "pyprojectChanged": true, "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", @@ -1992,7 +2162,7 @@ { "error": null, "kind": "pth", - "path": "/matrix-rerun/captures/1.1.15-direct-setup/project/pyproject.toml", + "path": "/matrix-final/captures/1.1.15-direct-setup/project/pyproject.toml", "status": "updated" } ], @@ -2050,7 +2220,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2065,7 +2235,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2089,7 +2259,7 @@ ], "exit": 1 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -2144,6 +2314,11 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, "warnings": [ { "action": "applied", @@ -2159,7 +2334,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2191,14 +2366,20 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, @@ -2261,7 +2442,22 @@ "exit": 0, "statements": 1 }, - "warnings": [] + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -2274,7 +2470,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -2287,7 +2483,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -2309,7 +2506,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2324,7 +2521,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-populated-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-populated-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2333,22 +2530,24 @@ "cmd": null }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-rerun/captures/1.1.15-populated-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-populated-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -2398,6 +2597,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nNo dependencies to install or update\n" + }, "warnings": [ { "action": "applied", @@ -2413,7 +2622,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2445,21 +2654,27 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2467,16 +2682,16 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": false, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\n\nWriting lock file\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n\nWriting lock file\n" }, "rescanIdempotent": { "applied": 1, @@ -2507,7 +2722,22 @@ "exit": 0, "statements": 1 }, - "warnings": [] + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -2521,7 +2751,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -2533,7 +2763,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -2555,7 +2786,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2570,7 +2801,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "-mikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.2.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2578,32 +2809,34 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": ": 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 0, @@ -2636,6 +2869,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -2651,7 +2894,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2741,7 +2984,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -2751,22 +2994,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 4, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.2.2-direct-agent-oot/venvs/poetry-patch-fixture-XGPMXTkb-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 4 + }, + "ootVenv": "/matrix-final/captures/1.2.2-direct-agent-oot/venvs/poetry-patch-fixture-E1xeLuc2-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -2814,14 +3062,19 @@ "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2829,16 +3082,16 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": false, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\n\nWriting lock file\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n\nWriting lock file\n" }, "rescanIdempotent": { "applied": 1, @@ -2884,7 +3137,17 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, - "warnings": [] + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -2897,7 +3160,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -2933,7 +3196,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -2948,7 +3211,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "ikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.2.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2956,32 +3219,34 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 0, @@ -3027,7 +3292,12 @@ "warmInstall": { "exit": 0, "patched": false, - "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -3044,7 +3314,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -3076,21 +3346,27 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3098,16 +3374,16 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 1, @@ -3138,7 +3414,22 @@ "exit": 0, "statements": 1 }, - "warnings": [] + "warmInstall": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -3152,7 +3443,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -3164,7 +3455,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": false }, "info": { "applied": 1, @@ -3186,7 +3478,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -3201,7 +3493,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "-mikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.3.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3209,32 +3501,34 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": ": 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 0, @@ -3267,6 +3561,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": false, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -3282,7 +3586,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -3372,7 +3676,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -3382,22 +3686,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 4, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.3.2-direct-agent-oot/venvs/poetry-patch-fixture-jcmV2dHD-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 4 + }, + "ootVenv": "/matrix-final/captures/1.3.2-direct-agent-oot/venvs/poetry-patch-fixture-5zqeSPAg-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -3445,14 +3754,19 @@ "appliedExactlyOne": { "applied": 1, "status": "success", - "warnings": [] + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "freshCloneInstallsPatch": { "exit": 0, "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "nstall, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3460,16 +3774,16 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 1, @@ -3515,7 +3829,17 @@ "patched": false, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, - "warnings": [] + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warnings": [ + { + "code": "redirect_poetry_stale_install_risk", + "detail": "poetry.lock was written by Poetry < 1.4, which does not replace an already-installed package at the same version: an existing virtualenv keeps the upstream urllib3 until it is recreated (or the package is `pip uninstall`ed) before `poetry install`; fresh installs pick up the patched wheel." + } + ] }, "mode": "hosted", "passed": true, @@ -3528,7 +3852,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -3564,7 +3888,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -3579,7 +3903,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "ikolalysenko-Projects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.3.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3587,32 +3911,34 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "pypi_poetry_integrity_unverified", + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\nConfiguration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\n\nConsider moving configuration to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 0, @@ -3658,7 +3984,12 @@ "warmInstall": { "exit": 0, "patched": false, - "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": false, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -3675,7 +4006,7 @@ "action": "skipped", "errorCode": "pypi_poetry_integrity_unverified", "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" + "reason": "poetry.lock was written by Poetry < 1.4: that installer does not verify local wheel hashes (the committed wheel bytes are the protection \u2014 review them) and does not replace an already-installed package at the same version \u2014 upgrade to Poetry >= 1.4, or recreate the virtualenv (or `pip uninstall` the package) before `poetry install`" }, { "action": "skipped", @@ -3707,7 +4038,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -3721,7 +4053,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": " 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3729,16 +4061,16 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 1, @@ -3769,6 +4101,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -3783,7 +4125,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -3795,7 +4137,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -3813,12 +4156,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -3832,7 +4169,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "jects-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.4.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3840,32 +4177,32 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "ates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 0, @@ -3898,6 +4235,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -3909,12 +4256,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4003,7 +4344,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -4013,22 +4354,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 4, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.4.2-direct-agent-oot/venvs/poetry-patch-fixture-4MHp-XhW-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 4 + }, + "ootVenv": "/matrix-final/captures/1.4.2-direct-agent-oot/venvs/poetry-patch-fixture-qjnPvAzm-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -4083,7 +4429,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": " 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4091,16 +4437,16 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 1, @@ -4146,6 +4492,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -4159,7 +4510,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -4191,12 +4542,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4210,7 +4555,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "cts-socket-patch/8c2fb367-b3b4-4269-91a3-b6f1bb918056/scratchpad/matrix-full/captures/1.4.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4218,32 +4563,32 @@ "lockCheck": { "cmd": "lock --check", "exit": 0, - "tail": "poetry.lock is consistent with pyproject.toml.\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "es, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, "lockBytesUnchanged": true, "patchSourceKept": true, "pyprojectUnchanged": true, - "tail": "Resolving dependencies...\n('Configuration file exists at /Users/mikolalysenko/Library/Application Support/pypoetry, reusing this directory.\\n\\nConsider moving TOML configuration files to /Users/mikolalysenko/Library/Preferences/pypoetry, as support for the legacy directory will be removed in an upcoming release.',)\n" + "tail": "Resolving dependencies...\n" }, "rescanIdempotent": { "applied": 0, @@ -4289,7 +4634,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -4302,12 +4652,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4338,7 +4682,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -4400,6 +4745,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -4414,7 +4769,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -4426,7 +4781,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -4444,12 +4800,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4463,7 +4813,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4474,22 +4824,22 @@ "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -4529,6 +4879,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -4540,12 +4900,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4634,7 +4988,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -4644,22 +4998,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.5.1-direct-agent-oot/venvs/poetry-patch-fixture-SaNI20UL-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/1.5.1-direct-agent-oot/venvs/poetry-patch-fixture-jQ7Wl_69-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -4777,6 +5136,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -4790,7 +5154,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -4822,12 +5186,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4841,7 +5199,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4852,22 +5210,22 @@ "tail": "poetry.lock is consistent with pyproject.toml.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -4920,7 +5278,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -4933,12 +5296,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -4969,7 +5326,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -5031,6 +5389,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -5045,7 +5413,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -5057,7 +5425,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -5075,12 +5444,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -5094,7 +5457,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -5105,22 +5468,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -5160,6 +5523,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -5171,12 +5544,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -5265,7 +5632,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -5275,22 +5642,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.6.1-direct-agent-oot/venvs/poetry-patch-fixture-ZKoUeQwE-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/1.6.1-direct-agent-oot/venvs/poetry-patch-fixture-v1n_i0Kp-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -5408,6 +5780,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -5421,7 +5798,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -5453,12 +5830,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -5472,7 +5843,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -5483,22 +5854,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -5551,7 +5922,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -5564,12 +5940,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -5600,7 +5970,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -5662,6 +6033,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -5676,7 +6057,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -5688,7 +6069,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -5706,12 +6088,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -5725,7 +6101,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -5736,22 +6112,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -5791,6 +6167,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -5802,12 +6188,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -5896,7 +6276,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -5906,22 +6286,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.7.1-direct-agent-oot/venvs/poetry-patch-fixture-gylI0DbJ-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/1.7.1-direct-agent-oot/venvs/poetry-patch-fixture-bdTEYSnE-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -6039,6 +6424,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n \u2022 Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -6052,7 +6442,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -6084,12 +6474,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -6103,7 +6487,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -6114,22 +6498,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-full/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -6182,7 +6566,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -6195,12 +6584,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -6231,7 +6614,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -6293,6 +6677,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -6307,7 +6701,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -6319,7 +6713,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -6337,12 +6732,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -6356,7 +6745,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -6367,22 +6756,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -6422,6 +6811,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -6433,12 +6832,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -6527,7 +6920,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -6537,22 +6930,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/1.8.5-direct-agent-oot/venvs/poetry-patch-fixture-gX0pmtjt-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/1.8.5-direct-agent-oot/venvs/poetry-patch-fixture-3PRLoMaQ-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -6670,6 +7068,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -6684,7 +7087,7 @@ "lockChanged": true, "poetryLockAfterSetup": { "exit": 0, - "tail": "Resolving dependencies...\n\nWriting lock file\nCreating virtualenv poetry-patch-fixture in /matrix-full/captures/1.8.5-direct-setup/project/.venv\nThe lock file might not be compatible with the current version of Poetry.\nUpgrade Poetry to ensure the lock file is read properly or, alternatively, regenerate the lock file with the `poetry lock` command.\n" + "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-final/captures/1.8.5-direct-setup/project/.venv\n" }, "pyprojectChanged": true, "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", @@ -6696,7 +7099,7 @@ { "error": null, "kind": "pth", - "path": "/matrix-full/captures/1.8.5-direct-setup/project/pyproject.toml", + "path": "/matrix-final/captures/1.8.5-direct-setup/project/pyproject.toml", "status": "updated" } ], @@ -6718,7 +7121,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -6750,12 +7153,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -6769,7 +7166,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -6780,22 +7177,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -6848,7 +7245,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -6861,12 +7263,6 @@ ], "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl" }, - { - "action": "skipped", - "errorCode": "pypi_poetry_integrity_unverified", - "purl": "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any-whl", - "reason": "Poetry < 1.4 does not verify local file hashes; use Poetry >= 1.4 or commit and review the vendored wheel bytes" - }, { "action": "skipped", "errorCode": "vendor_prebuilt_downloaded", @@ -6897,7 +7293,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -6959,6 +7356,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -6973,7 +7380,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -6985,7 +7392,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -7016,7 +7424,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7027,22 +7435,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -7082,6 +7490,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -7181,7 +7599,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -7191,22 +7609,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/2.0.1-direct-agent-oot/venvs/poetry-patch-fixture-f-Vekhwz-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/2.0.1-direct-agent-oot/venvs/poetry-patch-fixture-Ri37rVUh-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -7324,6 +7747,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -7337,7 +7765,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -7382,7 +7810,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7393,22 +7821,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -7461,7 +7889,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -7504,7 +7937,8 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -7576,6 +8010,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -7589,7 +8033,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -7602,7 +8046,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -7633,7 +8078,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7644,22 +8089,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -7709,6 +8154,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -7750,7 +8205,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -7812,6 +8268,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -7826,7 +8292,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -7838,7 +8304,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -7869,7 +8336,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7880,22 +8347,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -7935,6 +8402,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -8034,7 +8511,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -8044,22 +8521,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/2.1.4-direct-agent-oot/venvs/poetry-patch-fixture-9t5jsywg-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/2.1.4-direct-agent-oot/venvs/poetry-patch-fixture-VXTTlCYt-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -8177,6 +8659,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -8190,7 +8677,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -8235,7 +8722,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -8246,22 +8733,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -8314,7 +8801,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -8357,7 +8849,8 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -8429,6 +8922,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -8442,7 +8945,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -8455,7 +8958,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -8486,7 +8990,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -8497,22 +9001,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -8562,6 +9066,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -8603,7 +9117,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -8665,6 +9180,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -8679,7 +9204,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -8691,7 +9216,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -8722,7 +9248,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -8733,22 +9259,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -8788,6 +9314,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -8887,7 +9423,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -8897,22 +9433,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/2.2.1-direct-agent-oot/venvs/poetry-patch-fixture-SrpgH9Jy-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/2.2.1-direct-agent-oot/venvs/poetry-patch-fixture-scsakL9T-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -9030,6 +9571,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -9043,7 +9589,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -9088,7 +9634,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9099,22 +9645,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9167,7 +9713,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -9210,7 +9761,8 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -9282,6 +9834,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -9295,7 +9857,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -9308,7 +9870,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -9339,7 +9902,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9350,22 +9913,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9415,6 +9978,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -9456,7 +10029,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -9518,6 +10092,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -9532,7 +10116,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -9544,7 +10128,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -9575,7 +10160,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9586,22 +10171,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9641,6 +10226,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -9740,7 +10335,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -9750,22 +10345,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/2.3.4-direct-agent-oot/venvs/poetry-patch-fixture-i2qKgRB8-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/2.3.4-direct-agent-oot/venvs/poetry-patch-fixture-m5tUP2ja-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -9883,6 +10483,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -9896,7 +10501,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -9941,7 +10546,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9952,22 +10557,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10020,7 +10625,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -10063,7 +10673,8 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -10135,6 +10746,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -10148,7 +10769,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -10161,7 +10782,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -10192,7 +10814,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -10203,22 +10825,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10268,6 +10890,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -10309,7 +10941,8 @@ "rollbackClearsRedirectLedger": true, "rollbackExit0": true, "rollbackKeepsPyproject": true, - "rollbackRestoresLockBytes": true + "rollbackRestoresLockBytes": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -10371,6 +11004,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -10385,7 +11028,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -10397,7 +11040,8 @@ "rollbackKeepsPyproject": true, "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -10428,7 +11072,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -10439,22 +11083,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10494,6 +11138,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", @@ -10593,7 +11247,7 @@ }, { "checks": { - "bareScanSeesPoetryVenv": false, + "bareScanSeesPoetryVenv": true, "patchedViaPoetryRun": true, "poetryRunScanApplied": true, "rollbackClearsManifest": true, @@ -10603,22 +11257,27 @@ }, "expected": "bareScanSeesPoetryVenv is informational (known crawler gap); the rest must pass", "info": { + "applyPath": "bare", "bareScan": { "exit": 0, "packageDirs": [], "packagesWithPatches": 1, "paths": [], - "scannedPackages": 57, + "scannedPackages": 2, "urllib3Found": true }, - "bareScanSeesPoetryVenv": "the CLI found the out-of-tree venv without help", - "ootVenv": "/matrix-full/captures/2.4.3-direct-agent-oot/venvs/poetry-patch-fixture-6KMianfx-py3.12", + "bareScanSeesPoetryVenv": { + "found": 1, + "scannedPackages": 2 + }, + "ootVenv": "/matrix-final/captures/2.4.3-direct-agent-oot/venvs/poetry-patch-fixture-fvJVuHwd-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, "poetryRunScanApplied": { "applied": 1, - "exit": 0 + "exit": 0, + "path": "bare" }, "rollbackRestoresUpstream": { "exit": 0, @@ -10736,6 +11395,11 @@ "patched": true, "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -10750,7 +11414,7 @@ "lockChanged": true, "poetryLockAfterSetup": { "exit": 0, - "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-full/captures/2.4.3-direct-setup/project/.venv\n" + "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-final/captures/2.4.3-direct-setup/project/.venv\n" }, "pyprojectChanged": true, "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", @@ -10762,7 +11426,7 @@ { "error": null, "kind": "pth", - "path": "/matrix-full/captures/2.4.3-direct-setup/project/pyproject.toml", + "path": "/matrix-final/captures/2.4.3-direct-setup/project/pyproject.toml", "status": "updated" } ], @@ -10784,7 +11448,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -10829,7 +11493,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -10840,22 +11504,22 @@ "tail": "dynamic].\nIf you want to set the version dynamically via `poetry build --local-version` or you are using a plugin, which sets the version dynamically, you should define the version in [tool.poetry] and add 'version' to [project.dynamic].\nWarning: [tool.poetry.description] is deprecated. Use [project.description] instead.\nWarning: [tool.poetry.authors] is deprecated. Use [project.authors] instead.\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10908,7 +11572,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-warm/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -10951,7 +11620,8 @@ "rollbackExit0": true, "rollbackKeepsPyproject": true, "rollbackRestoresLockBytes": true, - "tamperBehaviorAsDocumented": true + "tamperBehaviorAsDocumented": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -11023,6 +11693,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": "Installing dependencies from lock file\n\nPackage operations: 0 installs, 1 update, 0 removals\n\n - Updating urllib3 (1.26.18 -> 1.26.18 https://patch.socket.dev/patch/pypi/urllib3/1.26.18/7e52b8b6-53f2-4dc8-860a-1ae7ebd8be0e/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [] }, "mode": "hosted", @@ -11036,7 +11716,7 @@ "freshCloneInstallsPatch": true, "installedBytesPatched": true, "lockHasFileSource": true, - "lockOnlyVendorApplies": false, + "lockOnlyVendorApplies": true, "lockRewritten": true, "lockUnchangedByInstall": true, "poetryInstallExit0": true, @@ -11049,7 +11729,8 @@ "rollbackRemovesVendoredWheel": true, "rollbackRestoresLockBytes": true, "tamperBehaviorAsDocumented": true, - "vendoredWheelPresent": true + "vendoredWheelPresent": true, + "warmInstallReplacesUpstream": true }, "info": { "applied": 1, @@ -11080,7 +11761,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -11091,22 +11772,22 @@ "tail": "All set!\n" }, "lockOnlyVendor": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, "lockOnlyVendorApplies": { - "applied": 0, + "applied": 1, "codes": [ - "package_not_installed", - "vendor_fetch_unverifiable" + "vendor_fetched_missing", + "vendor_prebuilt_downloaded" ], - "exit": 1 + "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-full/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -11156,6 +11837,16 @@ "exit": 0, "statements": 1 }, + "warmInstall": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, + "warmInstallReplacesUpstream": { + "exit": 0, + "patched": true, + "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + }, "warnings": [ { "action": "applied", diff --git a/scripts/backtest-poetry.py b/scripts/backtest-poetry.py index e383a98e..ce4512f8 100755 --- a/scripts/backtest-poetry.py +++ b/scripts/backtest-poetry.py @@ -714,8 +714,19 @@ def flag(cases, key, sub=None): tamper = f"{'yes' if any(c['info']['tamper']['installExit'] != 0 for c in direct_h) else ('n/a' if not direct_h else 'no')} / {'yes' if any(c['info']['tamper']['installExit'] != 0 for c in direct_v) else ('n/a' if not direct_v else 'no')}" relock = f"{flag([c for c in hosted if c['shape']=='direct'], 'relock', 'patchSourceKept')} / {flag([c for c in vendored if c['shape']=='direct'], 'relock', 'patchSourceKept')}" warm = f"{flag([c for c in hosted if c['shape']=='direct'], 'warmInstall', 'patched')} / {flag([c for c in vendored if c['shape']=='direct'], 'warmInstall', 'patched')}" - lockonly = flag(vendored, "lockOnlyVendor", "applied") - lockonly = {"0": "refused", "1": "yes"}.get(lockonly, lockonly) + # Per shape: the unpopulated legacy fixtures (`urllib3 = []`) name no + # wheel hash, so they stay refused while the populated ones vendor. + per_shape = {} + for c in vendored: + lo = c.get("info", {}).get("lockOnlyVendor") + if lo is not None: + per_shape[c["shape"]] = "yes" if lo.get("applied") == 1 else "refused" + if not per_shape: + lockonly = "n/a" + elif len(set(per_shape.values())) == 1: + lockonly = next(iter(per_shape.values())) + else: + lockonly = ", ".join(f"{v} ({k})" for k, v in sorted(per_shape.items())) lines.append( f"| {version} | {hosted_cell} | {cell(vendored)} | {cell(m('agent'))} | {cell(m('agent-oot'))} | {tamper} | {warm} | {relock} | {lockonly} |" ) From e58c40ad63ae25de24fb30d9aaf0bcb1191c544b Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 15:56:57 -0400 Subject: [PATCH 15/19] fix(poetry): keep hosted rollback invertible across Poetry's own relocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two defects with one root cause — the recorded `[[package]]` fragment ended at the unit's last line while the rewrite APPENDS `[package.source]` after it, so the pristine fragment was a prefix of every rewritten (or relocked) unit: - Replay's "already converged" check (`content.contains(original) && !new.contains(original)`) fired when a relock (Poetry 1.1/1.2 `poetry lock --no-update`) or a hand edit dropped the inserted `files` line but kept the Socket source block: rollback reported success, deleted the ledger and restored `[metadata.files]` to upstream hashes while the lock still redirected — an inconsistent lock with no record left (lock 1.1 and 2.x). For lock 1.0 the guard's other arm meant a hand-restored pristine lock could never converge and rollback refused with a spurious drift. - A re-scan after such a relock appended edits recorded against the RELOCKED text; replay inverted the newer links back to the relocked state and then found neither `new` nor `original` of the older ones, so `rollback` and `remove` refused forever — and the refusal's remedy ("re-run scan") was what lengthened the chain (reproduced with real Poetry 1.1.15 and 1.2.2). The fragment now extends through the next top-level header (`[[package]]`, `[metadata]`, …), so a unit that grew a source block never contains the pristine fragment: the drifted shape is refused, the hand-restored lock converges. The hosted ledger merge REBASES `redirect_poetry_lock_package` edits whose (path, kind, key) already exists when the pre-run file no longer carried their `new` fragments — keeping the oldest `original`, adopting the fresh `new` — instead of appending, so one invertible link survives any number of relock/re-scan rounds. Idempotent re-scans and token-rotation supersedes still append as before. Tests: fragment boundary property per generation and for adjacent units; dropped-files-line-with-source-kept is refused not converged (1.1, 2.x); lock-1.0 hand-restored lock converges; CLI relock → re-scan → rollback chain lands on the pristine lock with a two-edit ledger. Co-Authored-By: Claude Fable 5.1 --- CHANGELOG.md | 9 ++- .../src/commands/scan/hosted.rs | 65 +++++++++++++++- .../tests/in_process_redirect_poetry.rs | 76 +++++++++++++++++++ .../src/utils/poetry_lock.rs | 75 ++++++++++++++++++ .../socket-patch-core/tests/poetry_hosted.rs | 63 +++++++++++++++ docs/testing/poetry-compatibility.md | 7 +- 6 files changed, 292 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6170917b..78f6f0e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,7 +75,14 @@ into the new version's section — see docs/releasing.md. a future `lock-version = "2."` is rewritten like 2.1 on every path (the vendored loader already accepted it), and a malformed `[metadata.files]` / `[metadata.hashes]` value is refused instead of - panicking the scan. (#241) + panicking the scan. Rollback stays invertible across Poetry's own relocks: + the recorded package fragment carries its boundary header, so a unit that + Poetry 1.1/1.2 re-laid (source kept, inserted `files` line dropped) is + refused rather than mistaken for an already-reverted lock, a lock-1.0 + redirect restored by hand converges instead of refusing, and a re-scan + after such a relock REBASES the ledger's edits (pristine → current) + instead of appending a chain whose older links match nothing — which made + `rollback` and `remove` refuse forever. (#241) - **Python patches survive uv lockfiles in both hosted and vendored modes.** `scan --mode hosted|vendored` now rewrites native `uv.lock` together with the paired `pyproject.toml` source and metadata, PEP 723 script locks diff --git a/crates/socket-patch-cli/src/commands/scan/hosted.rs b/crates/socket-patch-cli/src/commands/scan/hosted.rs index 53b05628..b427b31d 100644 --- a/crates/socket-patch-cli/src/commands/scan/hosted.rs +++ b/crates/socket-patch-cli/src/commands/scan/hosted.rs @@ -13,6 +13,11 @@ use super::{discover_selected, ScanArgs}; /// Candidate lockfiles / registry configs the redirect rewriters may touch — /// read from the project when present and handed to `rewrite_registry_redirect`. +/// Fragment-edit kinds whose lockfile the package manager re-lays in place +/// (keeping the Socket source) — a re-scan REBASES their ledger edits instead +/// of appending; see the ledger merge below. +const REBASE_KINDS: &[&str] = &["redirect_poetry_lock_package"]; + const REDIRECT_CANDIDATE_FILES: &[&str] = &[ "package-lock.json", "npm-shrinkwrap.json", @@ -1817,8 +1822,66 @@ pub(crate) async fn run_redirect_selected( ledger.mode = "hosted".to_string(); // The bun.lockb→bun.lock migration removal precedes the rewrite // edits so `--revert` unwinds it last (after restoring bun.lock). + // + // REBASE instead of append for fragment kinds whose file the + // package manager itself rewrites in place: when the ledger already + // holds edits for the same (path, kind, key) and the file no longer + // carried their `new` fragments before this run (Poetry 1.1/1.2 + // `poetry lock --no-update` keeps the Socket source but re-lays the + // unit and drops the inserted `files` line), appending this run's + // edits — recorded against the RELOCKED text — would build a chain + // whose older links match nothing: rollback and remove then refuse + // forever, and the refusal's own remedy ("re-run scan") is what + // lengthened the chain. Keeping the oldest `original` (the pristine + // fragment) and adopting the fresh `new` keeps the chain a single + // invertible link: replay swaps the fragment this run wrote back to + // the fragment the very first run found. + let mut rebased: Vec = Vec::new(); + for edit in rewrite.edits.iter().filter(|e| REBASE_KINDS.contains(&e.kind.as_str())) { + let siblings: Vec = ledger + .edits + .iter() + .enumerate() + .filter(|(_, old)| { + old.path == edit.path && old.kind == edit.kind && old.key == edit.key + }) + .map(|(i, _)| i) + .collect(); + let before = files.get(&edit.path).map(String::as_str).unwrap_or(""); + let drifted = !siblings.is_empty() + && siblings.iter().all(|&i| { + ledger.edits[i] + .new + .as_ref() + .and_then(serde_json::Value::as_str) + .is_none_or(|new| !before.contains(new)) + }); + if !drifted { + continue; + } + // Positional pairing: the rewriter emits a key's fragments in a + // fixed order (package unit, then the legacy integrity entry). + let nth = rewrite + .edits + .iter() + .filter(|e| e.path == edit.path && e.kind == edit.kind && e.key == edit.key) + .position(|e| std::ptr::eq(e, edit)) + .unwrap_or(0); + if let Some(&target) = siblings.get(nth) { + if !rebased.contains(&target) { + ledger.edits[target].new = edit.new.clone(); + ledger.edits[target].action = edit.action.clone(); + rebased.push(target); + } + } + } for edit in migration_edits.iter().chain(rewrite.edits.iter()) { - if !ledger.edits.contains(edit) { + let is_rebased = REBASE_KINDS.contains(&edit.kind.as_str()) + && rebased.iter().any(|&t| { + let old = &ledger.edits[t]; + old.path == edit.path && old.kind == edit.kind && old.key == edit.key && old.new == edit.new + }); + if !is_rebased && !ledger.edits.contains(edit) { ledger.edits.push(edit.clone()); } } diff --git a/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs b/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs index 46d1cd3d..91ff7346 100644 --- a/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs +++ b/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs @@ -28,6 +28,9 @@ const HOSTED_URL: &str = "http://patch.test/patch/pypi/urllib3/1.26.18/22222222- const GHSA: &str = "GHSA-gm62-xv2j-4w53"; const LOCK: &str = include_str!("../../socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock"); +/// Poetry 1.2.2's native lock (lock-version 1.1, populated `[metadata.files]`). +const LOCK_1_1: &str = + include_str!("../../socket-patch-core/tests/fixtures/poetry/1.2.2/poetry.lock"); const PYPROJECT: &str = include_str!("../../socket-patch-core/tests/fixtures/poetry/2.4.3/pyproject.toml"); @@ -231,3 +234,76 @@ async fn lock_only_poetry_project_redirects_attests_rescans_and_rolls_back() { ); } } + +/// What `poetry lock --no-update` on Poetry 1.1 / 1.2 does to a redirected +/// lock-1.1 unit: keeps `[package.source]`, drops the inserted package-level +/// `files` line, and re-lays the `[metadata.files]` entry from the CLI's +/// inline table into Poetry's multi-line array. +fn simulate_poetry_1x_relock(lock: &str) -> String { + let mut out = String::new(); + for line in lock.lines() { + if line.starts_with("files = [{ file = ") { + continue; + } + if let Some(rest) = line.strip_prefix("urllib3 = [{ ") { + let inner = rest.trim_end_matches(" }]"); + out.push_str("urllib3 = [\n {"); + out.push_str(inner); + out.push_str("},\n]\n"); + continue; + } + out.push_str(line); + out.push('\n'); + } + out +} + +/// Relock → re-scan → rollback must still land on the pristine lock. The +/// re-scan REBASES the ledger's edits (pristine → freshly written) instead of +/// appending edits recorded against the relocked text, whose older links +/// would match nothing and make rollback (and remove) refuse forever. +#[tokio::test] +#[serial] +async fn relock_then_rescan_keeps_rollback_invertible() { + let server = MockServer::start().await; + mock_api(&server).await; + let tmp = tempfile::tempdir().unwrap(); + write_project(tmp.path()); + let lock_path = tmp.path().join("poetry.lock"); + std::fs::write(&lock_path, LOCK_1_1).unwrap(); + + assert_eq!(run(hosted_args(tmp.path(), server.uri(), None)).await, 0); + let redirected = read(&lock_path); + let ledger_path = tmp.path().join(".socket/vendor/redirect-state.json"); + let ledger: serde_json::Value = serde_json::from_str(&read(&ledger_path)).unwrap(); + assert_eq!(ledger["edits"].as_array().unwrap().len(), 2, "package + metadata fragments"); + + let relocked = simulate_poetry_1x_relock(&redirected); + assert_ne!(relocked, redirected); + assert!(relocked.contains(HOSTED_URL), "relock keeps the source"); + std::fs::write(&lock_path, &relocked).unwrap(); + + // Re-scan: the unit lost its `files` line, so the rewriter writes again. + assert_eq!(run(hosted_args(tmp.path(), server.uri(), None)).await, 0); + let rescanned = read(&lock_path); + assert_ne!(rescanned, relocked, "the re-scan must restore the package files entry"); + let ledger: serde_json::Value = serde_json::from_str(&read(&ledger_path)).unwrap(); + let edits = ledger["edits"].as_array().unwrap(); + assert_eq!(edits.len(), 2, "rebased, not appended: {ledger}"); + for edit in edits { + let original = edit["original"].as_str().unwrap(); + assert!(!original.contains(HOSTED_URL), "originals stay pristine: {original}"); + let new = edit["new"].as_str().unwrap(); + assert!(rescanned.contains(new), "new fragments describe the current lock"); + } + + let code = rollback::run(RollbackArgs { + targets: Vec::new(), + common: global(tmp.path(), server.uri()), + one_off: false, + preserve_state: false, + }) + .await; + assert_eq!(code, 0, "rollback after relock + re-scan must succeed"); + assert_eq!(read(&lock_path), LOCK_1_1, "pristine lock restored byte for byte"); +} diff --git a/crates/socket-patch-core/src/utils/poetry_lock.rs b/crates/socket-patch-core/src/utils/poetry_lock.rs index 5a71cd2f..b04e3b36 100644 --- a/crates/socket-patch-core/src/utils/poetry_lock.rs +++ b/crates/socket-patch-core/src/utils/poetry_lock.rs @@ -244,6 +244,28 @@ pub fn rewrite_poetry_lock( Ok(Some(result)) } +/// End (exclusive, before its line break) of the first top-level TOML header +/// line at or after `from`, skipping blank lines; `text.len()` at EOF; `from` +/// itself when the next non-blank line is not a header (a shape Poetry never +/// writes — the fragment then ends where it used to). +fn next_header_end(text: &str, from: usize) -> usize { + let mut pos = from; + for line in text[from..].split_inclusive('\n') { + let content = line.trim_end_matches(['\r', '\n']); + // Blank lines and comments sit between units (toml_edit clones carry + // the file's leading comment as decor); they belong to the boundary. + if content.trim().is_empty() || content.trim_start().starts_with('#') { + pos += line.len(); + continue; + } + if content.starts_with('[') { + return pos + content.len(); + } + return from; + } + text.len() +} + /// The verbatim `(original, replacement)` fragments that turn `original` into /// `rewritten` for `name`: the package's `[[package]]` unit (with its /// sub-tables) and, for legacy formats, its `[metadata.files]` / @@ -291,6 +313,17 @@ pub fn poetry_lock_edits( span.end += text[span.end..] .find(['\r', '\n']) .unwrap_or(text.len() - span.end); + // Carry the unit's BOUNDARY: the blank line(s) after it plus the next + // top-level header (`[[package]]`, `[metadata]`, `[extras]`, …) or + // EOF. The rewrite APPENDS `[package.source]` to the unit, so without + // the boundary the pristine fragment would be a strict prefix of every + // rewritten (or later relocked) unit: rollback's "already converged" + // check could never fire for lock 1.0, and a relock that dropped the + // inserted `files` line but kept the source block would match the + // pristine prefix and report a successful rollback while the lock + // still redirected. With the header included, the pristine fragment + // matches only a unit that really ends where it ended. + span.end = next_header_end(text, span.end); let mut result = vec![text[span].to_string()]; let metadata = lock .get("metadata") @@ -481,6 +514,48 @@ mod tests { assert!(edits[1].0.starts_with('\n')); } + /// The package fragment ends with the NEXT top-level header, so the + /// pristine fragment is never a prefix of the rewritten one (the source + /// block sits between the unit and that header). + #[test] + fn package_fragment_carries_its_boundary_header() { + for version in ["1.0.10", "1.2.2", "2.4.3"] { + let lock = fixture(version); + let rewritten = hosted(&lock).unwrap().unwrap(); + let edits = poetry_lock_edits(&lock, &rewritten, "urllib3").unwrap(); + let (original, new) = &edits[0]; + assert!( + original.ends_with("[metadata]") || original.ends_with("[extras]"), + "{version}: {original:?}" + ); + assert!(new.ends_with("[metadata]") || new.ends_with("[extras]")); + assert!(!new.contains(original.as_str()), "{version}: pristine must not be a prefix of new"); + // A relock that keeps `[package.source]` but drops the inserted + // `files` line must NOT contain the pristine fragment either. + let drifted: String = rewritten + .lines() + .filter(|l| !l.starts_with("files = [{ file")) + .collect::>() + .join("\n"); + assert!(!drifted.contains(original.as_str()), "{version}"); + } + // Two adjacent packages: the first fragment ends with the second's + // header, the second starts with it; both splice independently. + let lock = fixture("2.4.3"); + let mut doc: DocumentMut = lock.parse().unwrap(); + let mut second = doc["package"].as_array_of_tables().unwrap().get(0).unwrap().clone(); + second["name"] = value("six"); + second["version"] = value("1.16.0"); + second.set_position(None); + second.remove("extras"); + doc["package"].as_array_of_tables_mut().unwrap().push(second); + let two = doc.to_string(); + let first = hosted(&two).unwrap().unwrap(); + let edits = poetry_lock_edits(&two, &first, "urllib3").unwrap(); + assert!(edits[0].0.ends_with("[[package]]"), "{:?}", edits[0].0); + assert_eq!(two.matches(edits[0].0.as_str()).count(), 1); + } + #[test] fn absent_or_other_version_yields_none_not_error() { let lock = fixture("2.4.3"); diff --git a/crates/socket-patch-core/tests/poetry_hosted.rs b/crates/socket-patch-core/tests/poetry_hosted.rs index 76cc3140..17173e65 100644 --- a/crates/socket-patch-core/tests/poetry_hosted.rs +++ b/crates/socket-patch-core/tests/poetry_hosted.rs @@ -413,3 +413,66 @@ fn rotated_grant_token_supersedes_the_prior_hosted_url() { assert_eq!(second.edits.len(), 1); assert!(second.edits[0].original.as_ref().unwrap().as_str().unwrap().contains(URL)); } + +/// A relock (or hand edit) that drops the inserted `files` line but keeps +/// `[package.source]` must be REFUSED by rollback, never mistaken for an +/// already-reverted lock: before the fragment carried its boundary header the +/// pristine unit matched as a prefix, replay reported success, deleted the +/// ledger, and left the lock redirecting with upstream hashes in +/// `[metadata.files]`. +#[tokio::test] +async fn dropped_files_line_with_source_kept_is_refused_not_converged() { + for version in ["1.2.2", "2.4.3"] { + let pristine = original(version); + let files = BTreeMap::from([("poetry.lock".to_string(), pristine.clone())]); + let result = rewrite_registry_redirect(&files, &[patch()]); + let redirected = &result.files["poetry.lock"]; + let drifted: String = redirected + .lines() + .filter(|line| !line.starts_with("files = [{ file = ")) + .collect::>() + .join("\n") + + "\n"; + assert_ne!(drifted, *redirected, "{version}: the files line must have been removed"); + assert!(drifted.contains("[package.source]")); + let directory = tempfile::tempdir().unwrap(); + tokio::fs::write(directory.path().join("poetry.lock"), &drifted).await.unwrap(); + let mut state = RedirectState { + edits: result.edits.clone(), + ..RedirectState::default() + }; + let outcome = revert_remaining_redirect_edits(directory.path(), &mut state, false).await; + assert!(!outcome.fully_reverted(), "{version}: must refuse, not report success"); + assert_eq!( + tokio::fs::read_to_string(directory.path().join("poetry.lock")).await.unwrap(), + drifted, + "{version}: a refused revert writes nothing" + ); + assert!(!state.edits.is_empty(), "{version}: the ledger keeps its edits for a re-scan"); + } +} + +/// Lock 1.0 only APPENDS `[package.source]` to the unit. A lock restored to +/// pristine by hand (or by Poetry 1.0's own bare `poetry lock`, which drops +/// the source) must let rollback converge and clear the ledger instead of +/// refusing with a spurious drift. +#[tokio::test] +async fn lock_1_0_rollback_converges_on_a_hand_restored_lock() { + let pristine = original("1.0.10"); + let files = BTreeMap::from([("poetry.lock".to_string(), pristine.clone())]); + let result = rewrite_registry_redirect(&files, &[patch()]); + assert!(!result.edits.is_empty()); + let directory = tempfile::tempdir().unwrap(); + tokio::fs::write(directory.path().join("poetry.lock"), &pristine).await.unwrap(); + let mut state = RedirectState { + edits: result.edits, + ..RedirectState::default() + }; + let outcome = revert_remaining_redirect_edits(directory.path(), &mut state, false).await; + assert!(outcome.fully_reverted(), "{:?}", outcome.refusals); + assert!(state.edits.is_empty()); + assert_eq!( + tokio::fs::read_to_string(directory.path().join("poetry.lock")).await.unwrap(), + pristine + ); +} diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index 7f8a6af5..59eb205c 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -85,7 +85,12 @@ Other measured details: rewrites the entry in its own lock-1.1 shape, dropping the package-level `files` the rewrite added for Poetry ≥ 1.2's hash check; a lock relocked by 1.1 and then installed by 1.2+ installs the hosted wheel unverified. Re-run - `socket-patch scan --mode hosted` after relocking on those releases. + `socket-patch scan --mode hosted` after relocking on those releases: the + re-scan restores the entry and rebases the ledger's recorded edits onto the + relocked text (pristine → current, never an appended chain), so `rollback` + still lands on the pristine lock afterwards. A relocked-but-not-rescanned + lock is refused by `rollback` (its recorded fragments match nothing) rather + than reported as already reverted. - Poetry 0.12 and 1.0 resolve a relative `type = "file"` path against the shell's working directory, not the project root; run `poetry install` from the project root on those releases. From 75d49acfef2f6bfe95651224a8f4fdc6f9beb6e0 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 16:22:28 -0400 Subject: [PATCH 16/19] =?UTF-8?q?test(poetry):=20exercise=20relock=20?= =?UTF-8?q?=E2=86=92=20re-scan=20=E2=86=92=20rollback=20in=20the=20live=20?= =?UTF-8?q?matrix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Poetry's own relock keeps the patch source but re-lays the unit (1.1/1.2), the harness now re-scans instead of restoring the CLI's lock and lets the final rollback prove the rebased ledger still lands on pristine bytes. Co-Authored-By: Claude Fable 5.1 --- scripts/backtest-poetry.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/backtest-poetry.py b/scripts/backtest-poetry.py index ce4512f8..1c1028c0 100755 --- a/scripts/backtest-poetry.py +++ b/scripts/backtest-poetry.py @@ -593,7 +593,17 @@ def check(name, value, note=None): marker = b"patch.socket.dev" if mode == "hosted" else b".socket/vendor/pypi" rl.update(lockBytesUnchanged=relocked == lock_after, patchSourceKept=marker in relocked, pyprojectUnchanged=(project / "pyproject.toml").read_bytes() == pristine_pyproject) info["relock"] = rl - (project / "poetry.lock").write_bytes(lock_after) + if rl["patchSourceKept"] and not rl["lockBytesUnchanged"]: + # Poetry re-laid the unit around the kept source (1.1/1.2 drop + # the inserted `files` line). The documented recovery is a + # re-scan; it must restore the entry and leave a ledger that + # the final rollback below can still invert to pristine bytes. + rs = Run(cli_cmd(project, "scan", "--mode", mode), project, env, case / "rescan-after-relock.log") + ers = rs.json_or_empty() + check("rescanAfterRelockApplies", rs.ok() and applied_count(mode, ers) >= 0 and marker in (project / "poetry.lock").read_bytes(), {"exit": rs.rc, "applied": applied_count(mode, ers)}) + info["rescanAfterRelock"] = {"exit": rs.rc, "applied": applied_count(mode, ers), "lockChanged": (project / "poetry.lock").read_bytes() != relocked} + else: + (project / "poetry.lock").write_bytes(lock_after) # Rollback restores every byte and clears the ledgers. rb = Run(cli_cmd(project, "rollback"), project, env, case / "rollback.log") From 806fe3f5a241c51426f7d41c062fc1e2a6dc642b Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 16:39:49 -0400 Subject: [PATCH 17/19] test(poetry): final matrix results on the fixed CLI; isolate HOME for setup's Poetry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 108/108 cases on the fix-branch head (0.12.17 … 2.4.3 × hosted / vendored / agent / out-of-tree agent / setup × direct / populated / crlf / pep621), including the live relock → re-scan → rollback chain on Poetry 1.1 and 1.2. The `setup` leg now hands the CLI-spawned `poetry lock` the case-isolated HOME as well (Poetry <= 1.1's shared HTTP-cache lock wedged one parallel run). Co-Authored-By: Claude Fable 5.1 --- .../testing/poetry-compatibility/results.json | 408 ++++++++++-------- scripts/backtest-poetry.py | 3 + 2 files changed, 232 insertions(+), 179 deletions(-) diff --git a/docs/testing/poetry-compatibility/results.json b/docs/testing/poetry-compatibility/results.json index ac1a4350..d85d8915 100644 --- a/docs/testing/poetry-compatibility/results.json +++ b/docs/testing/poetry-compatibility/results.json @@ -1,9 +1,9 @@ { "errors": [], "provenance": { - "capturedAt": "2026-09-17T18:48:19.509655+00:00", - "cliRevision": "08030bd", - "cliSha256": "b2d6bbda707ce09fc578ff7115e0425e15da2dac98d63700b6076e9cbeaae1e9", + "capturedAt": "2026-09-17T20:22:39.127492+00:00", + "cliRevision": "75d49ac", + "cliSha256": "40a16bf5f5fe0f58e738710b88283a6dd412de0e6e23f958b324d9debacf201d", "host": "Darwin arm64", "modes": [ "hosted", @@ -12,7 +12,7 @@ "agent-oot", "setup" ], - "note": "Single harness run on the fix branch head (all fixes applied); every case passed.", + "note": "Single harness run on the fix-branch head; the Poetry 1.1.15 `setup` case was re-run alone after its first attempt hit Poetry <= 1.1's shared HTTP-cache lock (the CLI-spawned `poetry lock` now also gets the case-isolated HOME).", "poetryVersions": [ "0.12.17", "1.0.10", @@ -1050,7 +1050,7 @@ "found": 1, "scannedPackages": 3 }, - "ootVenv": "/matrix-final/captures/1.0.10-direct-agent-oot/venvs/poetry-patch-fixture-jHpS9Azl-py3.8", + "ootVenv": "/matrix-final2/captures/1.0.10-direct-agent-oot/venvs/poetry-patch-fixture-OOp1MSO--py3.8", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -1660,6 +1660,7 @@ "poetryInstallExit0": true, "pyprojectUnchanged": true, "recordHasFiles": true, + "rescanAfterRelockApplies": true, "rescanIdempotent": true, "rollbackClearsManifest": true, "rollbackClearsRedirectLedger": true, @@ -1702,6 +1703,15 @@ "pyprojectUnchanged": true, "tail": "Resolving dependencies...\n\nWriting lock file\n" }, + "rescanAfterRelock": { + "applied": 1, + "exit": 0, + "lockChanged": true + }, + "rescanAfterRelockApplies": { + "applied": 1, + "exit": 0 + }, "rescanIdempotent": { "applied": 1, "exit": 0, @@ -1810,7 +1820,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.1.15-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -1834,7 +1844,7 @@ ], "exit": 1 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.1.15-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -2004,7 +2014,7 @@ "found": 1, "scannedPackages": 4 }, - "ootVenv": "/matrix-final/captures/1.1.15-direct-agent-oot/venvs/poetry-patch-fixture-dufSn_8E-py3.8", + "ootVenv": "/matrix-final2/captures/1.1.15-direct-agent-oot/venvs/poetry-patch-fixture-Ynsj_tRb-py3.8", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -2039,6 +2049,7 @@ "poetryInstallExit0": true, "pyprojectUnchanged": true, "recordHasFiles": true, + "rescanAfterRelockApplies": true, "rescanIdempotent": true, "rollbackClearsManifest": true, "rollbackClearsRedirectLedger": true, @@ -2082,6 +2093,15 @@ "pyprojectUnchanged": true, "tail": "Resolving dependencies...\n\nWriting lock file\n" }, + "rescanAfterRelock": { + "applied": 1, + "exit": 0, + "lockChanged": true + }, + "rescanAfterRelockApplies": { + "applied": 1, + "exit": 0 + }, "rescanIdempotent": { "applied": 1, "exit": 0, @@ -2143,41 +2163,6 @@ "poetry": "1.1.15", "shape": "direct" }, - { - "checks": {}, - "expected": "informational: setup edits pyproject; poetry must resolve socket-patch[hook]", - "info": { - "lockChanged": true, - "poetryLockAfterSetup": { - "exit": 0, - "tail": "Creating virtualenv poetry-patch-fixture in /matrix-final/captures/1.1.15-direct-setup/project/.venv\nResolving dependencies...\n\nWriting lock file\n" - }, - "pyprojectChanged": true, - "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", - "setupCheckExit": 0, - "setupEnvelope": { - "alreadyConfigured": 0, - "errors": 0, - "files": [ - { - "error": null, - "kind": "pth", - "path": "/matrix-final/captures/1.1.15-direct-setup/project/pyproject.toml", - "status": "updated" - } - ], - "packageManager": "npm", - "pythonPackageManager": "poetry", - "status": "success", - "updated": 1 - }, - "setupExit": 0 - }, - "mode": "setup", - "passed": true, - "poetry": "1.1.15", - "shape": "direct" - }, { "checks": { "appliedExactlyOne": true, @@ -2235,7 +2220,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.1.15-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2259,7 +2244,7 @@ ], "exit": 1 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.1.15-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -2360,6 +2345,7 @@ "poetryInstallExit0": true, "pyprojectUnchanged": true, "recordHasFiles": true, + "rescanAfterRelockApplies": true, "rescanIdempotent": true, "rollbackClearsManifest": true, "rollbackClearsRedirectLedger": true, @@ -2403,6 +2389,15 @@ "pyprojectUnchanged": true, "tail": "Resolving dependencies...\n\nWriting lock file\n" }, + "rescanAfterRelock": { + "applied": 1, + "exit": 0, + "lockChanged": true + }, + "rescanAfterRelockApplies": { + "applied": 1, + "exit": 0 + }, "rescanIdempotent": { "applied": 1, "exit": 0, @@ -2521,7 +2516,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-populated-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.1.15-populated-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2547,7 +2542,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.1.15-populated-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.1.15-populated-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -2649,6 +2644,7 @@ "poetryInstallExit0": true, "pyprojectUnchanged": true, "recordHasFiles": true, + "rescanAfterRelockApplies": true, "rescanIdempotent": true, "rollbackClearsManifest": true, "rollbackClearsRedirectLedger": true, @@ -2693,6 +2689,15 @@ "pyprojectUnchanged": true, "tail": "Resolving dependencies...\n\nWriting lock file\n" }, + "rescanAfterRelock": { + "applied": 1, + "exit": 0, + "lockChanged": true + }, + "rescanAfterRelockApplies": { + "applied": 1, + "exit": 0 + }, "rescanIdempotent": { "applied": 1, "exit": 0, @@ -2801,7 +2806,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.2.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -2829,7 +2834,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -2872,12 +2877,12 @@ "warmInstall": { "exit": 0, "patched": false, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": false, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.2.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -3007,7 +3012,7 @@ "found": 1, "scannedPackages": 4 }, - "ootVenv": "/matrix-final/captures/1.2.2-direct-agent-oot/venvs/poetry-patch-fixture-E1xeLuc2-py3.12", + "ootVenv": "/matrix-final2/captures/1.2.2-direct-agent-oot/venvs/poetry-patch-fixture--o8xsesc-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -3048,6 +3053,7 @@ "poetryInstallExit0": true, "pyprojectUnchanged": true, "recordHasFiles": true, + "rescanAfterRelockApplies": true, "rescanIdempotent": true, "rollbackClearsManifest": true, "rollbackClearsRedirectLedger": true, @@ -3093,6 +3099,15 @@ "pyprojectUnchanged": true, "tail": "Resolving dependencies...\n\nWriting lock file\n" }, + "rescanAfterRelock": { + "applied": 1, + "exit": 0, + "lockChanged": true + }, + "rescanAfterRelockApplies": { + "applied": 1, + "exit": 0 + }, "rescanIdempotent": { "applied": 1, "exit": 0, @@ -3211,7 +3226,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.2.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3239,7 +3254,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -3292,12 +3307,12 @@ "warmInstall": { "exit": 0, "patched": false, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": false, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.2.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -3493,7 +3508,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.3.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3521,7 +3536,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -3564,12 +3579,12 @@ "warmInstall": { "exit": 0, "patched": false, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": false, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.3.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -3699,7 +3714,7 @@ "found": 1, "scannedPackages": 4 }, - "ootVenv": "/matrix-final/captures/1.3.2-direct-agent-oot/venvs/poetry-patch-fixture-5zqeSPAg-py3.12", + "ootVenv": "/matrix-final2/captures/1.3.2-direct-agent-oot/venvs/poetry-patch-fixture-nqgm3NcM-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -3903,7 +3918,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.3.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -3931,7 +3946,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -3984,12 +3999,12 @@ "warmInstall": { "exit": 0, "patched": false, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": false, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.3.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -4169,7 +4184,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.4.2-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4195,7 +4210,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -4238,12 +4253,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.4.2-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -4367,7 +4382,7 @@ "found": 1, "scannedPackages": 4 }, - "ootVenv": "/matrix-final/captures/1.4.2-direct-agent-oot/venvs/poetry-patch-fixture-qjnPvAzm-py3.12", + "ootVenv": "/matrix-final2/captures/1.4.2-direct-agent-oot/venvs/poetry-patch-fixture-7SNtuRHk-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -4555,7 +4570,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.4.2-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4581,7 +4596,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -4634,12 +4649,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.4.2-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -4813,7 +4828,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.5.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -4839,7 +4854,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -4882,12 +4897,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.5.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -5011,7 +5026,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/1.5.1-direct-agent-oot/venvs/poetry-patch-fixture-jQ7Wl_69-py3.12", + "ootVenv": "/matrix-final2/captures/1.5.1-direct-agent-oot/venvs/poetry-patch-fixture-_zoUJMnU-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -5199,7 +5214,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.5.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -5225,7 +5240,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -5278,12 +5293,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.5.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -5457,7 +5472,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.6.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -5483,7 +5498,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -5526,12 +5541,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.6.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -5655,7 +5670,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/1.6.1-direct-agent-oot/venvs/poetry-patch-fixture-v1n_i0Kp-py3.12", + "ootVenv": "/matrix-final2/captures/1.6.1-direct-agent-oot/venvs/poetry-patch-fixture-3oGutE4e-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -5843,7 +5858,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.6.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -5869,7 +5884,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -5922,12 +5937,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.6.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -6101,7 +6116,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.7.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -6127,7 +6142,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -6170,12 +6185,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " \u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "\u2022 Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.7.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -6299,7 +6314,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/1.7.1-direct-agent-oot/venvs/poetry-patch-fixture-bdTEYSnE-py3.12", + "ootVenv": "/matrix-final2/captures/1.7.1-direct-agent-oot/venvs/poetry-patch-fixture-h-NPhXP2-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -6487,7 +6502,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.7.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -6513,7 +6528,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n \u2022 Installing urllib3 (1.26.18 /matrix-final2/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -6566,12 +6581,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.7.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -6745,7 +6760,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/1.8.5-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -6771,7 +6786,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -6814,12 +6829,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.8.5-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -6943,7 +6958,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/1.8.5-direct-agent-oot/venvs/poetry-patch-fixture-3PRLoMaQ-py3.12", + "ootVenv": "/matrix-final2/captures/1.8.5-direct-agent-oot/venvs/poetry-patch-fixture-A0_pGI6P-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -7087,7 +7102,7 @@ "lockChanged": true, "poetryLockAfterSetup": { "exit": 0, - "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-final/captures/1.8.5-direct-setup/project/.venv\n" + "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-final2/captures/1.8.5-direct-setup/project/.venv\n" }, "pyprojectChanged": true, "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", @@ -7099,7 +7114,7 @@ { "error": null, "kind": "pth", - "path": "/matrix-final/captures/1.8.5-direct-setup/project/pyproject.toml", + "path": "/matrix-final2/captures/1.8.5-direct-setup/project/pyproject.toml", "status": "updated" } ], @@ -7166,7 +7181,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/1.8.5-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7192,7 +7207,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock --no-update -n", "exit": 0, @@ -7245,12 +7260,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/1.8.5-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -7424,7 +7439,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.0.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7450,7 +7465,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -7493,12 +7508,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.0.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -7622,7 +7637,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/2.0.1-direct-agent-oot/venvs/poetry-patch-fixture-Ri37rVUh-py3.12", + "ootVenv": "/matrix-final2/captures/2.0.1-direct-agent-oot/venvs/poetry-patch-fixture-0k24feQr-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -7810,7 +7825,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.0.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -7836,7 +7851,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -7889,12 +7904,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.0.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -8078,7 +8093,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.0.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -8104,7 +8119,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -8157,12 +8172,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.0.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -8336,7 +8351,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.1.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -8362,7 +8377,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -8405,12 +8420,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.1.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -8534,7 +8549,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/2.1.4-direct-agent-oot/venvs/poetry-patch-fixture-VXTTlCYt-py3.12", + "ootVenv": "/matrix-final2/captures/2.1.4-direct-agent-oot/venvs/poetry-patch-fixture-V-8iOFCt-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -8722,7 +8737,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.1.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -8748,7 +8763,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -8801,12 +8816,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.1.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -8990,7 +9005,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.1.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9016,7 +9031,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9069,12 +9084,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.1.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -9248,7 +9263,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.2.1-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9274,7 +9289,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9317,12 +9332,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.2.1-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -9446,7 +9461,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/2.2.1-direct-agent-oot/venvs/poetry-patch-fixture-scsakL9T-py3.12", + "ootVenv": "/matrix-final2/captures/2.2.1-direct-agent-oot/venvs/poetry-patch-fixture-GNeKz0YO-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -9634,7 +9649,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.2.1-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9660,7 +9675,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9713,12 +9728,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.2.1-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -9902,7 +9917,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.2.1-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -9928,7 +9943,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -9981,12 +9996,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.2.1-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -10160,7 +10175,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.3.4-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -10186,7 +10201,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10229,12 +10244,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.3.4-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -10358,7 +10373,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/2.3.4-direct-agent-oot/venvs/poetry-patch-fixture-m5tUP2ja-py3.12", + "ootVenv": "/matrix-final2/captures/2.3.4-direct-agent-oot/venvs/poetry-patch-fixture-a0nSdvf5-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -10546,7 +10561,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.3.4-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -10572,7 +10587,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10625,12 +10640,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.3.4-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -10814,7 +10829,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.3.4-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -10840,7 +10855,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -10893,12 +10908,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.3.4-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -11072,7 +11087,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.4.3-crlf-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -11098,7 +11113,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -11141,12 +11156,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " - Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "- Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.4.3-crlf-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -11270,7 +11285,7 @@ "found": 1, "scannedPackages": 2 }, - "ootVenv": "/matrix-final/captures/2.4.3-direct-agent-oot/venvs/poetry-patch-fixture-fvJVuHwd-py3.12", + "ootVenv": "/matrix-final2/captures/2.4.3-direct-agent-oot/venvs/poetry-patch-fixture-8DuawaLX-py3.12", "patchedViaPoetryRun": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, @@ -11414,7 +11429,7 @@ "lockChanged": true, "poetryLockAfterSetup": { "exit": 0, - "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-final/captures/2.4.3-direct-setup/project/.venv\n" + "tail": "Resolving dependencies...\nCreating virtualenv poetry-patch-fixture in /matrix-final2/captures/2.4.3-direct-setup/project/.venv\n" }, "pyprojectChanged": true, "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", @@ -11426,7 +11441,7 @@ { "error": null, "kind": "pth", - "path": "/matrix-final/captures/2.4.3-direct-setup/project/pyproject.toml", + "path": "/matrix-final2/captures/2.4.3-direct-setup/project/pyproject.toml", "status": "updated" } ], @@ -11493,7 +11508,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.4.3-direct-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -11519,7 +11534,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -11572,12 +11587,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.4.3-direct-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -11761,7 +11776,7 @@ "oracle": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" }, - "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.4.3-pep621-vendored/fresh/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "installedBytesPatched": { "urllib3/response.py": "9027726cab26bb63b978e6af295b22ec6172b100cda66d9b91cdc30bebc03730" @@ -11787,7 +11802,7 @@ ], "exit": 0 }, - "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", + "poetryInstallExit0": "Installing dependencies from lock file\n\nPackage operations: 1 install, 0 updates, 0 removals\n\n - Installing urllib3 (1.26.18 /matrix-final2/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n", "relock": { "cmd": "lock -n", "exit": 0, @@ -11840,12 +11855,12 @@ "warmInstall": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warmInstallReplacesUpstream": { "exit": 0, "patched": true, - "tail": " Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" + "tail": "Updating urllib3 (1.26.18 -> 1.26.18 /matrix-final2/captures/2.4.3-pep621-vendored/project/.socket/vendor/pypi/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl)\n" }, "warnings": [ { @@ -11870,6 +11885,41 @@ "passed": true, "poetry": "2.4.3", "shape": "pep621" + }, + { + "checks": {}, + "expected": "informational: setup edits pyproject; poetry must resolve socket-patch[hook]", + "info": { + "lockChanged": true, + "poetryLockAfterSetup": { + "exit": 0, + "tail": "Creating virtualenv poetry-patch-fixture in /matrix-final2-setup/captures/1.1.15-direct-setup/project/.venv\nResolving dependencies...\n" + }, + "pyprojectChanged": true, + "pyprojectDiff": "[tool.poetry]\nname = \"poetry-patch-fixture\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"Socket \"]\n\n[tool.poetry.dependencies]\npython = \">=3.8\"\nurllib3 = \"1.26.18\"\nsocket-patch = { version = \"*\", extras = [\"hook\"] }\n", + "setupCheckExit": 0, + "setupEnvelope": { + "alreadyConfigured": 0, + "errors": 0, + "files": [ + { + "error": null, + "kind": "pth", + "path": "/matrix-final2-setup/captures/1.1.15-direct-setup/project/pyproject.toml", + "status": "updated" + } + ], + "packageManager": "npm", + "pythonPackageManager": "poetry", + "status": "success", + "updated": 1 + }, + "setupExit": 0 + }, + "mode": "setup", + "passed": true, + "poetry": "1.1.15", + "shape": "direct" } ] } \ No newline at end of file diff --git a/scripts/backtest-poetry.py b/scripts/backtest-poetry.py index 1c1028c0..61c80c23 100755 --- a/scripts/backtest-poetry.py +++ b/scripts/backtest-poetry.py @@ -369,6 +369,9 @@ def check(name, value, note=None): if mode == "setup": senv = dict(env) senv["PATH"] = str(tool / "bin") + os.pathsep + senv.get("PATH", "") + # `setup` shells out to that Poetry; give it the case's isolated + # HOME too (Poetry <= 1.1's shared HTTP-cache lock, see poetry_env). + senv["HOME"] = poetry_env(project)["HOME"] r = Run(cli_cmd(project, "setup"), project, senv, case / "setup.log") info["setupExit"] = r.rc try: From eccfe2cc145eb87b873280dcce2805ed96b80725 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 17:32:05 -0400 Subject: [PATCH 18/19] Fix Poetry CI line endings and stale hosted attestations Preserve LF/CRLF in the relock simulator and exercise both newline forms. Probe installed Python package hashes after hosted redirects, warn on stale bytes, and exclude them from same-run VEX even when another interpreter is patched. Cover re-scans, ledger fallback, missing files, dry runs, variants, and custom prefixes. Assisted-by: Codex:gpt-6-astra --- CHANGELOG.md | 5 + crates/socket-patch-cli/CLI_CONTRACT.md | 3 + .../src/commands/scan/hosted.rs | 63 +++-- .../src/commands/scan/hosted/python.rs | 172 ++++++++++++ crates/socket-patch-cli/src/commands/vex.rs | 25 ++ .../tests/in_process_redirect_poetry.rs | 259 ++++++++++++++++-- docs/testing/poetry-compatibility.md | 9 + 7 files changed, 494 insertions(+), 42 deletions(-) create mode 100644 crates/socket-patch-cli/src/commands/scan/hosted/python.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f6f0e2..eb5c1efe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -200,6 +200,11 @@ into the new version's section — see docs/releasing.md. ### Fixed +- Hosted Python redirects now warn when installed files still contain upstream + or modified bytes and omit those packages from same-run VEX. The read-only + probe covers Poetry virtualenvs, repeats on re-scans, and uses persisted patch + records if fetching fresh records fails. + - **Agent mode finds Poetry's out-of-tree virtualenv.** Poetry keeps a project's virtualenv under `{cache-dir}/virtualenvs/--py` by default, so after a plain `poetry install` the crawler saw no diff --git a/crates/socket-patch-cli/CLI_CONTRACT.md b/crates/socket-patch-cli/CLI_CONTRACT.md index 1aea53e6..95c6ec83 100644 --- a/crates/socket-patch-cli/CLI_CONTRACT.md +++ b/crates/socket-patch-cli/CLI_CONTRACT.md @@ -140,6 +140,8 @@ The rewriter reads a fixed set of candidate files from the project root: the npm The hidden alias `--no-apply` on `get --save-only` is **part of the contract** — it does not appear in `--help` but is widely used in existing scripts. +**Python stale-install guard**: after a hosted redirect, `scan` / `get` use the Python crawler to inspect every matching installed package, including Poetry's out-of-tree virtualenvs and `--global-prefix`. A readable file that differs from the patch's `afterHash` emits `redirect_pypi_stale_install` in JSON `redirect.warnings[]` and human stderr. The probe changes no installed files, re-runs on idempotent scans, and falls back to persisted patch records when fresh record fetching fails. Missing/unreadable files alone do not prove staleness; lock-only checkouts stay quiet. Dry runs skip the probe. Same-run VEX excludes positively stale Python packages (qualifier-insensitive), even with `--vex-no-verify` or a healthy copy in another interpreter; if nothing remains to attest, the command exits 1 with `no_applicable_patches`. Reinstall from the rewritten lock in the affected interpreter and verify with `socket-patch vex`. + ### Embedded VEX (`apply --vex` / `scan --vex` / `vendor --vex`) `--vex ` folds OpenVEX 0.2.0 generation into `apply`, `scan`, and `vendor`: on a successful run the command writes the document to `` using the same engine as the standalone `vex` command. The `--vex-*` flags mirror `vex`'s `--product` / `--no-verify` / `--doc-id` / `--compact` knobs (namespaced to avoid colliding with the host command), and reuse the standalone env vars (`SOCKET_VEX_PRODUCT`, etc.). They are inert unless `--vex` is set. @@ -1069,6 +1071,7 @@ Every `--json` invocation emits a single JSON object that follows the **unified | `vendor_uuid_mismatch` | `skipped` | repair: the manifest's patch uuid moved past the vendored artifact — a re-vendor (`vendor` / `scan --vendor`) is pending; repair does not cross patch generations. | | `content_mismatch_overwritten` | `skipped` (warning) | apply (default policy): a file matched NEITHER beforeHash nor afterHash and was overwritten with the full verified patched content. `--strict` turns this case into a `failed` event instead. | | `vendor_lock_checksums_unsupported` / `vendor_stale_lock_checksum` | `failed` | vendor (gem): an ambiguous/platform CHECKSUMS entry, or a v1-wired lock whose stale token blocks the hot path (run `vendor --revert` + re-vendor). | +| `redirect_pypi_stale_install` | `redirect.warnings[]` (warning) | Hosted Python redirect: readable installed files differ from patched hashes. Read-only, repeated on re-scan, and excludes the package from same-run VEX. See the "Python stale-install guard" section. | | `redirect_gem_stale_install` | `redirect.warnings[]` (warning) | scan `--mode hosted` (gem): a stale UNPATCHED materialization (installed gem, or committed `vendor/cache` archive) that `bundle install` will reuse instead of fetching the redirected patch; the detail carries the verified remedy. Full rules and flavors: the "Gem stale-install guard" section. | | `pypi_{poetry,pdm,pipenv}_no_lockfile` | `failed` | vendor (pypi): a lock-less tool marker with no `requirements.txt` fallback — run ` lock`. | | `pypi_poetry_integrity_unverified` | `skipped` (warning) | vendor (pypi / poetry): the lock was written by Poetry < 1.4 (0.12 `[metadata.hashes]`, lock 1.0/1.1, or a 2.0 lock without a `@generated by Poetry X.Y.Z` header — 1.3 wrote those). That installer does not verify local wheel hashes (the committed wheel bytes are the protection) and does not replace an already-installed package at the same version; recreate the virtualenv or `pip uninstall` the package before `poetry install`, or upgrade Poetry. | diff --git a/crates/socket-patch-cli/src/commands/scan/hosted.rs b/crates/socket-patch-cli/src/commands/scan/hosted.rs index b427b31d..6419bb2d 100644 --- a/crates/socket-patch-cli/src/commands/scan/hosted.rs +++ b/crates/socket-patch-cli/src/commands/scan/hosted.rs @@ -11,6 +11,8 @@ use crate::commands::vex::generate_vex_from_manifest_path; use super::{discover_selected, ScanArgs}; +mod python; + /// Candidate lockfiles / registry configs the redirect rewriters may touch — /// read from the project when present and handed to `rewrite_registry_redirect`. /// Fragment-edit kinds whose lockfile the package manager re-lays in place @@ -392,14 +394,13 @@ fn build_redirect_json_envelope( result } -/// The gem stale-install probe's outcome: warnings for both output channels, +/// The installed-tree probes' outcome: warnings for both output channels, /// plus the stale purls STRUCTURALLY, so the same-run `--vex` can exclude /// them from `assume_applied` — an envelope must never attest a CVE its own -/// warnings say is live. Excluded purls fall back to `vex`'s normal -/// installed-tree verification: a patched install still attests (with hash -/// evidence), a stale one is omitted. +/// warnings say is live. Python also carries positive evidence through VEX +/// so a different, healthy interpreter cannot mask a stale installation. #[derive(Default)] -struct GemStaleOutcome { +struct StaleInstallOutcome { warnings: Vec, stale_purls: std::collections::BTreeSet, } @@ -493,13 +494,13 @@ fn gem_stale_cache_warning(purl: &str, cache_path: &Path) -> serde_json::Value { /// already-patched install must not produce a delete prescription. /// (`current_hash` is `Some` only when the bytes were really hashed, which /// also excludes the absent-new-file `Ready`.) -async fn gem_stale_positive_evidence( - gem_dir: &Path, +async fn installed_stale_positive_evidence( + package_dir: &Path, record: &socket_patch_core::manifest::schema::PatchRecord, ) -> bool { use socket_patch_core::patch::apply::{verify_file_patch, VerifyStatus}; for (file_name, info) in &record.files { - let result = verify_file_patch(gem_dir, file_name, info).await; + let result = verify_file_patch(package_dir, file_name, info).await; if matches!( result.status, VerifyStatus::Ready | VerifyStatus::HashMismatch @@ -533,7 +534,7 @@ async fn gem_stale_positive_evidence( /// Judgments are grouped BY INSTALLED DIR: platform-variant purls of one /// gem resolve to the same dir, and if ANY variant's record proves the /// dir patched, the dir is patched — never warned. -/// * STALE requires [`gem_stale_positive_evidence`] — never inferred from +/// * STALE requires [`installed_stale_positive_evidence`] — never inferred from /// missing/unreadable files. /// * A committed `vendor/cache/.gem` whose sha256 differs from the /// patched artifact's is stale too (bundler installs from it first, fresh @@ -553,14 +554,14 @@ async fn gem_stale_install_warnings( socket_patch_core::manifest::schema::PatchRecord, >, gem_artifact_shas: &std::collections::BTreeMap<(String, String), String>, -) -> GemStaleOutcome { +) -> StaleInstallOutcome { use socket_patch_core::crawlers::types::CrawlerOptions; use socket_patch_core::crawlers::RubyCrawler; use socket_patch_core::manifest::schema::PatchRecord; use socket_patch_core::vendor::file_sha256_hex; use socket_patch_core::vex::verify::verify_patch_record; - let mut out = GemStaleOutcome::default(); + let mut out = StaleInstallOutcome::default(); let find_record = |uuid: &str| -> Option<&PatchRecord> { records .values() @@ -624,7 +625,7 @@ async fn gem_stale_install_warnings( }); if verify_patch_record(&pkg.path, record).await.is_ok() { entry.patched = true; - } else if !entry.positive && gem_stale_positive_evidence(&pkg.path, record).await { + } else if !entry.positive && installed_stale_positive_evidence(&pkg.path, record).await { entry.positive = true; entry.purl = (*purl).to_string(); } @@ -1933,8 +1934,8 @@ pub(crate) async fn run_redirect_selected( // the probe's ledger-record fallback could still judge an // already-redirected project, so without this gate a dry-run would warn // about state the run did not (re)create. - let gem_stale: GemStaleOutcome = if common.dry_run { - GemStaleOutcome::default() + let gem_stale: StaleInstallOutcome = if common.dry_run { + StaleInstallOutcome::default() } else { // purl-coordinate → the PATCHED .gem artifact's sha256 (registry // override identifier, tarball integrity fallback) — judges a @@ -1963,6 +1964,12 @@ pub(crate) async fn run_redirect_selected( .await }; + let python_stale = if common.dry_run { + StaleInstallOutcome::default() + } else { + python::stale_install_warnings(common, &confirmed, &records, &ledger_records).await + }; + // Cross-mode takeover: a committed vendored ledger (`.socket/vendor/state.json`) // may still claim package(s) this project also has a hosted redirect ledger // for — their tarballs would then be orphaned and that ledger stale. But the @@ -2022,8 +2029,13 @@ pub(crate) async fn run_redirect_selected( params.assume_applied = confirmed .iter() .map(|(purl, _)| purl.clone()) - .filter(|purl| !gem_stale.stale_purls.contains(purl)) + .filter(|purl| { + !gem_stale.stale_purls.contains(purl) && !python_stale.stale_purls.contains(purl) + }) .collect(); + // A healthy copy in another interpreter must not override a stale + // Python tree found by the probe, including with --vex-no-verify. + params.known_stale = python_stale.stale_purls.iter().cloned().collect(); let manifest_path = common.resolved_manifest_path(); match generate_vex_from_manifest_path(common, ¶ms, &manifest_path).await { Ok(summary) => vex_statements = Some(summary.statements), @@ -2049,6 +2061,7 @@ pub(crate) async fn run_redirect_selected( warnings.extend(rush_warnings.iter().cloned()); warnings.extend(pnpm_warnings.iter().cloned()); warnings.extend(gem_stale.warnings.iter().cloned()); + warnings.extend(python_stale.warnings.iter().cloned()); warnings.extend(takeover_pre_warnings.iter().cloned()); warnings.extend(takeover_warnings.iter().cloned()); warnings.extend(prune_warnings.iter().cloned()); @@ -2126,7 +2139,7 @@ pub(crate) async fn run_redirect_selected( for w in &pnpm_warnings { eprintln!(" warning: {}", w["detail"].as_str().unwrap_or_default()); } - for w in &gem_stale.warnings { + for w in gem_stale.warnings.iter().chain(&python_stale.warnings) { // Code included: the stale-install hazard is a silent-CVE // state, so the stderr line must be greppable by its stable // code in CI logs, same as the JSON envelope. @@ -2196,7 +2209,7 @@ pub(crate) fn boxed_run_redirect_selected<'a>( mod tests { use super::{ build_redirect_json_envelope, gem_stale_cache_warning, gem_stale_install_warning, - gem_stale_install_warnings, gem_stale_positive_evidence, parse_purl_simple, + gem_stale_install_warnings, installed_stale_positive_evidence, parse_purl_simple, plan_workspace_trust, pnpm_heal_root, pnpm_lock_carries_hosted_redirect, pnpm_lock_version_major, pnpm_trust_configured_detail, pnpm_trust_legacy_detail, pnpm_trust_manual_guidance, pnpm_trust_workspace_unreadable_detail, @@ -2748,7 +2761,7 @@ mod tests { cwd: &std::path::Path, confirmed: &[(String, String)], records: &std::collections::BTreeMap, - ) -> super::GemStaleOutcome { + ) -> super::StaleInstallOutcome { gem_stale_install_warnings( cwd, false, @@ -2856,7 +2869,7 @@ mod tests { /// transiently unreadable file in a patched install must not produce /// a delete prescription. #[tokio::test] - async fn gem_stale_positive_evidence_requires_readable_mismatched_bytes() { + async fn installed_stale_positive_evidence_requires_readable_mismatched_bytes() { let tmp = tempfile::tempdir().unwrap(); let record = gem_record(); @@ -2864,30 +2877,30 @@ mod tests { let upstream = tmp.path().join("upstream"); std::fs::create_dir_all(upstream.join("lib")).unwrap(); std::fs::write(upstream.join("lib").join("stale_unit.rb"), GEM_UPSTREAM).unwrap(); - assert!(gem_stale_positive_evidence(&upstream, &record).await); + assert!(installed_stale_positive_evidence(&upstream, &record).await); // Tampered bytes (neither hash) → evidence. let tampered = tmp.path().join("tampered"); std::fs::create_dir_all(tampered.join("lib")).unwrap(); std::fs::write(tampered.join("lib").join("stale_unit.rb"), b"other").unwrap(); - assert!(gem_stale_positive_evidence(&tampered, &record).await); + assert!(installed_stale_positive_evidence(&tampered, &record).await); // Patched bytes → no evidence. let patched = tmp.path().join("patched"); std::fs::create_dir_all(patched.join("lib")).unwrap(); std::fs::write(patched.join("lib").join("stale_unit.rb"), GEM_PATCHED).unwrap(); - assert!(!gem_stale_positive_evidence(&patched, &record).await); + assert!(!installed_stale_positive_evidence(&patched, &record).await); // Missing file → no evidence (never a guess). let hollow = tmp.path().join("hollow"); std::fs::create_dir_all(hollow.join("lib")).unwrap(); - assert!(!gem_stale_positive_evidence(&hollow, &record).await); + assert!(!installed_stale_positive_evidence(&hollow, &record).await); // A DIRECTORY at the file path (the unreadable-NotFound class) → // no evidence. let blocked = tmp.path().join("blocked"); std::fs::create_dir_all(blocked.join("lib").join("stale_unit.rb")).unwrap(); - assert!(!gem_stale_positive_evidence(&blocked, &record).await); + assert!(!installed_stale_positive_evidence(&blocked, &record).await); // Absent new-file (empty beforeHash routes to Ready with NO // current_hash) → no evidence. @@ -2897,7 +2910,7 @@ mod tests { .get_mut("lib/stale_unit.rb") .expect("fixture file entry") .before_hash = String::new(); - assert!(!gem_stale_positive_evidence(&hollow, &new_file).await); + assert!(!installed_stale_positive_evidence(&hollow, &new_file).await); } /// The probe end to end over a real deployment layout: a STALE diff --git a/crates/socket-patch-cli/src/commands/scan/hosted/python.rs b/crates/socket-patch-cli/src/commands/scan/hosted/python.rs new file mode 100644 index 00000000..37433a6c --- /dev/null +++ b/crates/socket-patch-cli/src/commands/scan/hosted/python.rs @@ -0,0 +1,172 @@ +//! Read-only installed-byte checks for hosted Python redirects. + +use std::collections::{BTreeMap, BTreeSet}; + +use socket_patch_core::crawlers::{types::CrawlerOptions, PythonCrawler}; +use socket_patch_core::manifest::schema::PatchRecord; +use socket_patch_core::utils::purl::strip_purl_qualifiers; +use socket_patch_core::vex::verify::verify_patch_record; + +use super::{installed_stale_positive_evidence, StaleInstallOutcome}; + +/// A lock rewrite cannot prove a warm virtualenv has installed the wheel. +/// Use the same discovery as apply (including Poetry's out-of-tree venvs), +/// and inspect every interpreter rather than deduplicating by package name. +/// Missing/unreadable files are not positive evidence of stale bytes. +pub(super) async fn stale_install_warnings( + common: &crate::args::GlobalArgs, + confirmed: &[(String, String)], + records: &BTreeMap, + ledger_records: &BTreeMap, +) -> StaleInstallOutcome { + let mut out = StaleInstallOutcome::default(); + let candidates: Vec<_> = confirmed + .iter() + .filter(|(purl, _)| purl.starts_with("pkg:pypi/")) + .filter_map(|(purl, uuid)| { + records + .values() + .chain(ledger_records.values()) + .find(|record| &record.uuid == uuid) + .filter(|record| !record.files.is_empty()) + .map(|record| (purl, record)) + }) + .collect(); + if candidates.is_empty() { + return out; + } + + let crawler = PythonCrawler::new(); + let paths = crawler + .get_site_packages_paths(&CrawlerOptions { + cwd: common.cwd.clone(), + global: common.global, + global_prefix: common.global_prefix.clone(), + }) + .await + .unwrap_or_default(); + + #[derive(Default)] + struct Judgment { + purls: BTreeSet, + patched: bool, + stale: bool, + } + // Python distributions share site-packages, so the key must include + // the package identity. Any matching artifact variant can prove this + // package patched; a healthy *different* package cannot. + let mut judgments = BTreeMap::new(); + for (purl, record) in candidates { + let base = strip_purl_qualifiers(purl).to_string(); + for site in &paths { + let found = crawler + .find_by_purls(site, std::slice::from_ref(&base)) + .await + .unwrap_or_default(); + let Some(pkg) = found.get(&base) else { + continue; + }; + let judgment: &mut Judgment = judgments + .entry((pkg.path.clone(), pkg.name.clone(), pkg.version.clone())) + .or_default(); + judgment.purls.insert(purl.clone()); + if verify_patch_record(&pkg.path, record).await.is_ok() { + judgment.patched = true; + } else if installed_stale_positive_evidence(&pkg.path, record).await { + judgment.stale = true; + } + } + } + for ((site, _, _), judgment) in judgments { + if judgment.patched || !judgment.stale { + continue; + } + for purl in judgment.purls { + out.warnings.push(serde_json::json!({ + "code": "redirect_pypi_stale_install", + "detail": format!( + "{purl} was redirected to a hosted patch, but installed files in {} \ + still differ from the patched hashes. Reinstall from the rewritten \ + lock in this interpreter and verify with `socket-patch vex`. \ + Poetry before 1.4 may keep same-version packages: recreate the \ + project virtualenv or uninstall this package before installing. \ + The installed files were left unchanged.", + site.display() + ), + })); + out.stale_purls.insert(purl); + } + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + use socket_patch_core::hash::git_sha256::compute_git_sha256_from_bytes; + use socket_patch_core::manifest::schema::PatchFileInfo; + + fn record(uuid: &str, file: &str, patched: &[u8]) -> PatchRecord { + PatchRecord { + uuid: uuid.to_string(), + exported_at: "2026-09-17T00:00:00Z".to_string(), + files: [( + file.to_string(), + PatchFileInfo { + before_hash: compute_git_sha256_from_bytes(b"upstream"), + after_hash: compute_git_sha256_from_bytes(patched), + }, + )] + .into(), + vulnerabilities: Default::default(), + description: String::new(), + license: String::new(), + tier: "free".to_string(), + } + } + + #[tokio::test] + async fn prefix_probe_groups_variants_by_package_and_uses_ledger_records() { + let tmp = tempfile::tempdir().unwrap(); + let site = tmp.path().join("custom-site-packages"); + for name in ["first", "second"] { + std::fs::create_dir_all(site.join(format!("{name}-1.0.dist-info"))).unwrap(); + } + std::fs::write(site.join("first.py"), b"upstream").unwrap(); + std::fs::write(site.join("second.py"), b"patched").unwrap(); + let common = crate::args::GlobalArgs { + cwd: tmp.path().to_path_buf(), + global_prefix: Some(site.clone()), + ..Default::default() + }; + let first = "pkg:pypi/first@1.0?artifact_id=one"; + let second = "pkg:pypi/second@1.0"; + let mut confirmed = vec![ + (first.to_string(), "first-uuid".to_string()), + (second.to_string(), "second-uuid".to_string()), + ]; + // Deliberately unrelated keys: lookup must use each record's UUID. + let mut ledger = BTreeMap::from([ + ("one".into(), record("first-uuid", "first.py", b"patched")), + ("two".into(), record("second-uuid", "second.py", b"patched")), + ]); + let out = stale_install_warnings(&common, &confirmed, &BTreeMap::new(), &ledger).await; + assert_eq!(out.stale_purls, BTreeSet::from([first.to_string()])); + assert_eq!(out.warnings.len(), 1); + assert!(out.warnings[0]["detail"] + .as_str() + .unwrap() + .contains(&site.display().to_string())); + + // An installed package can match a different wheel variant. That + // variant, unlike the healthy sibling distribution, proves it patched. + confirmed.push(( + "pkg:pypi/first@1.0?artifact_id=two".into(), + "variant".into(), + )); + ledger.insert("three".into(), record("variant", "first.py", b"upstream")); + let out = stale_install_warnings(&common, &confirmed, &BTreeMap::new(), &ledger).await; + assert!(out.stale_purls.is_empty()); + assert!(out.warnings.is_empty()); + } +} diff --git a/crates/socket-patch-cli/src/commands/vex.rs b/crates/socket-patch-cli/src/commands/vex.rs index 9e7d5015..fdfecdf5 100644 --- a/crates/socket-patch-cli/src/commands/vex.rs +++ b/crates/socket-patch-cli/src/commands/vex.rs @@ -157,6 +157,7 @@ impl VexEmbedArgs { doc_id: self.vex_doc_id.clone(), compact: self.vex_compact, assume_applied: Vec::new(), + known_stale: Vec::new(), } } } @@ -180,6 +181,9 @@ pub(crate) struct VexBuildParams { /// standalone `vex` passes an empty list so redirected patches are then /// hash-verified against the installed tree like any applied patch. pub assume_applied: Vec, + /// Hosted probes positively identified unpatched installed bytes. These + /// PURLs cannot be attested by another interpreter or --no-verify. + pub known_stale: Vec, } /// Successful result of [`generate_vex`]. @@ -233,6 +237,7 @@ pub async fn run(args: VexArgs) -> i32 { doc_id: args.doc_id.clone(), compact: args.compact, assume_applied: Vec::new(), + known_stale: Vec::new(), }; let manifest_path = args.common.resolved_manifest_path(); @@ -418,6 +423,26 @@ async fn generate_vex( } } + // Positive evidence from a hosted probe takes precedence over an + // assumed redirect or a healthy copy found in a different interpreter. + if !params.known_stale.is_empty() { + use socket_patch_core::utils::purl::strip_purl_qualifiers; + let stale: std::collections::HashSet<&str> = params + .known_stale + .iter() + .map(|purl| strip_purl_qualifiers(purl)) + .collect(); + let is_stale = |purl: &str| stale.contains(strip_purl_qualifiers(purl)); + outcome.applied.retain(|purl| !is_stale(purl)); + outcome.failed.retain(|failure| !is_stale(&failure.purl)); + outcome.failed.extend(manifest.patches.keys().filter(|purl| is_stale(purl)).map( + |purl| FailedPatch { + purl: purl.clone(), + reason: "stale_install".to_string(), + }, + )); + } + // Vendored disclosure: the committed artifact verified (the attestation // stands — the committables are what the lockfile consumes) but the LIVE // installed tree is present and running different bytes. Say so — a diff --git a/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs b/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs index 91ff7346..5daf55a7 100644 --- a/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs +++ b/crates/socket-patch-cli/tests/in_process_redirect_poetry.rs @@ -14,6 +14,7 @@ use socket_patch_cli::args::GlobalArgs; use socket_patch_cli::commands::rollback::{self, RollbackArgs}; use socket_patch_cli::commands::scan::{run, ScanArgs}; use socket_patch_cli::commands::vex::VexEmbedArgs; +use socket_patch_core::hash::git_sha256::compute_git_sha256_from_bytes; use wiremock::matchers::{method, path, path_regex}; use wiremock::{Mock, MockServer, ResponseTemplate}; @@ -26,6 +27,8 @@ const RECORD_PURL: &str = "pkg:pypi/urllib3@1.26.18?artifact_id=py2-py3-none-any const UUID: &str = "e828efa5-5c6d-43f3-9909-03f5ac232b98"; const HOSTED_URL: &str = "http://patch.test/patch/pypi/urllib3/1.26.18/22222222-2222-4222-8222-222222222222/e828efa5-5c6d-43f3-9909-03f5ac232b98/urllib3-1.26.18-py2.py3-none-any.whl"; const GHSA: &str = "GHSA-gm62-xv2j-4w53"; +const UPSTREAM: &[u8] = b"upstream response implementation\n"; +const PATCHED: &[u8] = b"patched response implementation\n"; const LOCK: &str = include_str!("../../socket-patch-core/tests/fixtures/poetry/2.4.3/poetry.lock"); /// Poetry 1.2.2's native lock (lock-version 1.1, populated `[metadata.files]`). @@ -87,7 +90,9 @@ async fn mock_api(server: &MockServer) { .mount(server) .await; Mock::given(method("GET")) - .and(path_regex(format!("^/v0/orgs/{ORG}/patches/by-package/.+$"))) + .and(path_regex(format!( + "^/v0/orgs/{ORG}/patches/by-package/.+$" + ))) .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ "patches": [{ "uuid": UUID, "purl": RECORD_PURL, @@ -126,8 +131,8 @@ async fn mock_api(server: &MockServer) { "publishedAt": "2026-07-29T20:20:47Z", "files": { "urllib3/response.py": { - "beforeHash": "a".repeat(64), - "afterHash": "b".repeat(64), + "beforeHash": compute_git_sha256_from_bytes(UPSTREAM), + "afterHash": compute_git_sha256_from_bytes(PATCHED), } }, "vulnerabilities": { @@ -154,7 +159,10 @@ fn write_project(root: &Path) { let site = if cfg!(windows) { root.join(".venv").join("Lib").join("site-packages") } else { - root.join(".venv").join("lib").join("python3.12").join("site-packages") + root.join(".venv") + .join("lib") + .join("python3.12") + .join("site-packages") }; std::fs::create_dir_all(site).unwrap(); } @@ -183,10 +191,15 @@ async fn lock_only_poetry_project_redirects_attests_rescans_and_rolls_back() { "{redirected}" ); assert!(redirected.contains("type = \"url\""), "{redirected}"); - assert_eq!(read(&tmp.path().join("pyproject.toml")), PYPROJECT, "pyproject untouched"); - let ledger: serde_json::Value = - serde_json::from_str(&read(&tmp.path().join(".socket/vendor/redirect-state.json"))) - .unwrap(); + assert_eq!( + read(&tmp.path().join("pyproject.toml")), + PYPROJECT, + "pyproject untouched" + ); + let ledger: serde_json::Value = serde_json::from_str(&read( + &tmp.path().join(".socket/vendor/redirect-state.json"), + )) + .unwrap(); assert!( ledger["records"][RECORD_PURL].is_object(), "ledger keyed by the artifact-qualified purl: {ledger}" @@ -211,7 +224,11 @@ async fn lock_only_poetry_project_redirects_attests_rescans_and_rolls_back() { // 2. Idempotent re-scan: no further edits, lock byte-identical. let code = run(hosted_args(tmp.path(), server.uri(), None)).await; assert_eq!(code, 0); - assert_eq!(read(&lock_path), redirected, "re-scan must not touch the lock"); + assert_eq!( + read(&lock_path), + redirected, + "re-scan must not touch the lock" + ); // 3. rollback unwinds the redirect and drops the record. let code = rollback::run(RollbackArgs { @@ -222,7 +239,11 @@ async fn lock_only_poetry_project_redirects_attests_rescans_and_rolls_back() { }) .await; assert_eq!(code, 0, "rollback must succeed"); - assert_eq!(read(&lock_path), LOCK, "rollback must restore the pristine lock byte for byte"); + assert_eq!( + read(&lock_path), + LOCK, + "rollback must restore the pristine lock byte for byte" + ); let ledger_path = tmp.path().join(".socket/vendor/redirect-state.json"); if ledger_path.exists() { let ledger: serde_json::Value = serde_json::from_str(&read(&ledger_path)).unwrap(); @@ -240,6 +261,7 @@ async fn lock_only_poetry_project_redirects_attests_rescans_and_rolls_back() { /// `files` line, and re-lays the `[metadata.files]` entry from the CLI's /// inline table into Poetry's multi-line array. fn simulate_poetry_1x_relock(lock: &str) -> String { + let newline = if lock.contains("\r\n") { "\r\n" } else { "\n" }; let mut out = String::new(); for line in lock.lines() { if line.starts_with("files = [{ file = ") { @@ -255,7 +277,7 @@ fn simulate_poetry_1x_relock(lock: &str) -> String { out.push_str(line); out.push('\n'); } - out + out.replace("\n", newline) } /// Relock → re-scan → rollback must still land on the pristine lock. The @@ -265,18 +287,30 @@ fn simulate_poetry_1x_relock(lock: &str) -> String { #[tokio::test] #[serial] async fn relock_then_rescan_keeps_rollback_invertible() { + // Checkout settings must not decide which newline shape this test covers. + for newline in ["\n", "\r\n"] { + let lock = LOCK_1_1.replace("\r\n", "\n").replace("\n", newline); + assert_relock_roundtrip(&lock).await; + } +} + +async fn assert_relock_roundtrip(lock: &str) { let server = MockServer::start().await; mock_api(&server).await; let tmp = tempfile::tempdir().unwrap(); write_project(tmp.path()); let lock_path = tmp.path().join("poetry.lock"); - std::fs::write(&lock_path, LOCK_1_1).unwrap(); + std::fs::write(&lock_path, lock).unwrap(); assert_eq!(run(hosted_args(tmp.path(), server.uri(), None)).await, 0); let redirected = read(&lock_path); let ledger_path = tmp.path().join(".socket/vendor/redirect-state.json"); let ledger: serde_json::Value = serde_json::from_str(&read(&ledger_path)).unwrap(); - assert_eq!(ledger["edits"].as_array().unwrap().len(), 2, "package + metadata fragments"); + assert_eq!( + ledger["edits"].as_array().unwrap().len(), + 2, + "package + metadata fragments" + ); let relocked = simulate_poetry_1x_relock(&redirected); assert_ne!(relocked, redirected); @@ -286,15 +320,24 @@ async fn relock_then_rescan_keeps_rollback_invertible() { // Re-scan: the unit lost its `files` line, so the rewriter writes again. assert_eq!(run(hosted_args(tmp.path(), server.uri(), None)).await, 0); let rescanned = read(&lock_path); - assert_ne!(rescanned, relocked, "the re-scan must restore the package files entry"); + assert_ne!( + rescanned, relocked, + "the re-scan must restore the package files entry" + ); let ledger: serde_json::Value = serde_json::from_str(&read(&ledger_path)).unwrap(); let edits = ledger["edits"].as_array().unwrap(); assert_eq!(edits.len(), 2, "rebased, not appended: {ledger}"); for edit in edits { let original = edit["original"].as_str().unwrap(); - assert!(!original.contains(HOSTED_URL), "originals stay pristine: {original}"); + assert!( + !original.contains(HOSTED_URL), + "originals stay pristine: {original}" + ); let new = edit["new"].as_str().unwrap(); - assert!(rescanned.contains(new), "new fragments describe the current lock"); + assert!( + rescanned.contains(new), + "new fragments describe the current lock" + ); } let code = rollback::run(RollbackArgs { @@ -305,5 +348,187 @@ async fn relock_then_rescan_keeps_rollback_invertible() { }) .await; assert_eq!(code, 0, "rollback after relock + re-scan must succeed"); - assert_eq!(read(&lock_path), LOCK_1_1, "pristine lock restored byte for byte"); + assert_eq!( + read(&lock_path), + lock, + "pristine lock restored byte for byte" + ); +} + +fn install_package(root: &Path, venv: &str, bytes: &[u8]) -> std::path::PathBuf { + let site = if cfg!(windows) { + root.join(venv).join("Lib").join("site-packages") + } else { + root.join(venv) + .join("lib") + .join("python3.12") + .join("site-packages") + }; + std::fs::create_dir_all(site.join("urllib3-1.26.18.dist-info")).unwrap(); + std::fs::create_dir_all(site.join("urllib3")).unwrap(); + let file = site.join("urllib3").join("response.py"); + std::fs::write(&file, bytes).unwrap(); + file +} + +async fn scan_output(root: &Path, server: &MockServer, extra: &[&str]) -> std::process::Output { + let mut cmd = tokio::process::Command::new(env!("CARGO_BIN_EXE_socket-patch")); + for (key, _) in std::env::vars_os() { + let name = key.to_string_lossy(); + if name.starts_with("SOCKET_") || name.starts_with("POETRY_") || name == "VIRTUAL_ENV" { + cmd.env_remove(key); + } + } + cmd.env("SOCKET_TELEMETRY_DISABLED", "1") + .args(["scan", "--mode", "hosted", "--yes", "--cwd"]) + .arg(root) + .args([ + "--api-url", + &server.uri(), + "--org", + ORG, + "--api-token", + "fake", + ]) + .args(extra); + cmd.output().await.unwrap() +} + +fn envelope(out: &std::process::Output) -> serde_json::Value { + serde_json::from_slice(&out.stdout).unwrap_or_else(|error| { + panic!( + "{error}: stdout={} stderr={}", + String::from_utf8_lossy(&out.stdout), + String::from_utf8_lossy(&out.stderr) + ) + }) +} + +fn stale_warning(value: &serde_json::Value) -> bool { + value["redirect"]["warnings"] + .as_array() + .unwrap() + .iter() + .any(|warning| warning["code"] == "redirect_pypi_stale_install") +} + +/// Both upstream and locally modified warm installs must be diagnosed on +/// every scan. Merely rewriting the lock must never attest their live bytes. +#[tokio::test] +async fn stale_python_install_warns_and_cannot_attest_even_on_rescan() { + for bytes in [UPSTREAM, b"local modification\n".as_slice()] { + let server = MockServer::start().await; + mock_api(&server).await; + let tmp = tempfile::tempdir().unwrap(); + write_project(tmp.path()); + let installed = install_package(tmp.path(), ".venv", bytes); + let out = scan_output(tmp.path(), &server, &["--json"]).await; + let json = envelope(&out); + assert!(out.status.success(), "{json}"); + assert_eq!(json["redirect"]["redirected"], 1, "{json}"); + assert!(stale_warning(&json), "{json}"); + let redirected = read(&tmp.path().join("poetry.lock")); + let vex = tmp.path().join("out.vex.json"); + for extra in [ + vec!["--json", "--vex", vex.to_str().unwrap()], + vec!["--json", "--vex", vex.to_str().unwrap(), "--vex-no-verify"], + ] { + let out = scan_output(tmp.path(), &server, &extra).await; + let json = envelope(&out); + assert_eq!(out.status.code(), Some(1), "{json}"); + assert!(stale_warning(&json), "{json}"); + assert_eq!(json["error"]["code"], "no_applicable_patches", "{json}"); + assert!(!vex.exists(), "stale bytes cannot produce a VEX file"); + } + // A failed fresh record fetch must not bypass the persisted evidence. + Mock::given(method("GET")) + .and(path(format!("/v0/orgs/{ORG}/patches/view/{UUID}"))) + .respond_with(ResponseTemplate::new(404)) + .with_priority(1) + .mount(&server) + .await; + let out = scan_output(tmp.path(), &server, &[]).await; + assert!( + out.status.success(), + "{}", + String::from_utf8_lossy(&out.stderr) + ); + assert!(String::from_utf8_lossy(&out.stderr).contains("redirect_pypi_stale_install")); + assert_eq!( + std::fs::read(installed).unwrap(), + bytes, + "probe is read-only" + ); + assert_eq!(read(&tmp.path().join("poetry.lock")), redirected); + } +} + +#[tokio::test] +async fn patched_python_install_attests_without_a_stale_warning() { + let server = MockServer::start().await; + mock_api(&server).await; + let tmp = tempfile::tempdir().unwrap(); + write_project(tmp.path()); + let installed = install_package(tmp.path(), ".venv", PATCHED); + let vex = tmp.path().join("out.vex.json"); + let out = scan_output( + tmp.path(), + &server, + &["--json", "--vex", vex.to_str().unwrap()], + ) + .await; + let json = envelope(&out); + assert!(out.status.success(), "{json}"); + assert!(!stale_warning(&json), "{json}"); + assert_eq!(json["vex"]["statements"], 1, "{json}"); + assert_eq!(std::fs::read(installed).unwrap(), PATCHED); +} + +#[tokio::test] +async fn healthy_interpreter_cannot_mask_a_stale_python_install() { + let server = MockServer::start().await; + mock_api(&server).await; + let tmp = tempfile::tempdir().unwrap(); + write_project(tmp.path()); + install_package(tmp.path(), ".venv", PATCHED); + install_package(tmp.path(), "venv", UPSTREAM); + let vex = tmp.path().join("out.vex.json"); + let out = scan_output( + tmp.path(), + &server, + &["--json", "--vex", vex.to_str().unwrap()], + ) + .await; + let json = envelope(&out); + assert_eq!(out.status.code(), Some(1), "{json}"); + assert!(stale_warning(&json), "{json}"); + assert!(!vex.exists()); +} + +#[tokio::test] +async fn python_probe_does_not_guess_staleness_or_run_on_dry_run() { + let server = MockServer::start().await; + mock_api(&server).await; + let tmp = tempfile::tempdir().unwrap(); + write_project(tmp.path()); + let installed = install_package(tmp.path(), ".venv", UPSTREAM); + let out = scan_output(tmp.path(), &server, &["--json", "--dry-run"]).await; + let json = envelope(&out); + assert!(out.status.success(), "{json}"); + assert!(!stale_warning(&json), "{json}"); + assert_eq!(read(&tmp.path().join("poetry.lock")), LOCK); + assert!(!tmp + .path() + .join(".socket/vendor/redirect-state.json") + .exists()); + std::fs::remove_file(&installed).unwrap(); + for unreadable in [false, true] { + if unreadable { + std::fs::create_dir(&installed).unwrap(); + } + let out = scan_output(tmp.path(), &server, &["--json"]).await; + let json = envelope(&out); + assert!(out.status.success(), "{json}"); + assert!(!stale_warning(&json), "{json}"); + } } diff --git a/docs/testing/poetry-compatibility.md b/docs/testing/poetry-compatibility.md index 59eb205c..381c9419 100644 --- a/docs/testing/poetry-compatibility.md +++ b/docs/testing/poetry-compatibility.md @@ -71,6 +71,15 @@ Two consequences for Poetry releases before 1.4: release from 1.0 on by the default installer (Poetry's deprecated pip backend, `experimental.new-installer = false`, verifies nothing). +Hosted mode also checks the installed package's bytes, independently of the lock's +writer version. `redirect_pypi_stale_install` means readable files in a discovered +interpreter still differ from the patched hashes. This read-only check repeats on +re-scans and excludes the package from same-run VEX, even with +`--vex-no-verify` or a healthy copy in another interpreter. If no patches remain +to attest, `--vex` fails with `no_applicable_patches`. Reinstall in the affected +interpreter, then verify with `socket-patch vex`. A lock-only checkout has no +installed bytes to judge and keeps the existing lock-based attestation behavior. + Other measured details: - `poetry lock --no-update` (1.1–1.8) and bare `poetry lock` (2.x) keep the From 106645c41c687823719a40c9eaba90a8f2dd156b Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Thu, 17 Sep 2026 17:55:32 -0400 Subject: [PATCH 19/19] Retry Windows delete-pending race in apply lock test Treat ERROR_ACCESS_DENIED from an open racing the deliberate lock-file deletion as a benign test interleaving on Windows. Retry within the existing bound and still require a clean mutually exclusive acquisition. Production lock acquisition and error handling are unchanged. Assisted-by: Codex:gpt-6-astra --- .../socket-patch-core/src/patch/apply_lock.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/socket-patch-core/src/patch/apply_lock.rs b/crates/socket-patch-core/src/patch/apply_lock.rs index 518a1315..abd19f6f 100644 --- a/crates/socket-patch-core/src/patch/apply_lock.rs +++ b/crates/socket-patch-core/src/patch/apply_lock.rs @@ -360,8 +360,8 @@ mod tests { /// lock exists to prevent. Re-opening the path on every retry keeps /// the waiter honest about whatever file `apply.lock` names now. /// - /// The choreography below can lose two *benign* races on a loaded - /// runner (both observed on CI's macos-latest), so it retries: the + /// The choreography below can lose benign races on a loaded runner + /// (observed on macOS and Windows CI), so it retries: the /// regressed bug double-holds on essentially every iteration, while /// the benign losses need an unlucky deschedule and almost never /// repeat. One clean iteration proves the re-open behavior; a full @@ -430,6 +430,28 @@ mod tests { (Ok(_fresh_guard), Ok(_waiter_guard)) => { benign.push("double hold via the open->flock window"); } + // Windows can keep an unlinked file delete-pending until + // its last handle closes. CreateFile then returns + // ERROR_ACCESS_DENIED (5), including when the waiter is + // reopening while the fresh acquire races that cleanup. + // Neither an I/O refusal nor Held grants a second lock. + // Retry this choreography; still require a clean Held + // iteration above, and never relax acquire's I/O errors. + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea + #[cfg(windows)] + (Ok(_) | Err(LockError::Held), Err(LockError::Io { source, .. })) + | (Err(LockError::Io { source, .. }), Ok(_) | Err(LockError::Held)) + if source.raw_os_error() == Some(5) => + { + benign.push("open raced Windows delete-pending handle"); + } + #[cfg(windows)] + ( + Err(LockError::Io { source: first, .. }), + Err(LockError::Io { source: second, .. }), + ) if first.raw_os_error() == Some(5) && second.raw_os_error() == Some(5) => { + benign.push("both opens raced Windows delete-pending handle"); + } (fresh, waiter_result) => panic!( "unexpected lock outcome: fresh={:?} waiter={:?}", fresh.map(|_| "Ok(guard)"),