From 5db779cfa726ee93e5936093400787e67dcf4956 Mon Sep 17 00:00:00 2001 From: Rain Date: Sun, 11 Aug 2024 13:59:47 -0700 Subject: [PATCH] [taplo-common] fix infinite recursion with composed allOfs --- Cargo.lock | 10 +++--- crates/taplo-common/Cargo.toml | 6 ++++ crates/taplo-common/src/schema/mod.rs | 46 ++++++++++++++++++++++++-- test-data/schemas/all-of-composed.json | 23 +++++++++++++ 4 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 test-data/schemas/all-of-composed.json diff --git a/Cargo.lock b/Cargo.lock index 97c2b8d3a..60e76f9a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1116,7 +1116,7 @@ dependencies = [ [[package]] name = "lsp-async-stub" -version = "0.6.3" +version = "0.6.4" dependencies = [ "anyhow", "async-trait", @@ -2165,7 +2165,7 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "taplo" -version = "0.13.1" +version = "0.13.2" dependencies = [ "ahash 0.8.8", "arc-swap", @@ -2190,7 +2190,7 @@ dependencies = [ [[package]] name = "taplo-cli" -version = "0.9.2" +version = "0.9.3" dependencies = [ "ansi_term", "anyhow", @@ -2223,7 +2223,7 @@ dependencies = [ [[package]] name = "taplo-common" -version = "0.5.1" +version = "0.5.2" dependencies = [ "ahash 0.8.8", "anyhow", @@ -2261,7 +2261,7 @@ dependencies = [ [[package]] name = "taplo-lsp" -version = "0.7.1" +version = "0.7.2" dependencies = [ "anyhow", "arc-swap", diff --git a/crates/taplo-common/Cargo.toml b/crates/taplo-common/Cargo.toml index 10356b81a..32e4b4887 100644 --- a/crates/taplo-common/Cargo.toml +++ b/crates/taplo-common/Cargo.toml @@ -59,6 +59,12 @@ tokio = { version = "1.24.2", features = [ "io-util", ], default-features = false } +[dev-dependencies] +tokio = { version = "1.24.2", features = [ + "macros", + "test-util", +] } + [features] # default-tls enables native-tls but without enabling native-tls specific features. native-tls = ["reqwest/default-tls"] diff --git a/crates/taplo-common/src/schema/mod.rs b/crates/taplo-common/src/schema/mod.rs index 206e7df9f..e3db8a2ac 100644 --- a/crates/taplo-common/src/schema/mod.rs +++ b/crates/taplo-common/src/schema/mod.rs @@ -543,9 +543,12 @@ impl Schemas { if let Some(all_ofs) = schema["allOf"].as_array() { if !all_ofs.is_empty() && composed { let mut schema = schema.clone(); - if let Some(obj) = schema["allOf"].as_object_mut() { - obj.remove("allOf"); - } + // Remove the allOf because we're resolving in this spot -- not doing so will cause + // infinite recursion. + schema + .as_object_mut() + .expect("schema is an object") + .remove("allOf"); let mut merged_all_of = Value::Object(serde_json::Map::default()); @@ -720,3 +723,40 @@ mod formats { semver::VersionReq::parse(value).is_ok() } } + +#[cfg(test)] +mod tests { + use std::path::Path; + + use crate::environment::native::NativeEnvironment; + + use super::*; + + #[tokio::test] + async fn test_all_of_composed() { + let schemas = new_schemas(); + let schema_url = url_for_test_schema("all-of-composed.json"); + + // Ensure this doesn't panic: this ensures that allOfs don't cause infinite recursion. + schemas + .possible_schemas_from(&schema_url, &serde_json::Value::Null, &Keys::empty(), 8) + .await + .unwrap(); + } + + fn new_schemas() -> Schemas { + Schemas::new(NativeEnvironment::new(), reqwest::Client::new()) + } + + fn url_for_test_schema(name: &str) -> Url { + let dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let path = dir + .parent() + .unwrap() + .parent() + .unwrap() + .join("test-data/schemas") + .join(name); + Url::parse(&format!("file://{}", path.display())).unwrap() + } +} diff --git a/test-data/schemas/all-of-composed.json b/test-data/schemas/all-of-composed.json new file mode 100644 index 000000000..62f22539a --- /dev/null +++ b/test-data/schemas/all-of-composed.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "duration": { + "allOf": [ + { + "$ref": "#/definitions/Duration" + } + ] + } + }, + "definitions": { + "Duration": { + "title": "Duration", + "description": "A duration, specified in a human-readable format.", + "examples": [ + "60s", + "1w 3d" + ], + "type": "string" + } + } +}