From d0c1cfe55687592b3e725b890b2bad484ab65f8f Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Tue, 20 Oct 2026 15:00:20 +0400 Subject: [PATCH 1/2] Fix dependency advisories and harden ZIP permissions Update rustls to 0.23.46 and replace serde_yaml/unsafe-libyaml with serde-saphyr 2.0.0 in runtime and E2E configuration parsing. ZIP is already at patched version 9.0.3; additionally mask special permission bits in Mason extraction. Add YAML alias/scalar compatibility coverage and ZIP permission regression tests. cargo deny check, make test (470 passed, one ignored), cargo fmt --check, and Clippy passed. The complete real-server E2E suite ran but failed on GitHub API rate limits fetching Mason metadata and missing java25; real-server validation remains incomplete. --- Cargo.lock | 136 +++++++++++++++++++++++++++------ Cargo.toml | 2 +- src/config.rs | 6 +- src/config_tests.rs | 17 +++++ src/mason/install/artifacts.rs | 15 +++- src/mason/install/tests.rs | 40 ++++++++-- tests/e2e/Cargo.toml | 2 +- tests/e2e/case_files.rs | 2 +- tests/e2e/manifest_tests.rs | 6 +- 9 files changed, 185 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e01b2fa..c548f84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "annotate-snippets" +version = "0.12.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a5b0a5ab8561c603f16c3b78c24a386b1f70e7fc1b1b1e8c15738828e4a176" +dependencies = [ + "anstyle", + "memchr", + "unicode-width", +] + [[package]] name = "anstream" version = "1.0.0" @@ -73,12 +84,24 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + [[package]] name = "backon" version = "1.6.0" @@ -226,6 +249,12 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + [[package]] name = "cpufeatures" version = "0.3.0" @@ -290,6 +319,29 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "encoding_rs" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" +dependencies = [ + "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + +[[package]] +name = "encoding_rs_io" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba3fe847045ecff794b9c138293a80db914678c453ad63fbf0c6a9eb6e00b22" +dependencies = [ + "encoding_rs", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -459,6 +511,16 @@ dependencies = [ "wasip3", ] +[[package]] +name = "granit-parser" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da55feca5d1625466bae068f9fd4b87892caeae70c3fe671ddb0f50d41aebf37" +dependencies = [ + "arraydeque", + "smallvec", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -818,8 +880,8 @@ dependencies = [ "regex", "reqwest", "serde", + "serde-saphyr", "serde_json", - "serde_yaml", "sha2", "shlex 2.0.1", "tar", @@ -840,8 +902,8 @@ dependencies = [ "nix 0.31.3", "reqwest", "serde", + "serde-saphyr", "serde_json", - "serde_yaml", "sha2", "tar", "tempfile", @@ -901,6 +963,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + [[package]] name = "nix" version = "0.27.1" @@ -924,6 +992,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1209,9 +1286,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.45" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "once_cell", "ring", @@ -1254,6 +1331,12 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "semver" version = "1.0.28" @@ -1270,6 +1353,20 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-saphyr" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a253edfdea34032da21af84e16fcc94f4c7a6ba237f9f3bc2dbf43cea8535c44" +dependencies = [ + "annotate-snippets", + "encoding_rs_io", + "granit-parser", + "num-traits", + "serde_core", + "smallvec", +] + [[package]] name = "serde_core" version = "1.0.229" @@ -1326,19 +1423,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sha2" version = "0.11.1" @@ -1368,6 +1452,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.12" @@ -1632,16 +1722,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] -name = "unicode-xid" -version = "0.2.6" +name = "unicode-width" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] -name = "unsafe-libyaml" -version = "0.2.11" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" diff --git a/Cargo.toml b/Cargo.toml index 4ec6ee2..4d94761 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ regex = "1.11.1" reqwest = { version = "0.12.24", default-features = false, features = ["blocking", "json", "rustls-tls"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.150" -serde_yaml = "0.9.34" +serde-saphyr = { version = "2.0.0", default-features = false, features = ["deserialize"] } sha2 = "0.11.0" shlex = "2.0.1" tar = "0.4.46" diff --git a/src/config.rs b/src/config.rs index 8d7582f..407ed4f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -237,7 +237,7 @@ fn load_optional_cli_config_file(path: &Path) -> Result { } let contents = path_fs::read_to_string(path)?; - let file: CliConfigFile = serde_yaml::from_str(&contents) + let file: CliConfigFile = serde_saphyr::from_str(&contents) .map_err(|error| Error::config_format(path_fs::format_path_error(path, error)))?; Ok(CliConfig::from(file)) } @@ -351,7 +351,7 @@ fn load_filetypes(dir: &Path) -> Result> { .into_iter() .map(|path| { let contents = path_fs::read_to_string(&path)?; - let file: FiletypeFile = serde_yaml::from_str(&contents) + let file: FiletypeFile = serde_saphyr::from_str(&contents) .map_err(|error| Error::config_format(path_fs::format_path_error(&path, error)))?; let Some(stem) = path.file_stem().and_then(|value| value.to_str()) else { return Err(Error::config_format(format!( @@ -393,7 +393,7 @@ fn load_lsps(dir: &Path) -> Result> { .into_iter() .map(|path| { let contents = path_fs::read_to_string(&path)?; - let file: LspFile = serde_yaml::from_str(&contents) + let file: LspFile = serde_saphyr::from_str(&contents) .map_err(|error| Error::config_format(path_fs::format_path_error(&path, error)))?; let Some(stem) = path.file_stem().and_then(|value| value.to_str()) else { return Err(Error::config_format(format!( diff --git a/src/config_tests.rs b/src/config_tests.rs index 9b05769..8bb3deb 100644 --- a/src/config_tests.rs +++ b/src/config_tests.rs @@ -387,3 +387,20 @@ fn rejects_invalid_request_window_sizes() { assert!(error.contains("max-requests-in-flight must be a positive integer")); } } + +#[test] +fn loads_yaml_aliases_and_string_scalars() { + let global = TestDir::new("cli-config-yaml-aliases"); + global.write_file( + "lsp-cli.yaml", + "lsp:\n first: &servers\n - on\n - '123'\n second: *servers\n", + ); + + let config = load_cli_config(global.path(), None).expect("YAML aliases should load"); + + assert_eq!(config.lsp_preferences["first"], ["on", "123"]); + assert_eq!( + config.lsp_preferences["second"], + config.lsp_preferences["first"] + ); +} diff --git a/src/mason/install/artifacts.rs b/src/mason/install/artifacts.rs index 16175f8..c905cae 100644 --- a/src/mason/install/artifacts.rs +++ b/src/mason/install/artifacts.rs @@ -446,7 +446,8 @@ fn ensure_decompressed_size_limit(size: u64, path: &str) -> Result<()> { #[cfg(unix)] fn owner_writable_mode(mode: u32) -> u32 { - mode & !0o022 + // Archive permissions must not grant special privileges to installed files. + (mode & 0o777) & !0o022 } fn write_file(path: &Path, bytes: &[u8]) -> Result<()> { @@ -466,3 +467,15 @@ pub(super) fn parse_archive_file_spec(file: &str) -> (&str, Option<&str>) { None => (file, None), } } + +#[cfg(all(test, unix))] +mod tests { + use super::owner_writable_mode; + + #[test] + fn archive_modes_cannot_grant_special_privileges() { + for (mode, expected) in [(0o107_777, 0o755), (0o106_666, 0o644), (0o100_700, 0o700)] { + assert_eq!(owner_writable_mode(mode), expected); + } + } +} diff --git a/src/mason/install/tests.rs b/src/mason/install/tests.rs index 20a8067..ca4c81f 100644 --- a/src/mason/install/tests.rs +++ b/src/mason/install/tests.rs @@ -30,20 +30,25 @@ fn parses_archive_file_spec() { ); } -#[test] -fn extracts_vsix_as_a_zip_archive() { - let directory = tempfile::tempdir().expect("temporary directory should initialize"); +fn zip_with_file(path: &str, mode: u32) -> Vec { let mut archive = zip::ZipWriter::new(Cursor::new(Vec::new())); archive .start_file( - "extension/server/dist/server.js", - zip::write::SimpleFileOptions::default(), + path, + // Encode special bits in the archive to exercise extraction of untrusted modes. + zip::write::SimpleFileOptions::default().external_attributes(mode << 16), ) - .expect("VSIX entry should initialize"); + .expect("ZIP entry should initialize"); archive .write_all(b"server") - .expect("VSIX entry should be written"); - let bytes = archive.finish().expect("VSIX should finish").into_inner(); + .expect("ZIP entry should be written"); + archive.finish().expect("ZIP should finish").into_inner() +} + +#[test] +fn extracts_vsix_as_a_zip_archive() { + let directory = tempfile::tempdir().expect("temporary directory should initialize"); + let bytes = zip_with_file("extension/server/dist/server.js", 0o100_644); install_downloaded_artifact(directory.path(), "server.vsix", &bytes) .expect("VSIX should extract"); @@ -267,3 +272,22 @@ fn installer_command_scopes_toolchain_environment_to_cargo() { ); assert!(!npm_environment.contains_key(std::ffi::OsStr::new("CARGO_HOME"))); } + +#[cfg(unix)] +#[test] +fn zip_extraction_strips_special_permissions_and_preserves_executable_bits() { + use std::os::unix::fs::PermissionsExt; + + let directory = tempfile::tempdir().expect("temporary directory should initialize"); + for (mode, expected) in [(0o107_777, 0o755), (0o106_666, 0o644)] { + let bytes = zip_with_file("server", mode); + + install_downloaded_artifact(directory.path(), "server.zip", &bytes) + .expect("ZIP should extract"); + + let permissions = fs::metadata(directory.path().join("server")) + .expect("server should be extracted") + .permissions(); + assert_eq!(permissions.mode() & 0o7777, expected); + } +} diff --git a/tests/e2e/Cargo.toml b/tests/e2e/Cargo.toml index e4e147a..875b751 100644 --- a/tests/e2e/Cargo.toml +++ b/tests/e2e/Cargo.toml @@ -27,7 +27,7 @@ fs_extra = "1.3.0" reqwest = { version = "0.12.24", default-features = false, features = ["blocking", "json", "rustls-tls"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.150" -serde_yaml = "0.9.34" +serde-saphyr = { version = "2.0.0", default-features = false, features = ["deserialize"] } sha2 = "0.11.0" tar = { version = "0.4.46", optional = true } tempfile = "3.23.0" diff --git a/tests/e2e/case_files.rs b/tests/e2e/case_files.rs index 56c47da..c355142 100644 --- a/tests/e2e/case_files.rs +++ b/tests/e2e/case_files.rs @@ -21,7 +21,7 @@ pub(crate) fn yaml_paths(directory: &Path) -> Result, String> { pub(crate) fn read_yaml(path: &Path) -> Result { let contents = fs::read_to_string(path) .map_err(|error| format!("failed to read {}: {error}", path.display()))?; - serde_yaml::from_str(&contents) + serde_saphyr::from_str(&contents) .map_err(|error| format!("failed to parse {}: {error}", path.display())) } diff --git a/tests/e2e/manifest_tests.rs b/tests/e2e/manifest_tests.rs index 83c556e..c129786 100644 --- a/tests/e2e/manifest_tests.rs +++ b/tests/e2e/manifest_tests.rs @@ -272,7 +272,7 @@ fn manifest_rejects_a_pair_without_test_behavior() { #[test] fn manifest_rejects_unknown_fields() { - let error = serde_yaml::from_str::( + let error = serde_saphyr::from_str::( "schema-version: 4\ncoverage: partial\ncommands: []\nunknown: true\n", ) .expect_err("unknown manifest fields should fail"); @@ -296,7 +296,7 @@ fn manifest_rejects_a_source_language_without_a_preferred_server() { #[test] fn language_case_filename_must_match_its_id() { - let case = serde_yaml::from_str::( + let case = serde_saphyr::from_str::( "language:\n id: gomod\n kind: metadata\n project: playground/gomod\n", ) .expect("language case should parse"); @@ -310,7 +310,7 @@ fn language_case_filename_must_match_its_id() { #[test] fn language_case_must_own_its_pairs() { - let case = serde_yaml::from_str::( + let case = serde_saphyr::from_str::( "language:\n id: gomod\n kind: metadata\n project: playground/gomod\npairs:\n - language: gowork\n server: gopls\n", ) .expect("language case should parse"); From 5055a37ff08bb576b633b0b694c8e8874286fb23 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Tue, 20 Oct 2026 16:55:17 +0400 Subject: [PATCH 2/2] fix(deps): update quinn-proto and anyhow for security advisories --- Cargo.lock | 101 +++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c548f84..b84fe04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arraydeque" @@ -178,6 +178,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + [[package]] name = "clap" version = "4.6.7" @@ -484,20 +495,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi 5.3.0", - "wasip2", - "wasm-bindgen", -] - [[package]] name = "getrandom" version = "0.4.2" @@ -505,10 +502,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", - "r-efi 6.0.0", + "r-efi", + "rand_core", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -1040,15 +1040,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - [[package]] name = "prettyplease" version = "0.2.37" @@ -1090,14 +1081,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.15" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" +checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.4.2", "lru-slab", "rand", + "rand_pcg", "ring", "rustc-hash", "rustls", @@ -1132,12 +1124,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - [[package]] name = "r-efi" version = "6.0.0" @@ -1146,31 +1132,28 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.9.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ - "rand_chacha", + "chacha20", + "getrandom 0.4.2", "rand_core", ] [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "rand_core" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] -name = "rand_core" -version = "0.9.5" +name = "rand_pcg" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" dependencies = [ - "getrandom 0.3.4", + "rand_core", ] [[package]] @@ -2240,26 +2223,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "zerofrom" version = "0.1.7"