diff --git a/Cargo.lock b/Cargo.lock index a9781ccfa..41e393932 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -31,33 +31,32 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -79,9 +78,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "2.1.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -89,9 +88,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arc-swap" @@ -126,9 +125,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.1" +version = "0.4.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "62b74f44609f0f91493e3082d3734d98497e094777144380ea4db9f9905dd5b6" +checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" dependencies = [ "flate2", "futures-core", @@ -137,17 +136,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-trait" -version = "0.1.72" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.28", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -156,9 +144,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -171,9 +159,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "bitflags" @@ -183,9 +171,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -210,9 +198,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.6.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" dependencies = [ "memchr", "regex-automata", @@ -270,6 +258,8 @@ dependencies = [ "fern", "fs_extra", "gix", + "globset", + "goblin", "home", "insta", "krates", @@ -277,6 +267,8 @@ dependencies = [ "nu-ansi-term", "parking_lot", "rayon", + "reqwest", + "ring", "rustsec", "semver", "serde", @@ -290,6 +282,7 @@ dependencies = [ "toml", "twox-hash", "url", + "walkdir", ] [[package]] @@ -329,9 +322,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.81" +version = "1.0.83" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", "libc", @@ -355,20 +348,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.3.19" +version = "4.4.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.4.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", @@ -378,21 +370,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "clru" @@ -437,6 +429,22 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + [[package]] name = "cpufeatures" version = "0.2.9" @@ -541,17 +549,11 @@ dependencies = [ "serde", ] -[[package]] -name = "data-encoding" -version = "2.4.0" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" - [[package]] name = "deranged" -version = "0.3.6" +version = "0.3.8" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] name = "digest" @@ -583,25 +585,13 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.5.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -610,9 +600,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -629,6 +619,15 @@ dependencies = [ "libc", ] +[[package]] +name = "faster-hex" +version = "0.8.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "e9042d281a5eec0f2387f8c3ea6c4514e2cf2732c90a85aaf383b761ee3b290d" +dependencies = [ + "serde", +] + [[package]] name = "fastrand" version = "2.0.0" @@ -646,13 +645,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.21" +version = "0.2.22" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "windows-sys 0.48.0", ] @@ -664,9 +663,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -734,7 +733,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -788,15 +787,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "gix" -version = "0.50.1" +version = "0.52.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "275b1bfa0d6f6ed31a2e2e878a4539f4994eac8840546283ab3aebbd8fcaa42d" +checksum = "a35ed1401a11506b45361746507a7c94c546574ddd7dfc2717f8941e30070254" dependencies = [ "gix-actor", "gix-attributes", @@ -821,12 +820,14 @@ dependencies = [ "gix-odb", "gix-pack", "gix-path", + "gix-pathspec", "gix-prompt", "gix-protocol", "gix-ref", "gix-refspec", "gix-revision", "gix-sec", + "gix-submodule", "gix-tempfile", "gix-trace", "gix-transport", @@ -835,8 +836,10 @@ dependencies = [ "gix-utils", "gix-validate", "gix-worktree", + "gix-worktree-state", "log", "once_cell", + "parking_lot", "reqwest", "signal-hook", "smallvec", @@ -846,23 +849,23 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.24.2" +version = "0.25.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "abd2566c12095a584716f2c16f051850bd8987f57556f1fef4a7cce0300b83d0" +checksum = "8f8a773b5385e9d2f88bd879fb763ec1212585f6d630ebe13adb7bac93bce975" dependencies = [ "bstr", "btoi", "gix-date", "itoa", - "nom", "thiserror", + "winnow", ] [[package]] name = "gix-attributes" -version = "0.16.0" +version = "0.17.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "63a134a674e39e238bd273326a9815296cc71f867ad5466518da71392cff98ce" +checksum = "b1ecae08f2625d8abcd27570fa2f9c2fcf01a1cd968a8d90858e63f8e08211a3" dependencies = [ "bstr", "gix-glob", @@ -877,9 +880,9 @@ dependencies = [ [[package]] name = "gix-bitmap" -version = "0.2.6" +version = "0.2.7" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "0aa8bbde7551a9e3e783a2871f53bbb0f50aac7a77db5680c8709f69e8ce724f" +checksum = "0ccab4bc576844ddb51b78d81b4a42d73e6229660fa614dfc3d3999c874d1959" dependencies = [ "thiserror", ] @@ -895,18 +898,18 @@ dependencies = [ [[package]] name = "gix-command" -version = "0.2.8" +version = "0.2.9" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2783ad148fb16bf9cfd46423706ba552a62a4d4a18fda5dd07648eb0228862dd" +checksum = "0f28f654184b5f725c5737c7e4f466cbd8f0102ac352d5257eeab19647ee4256" dependencies = [ "bstr", ] [[package]] name = "gix-commitgraph" -version = "0.18.1" +version = "0.19.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c4c2d5ce99eba59fe9477a9e3037b0e1d0266d53925cc4b322bc06c566589b99" +checksum = "3845b3c8722a0e97d9d593c05d384bb1275a5865f1cd967523a3780ffc93168e" dependencies = [ "bstr", "gix-chunk", @@ -918,9 +921,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.26.2" +version = "0.28.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2135b921a699a4c36167148193bea23c653a16ef0686f6a280e383469709a773" +checksum = "9a312d120231dc8d5a2e34928a9a2098c1d3dbad76f0660ee38d0b1a87de5271" dependencies = [ "bstr", "gix-config-value", @@ -940,11 +943,11 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.12.5" +version = "0.13.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6e874f41437441c02991dcea76990b9058fadfc54b02ab4dd06ab2218af43897" +checksum = "901e184f3d4f99bf015ca13b5ccacb09e26b400f198fe2066651089e2c490680" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "bstr", "gix-path", "libc", @@ -953,9 +956,9 @@ dependencies = [ [[package]] name = "gix-credentials" -version = "0.17.1" +version = "0.18.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "307d91ec5f7c8e9bfaa217fe30c2e0099101cbe83dbed27a222dbb6def38725f" +checksum = "2988e917f7ee4a99072354d5885ca14c9e7039de8246e96e300ab3e5060cad19" dependencies = [ "bstr", "gix-command", @@ -969,9 +972,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.7.1" +version = "0.7.4" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "56b0312dba1ad003d9b8c502bed52fbcf106f8de3a9a26bfa7b45642a6f94b72" +checksum = "0a825babda995d788e30d306a49dacd1e93d5f5d33d53c7682d0347cef40333c" dependencies = [ "bstr", "itoa", @@ -981,9 +984,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.33.1" +version = "0.34.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "9a49d7a9a9ed5ec3428c3061da45d0fc5f50b3c07b91ea4e7ec4959668f25f6c" +checksum = "016be5f0789da595b61d15a862476be0cbae8fd29e2c91d66770fdd8df145773" dependencies = [ "gix-hash", "gix-object", @@ -993,9 +996,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.22.1" +version = "0.23.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "041480eb03d8aa0894d9b73d25d182d51bc4d0ea8925a6ee0c971262bbc7715e" +checksum = "2b74760d912716b287357dae5654ad84be12a2a75a721f00b58ecdd65496e024" dependencies = [ "bstr", "dunce", @@ -1008,9 +1011,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.32.1" +version = "0.33.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "882695cccf38da4c3cc7ee687bdb412cf25e37932d7f8f2c306112ea712449f1" +checksum = "7f77decb545f63a52852578ef5f66ecd71017ffc1983d551d5fa2328d6d9817f" dependencies = [ "bytes", "crc32fast", @@ -1030,9 +1033,9 @@ dependencies = [ [[package]] name = "gix-filter" -version = "0.2.0" +version = "0.3.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ef4d4d61f2ab07de4612f8e078d7f1a443c7ab5c40f382784c8eacdf0fd172b9" +checksum = "5f5495cdd54f4c3bb05b35a525cd39df1643362d917a7e03f112564c2825feb4" dependencies = [ "bstr", "encoding_rs", @@ -1050,20 +1053,20 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.4.1" +version = "0.5.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4d5b6e9d34a2c61ea4a02bbca94c409ab6dbbca1348cbb67298cd7fed8758761" +checksum = "53d5089f3338647776733a75a800a664ab046f56f21c515fa4722e395f877ef8" dependencies = [ "gix-features", ] [[package]] name = "gix-glob" -version = "0.10.1" +version = "0.11.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "d7c79b881a18d89a75876ba277476d5a2bad5b19f03759c7a07e0808dfe08212" +checksum = "c753299d14a29ca06d7adc8464c16f1786eb97bc9a44a796ad0a37f57235a494" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "bstr", "gix-features", "gix-path", @@ -1071,19 +1074,19 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.11.4" +version = "0.12.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4b422ff2ad9a0628baaad6da468cf05385bf3f5ab495ad5a33cce99b9f41092f" +checksum = "7d4796bac3aaf0c2f8bea152ca924ae3bdc5f135caefe6431116bcd67e98eab9" dependencies = [ - "hex", + "faster-hex", "thiserror", ] [[package]] name = "gix-hashtable" -version = "0.2.4" +version = "0.3.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "385f4ce6ecf3692d313ca3aa9bd3b3d8490de53368d6d94bedff3af8b6d9c58d" +checksum = "45ad1b70efd1e77c32729d5a522f0c855e9827242feb10318e1acaf2259222c0" dependencies = [ "gix-hash", "hashbrown 0.14.0", @@ -1092,9 +1095,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.5.1" +version = "0.6.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "a88b95ceb3bc45abcab6eb55ef4e0053e58b4df0712d3f9aec7d0ca990952603" +checksum = "b355098421f5cc91a0e5f1ef3600ae250c13b7c3c472b18c361897c6081bfbb1" dependencies = [ "bstr", "gix-glob", @@ -1104,11 +1107,11 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.21.1" +version = "0.22.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "732f61ec71576bd443a3c24f4716dc7eac180d8929e7bb8603c7310161507106" +checksum = "a9738fc58ca30e232c7b1be8e8ab52b072979acb9bf3fa97662b5b23c0c6fbca" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "bstr", "btoi", "filetime", @@ -1127,9 +1130,9 @@ dependencies = [ [[package]] name = "gix-lock" -version = "7.0.2" +version = "8.0.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "7e82ec23c8a281f91044bf3ed126063b91b59f9c9340bf0ae746f385cc85a6fa" +checksum = "de4363023577b31906b476b34eefbf76931363ec574f88b5c7b6027789f1e3ce" dependencies = [ "gix-tempfile", "gix-utils", @@ -1138,9 +1141,9 @@ dependencies = [ [[package]] name = "gix-mailmap" -version = "0.16.1" +version = "0.17.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "7fc0dbbf35d29639770af68d7ff55924d83786c8924b0e6a1766af1a98b7d58b" +checksum = "244a4a6f08e8104110675de649ccd20fe1d1116783063920e19aa7da197a4ad0" dependencies = [ "bstr", "gix-actor", @@ -1150,11 +1153,11 @@ dependencies = [ [[package]] name = "gix-negotiate" -version = "0.5.1" +version = "0.6.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ce0061b7ae867e830c77b1ecfc5875f0d042aebb3d7e6014d04fd86ca6c71d59" +checksum = "a0b0ea711559f843b8286cdf71ea421560c072120fae35a949bcf6b068b73745" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "gix-commitgraph", "gix-date", "gix-hash", @@ -1166,9 +1169,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.33.2" +version = "0.35.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "bfdd87520c71a19afecfa616863a4b761621074878f5a3999243b3e37e233943" +checksum = "c4283b7b5e9438afe2e3183e9acd1c77e750800937bb56c06b750822d2ff6d95" dependencies = [ "bstr", "btoi", @@ -1177,18 +1180,17 @@ dependencies = [ "gix-features", "gix-hash", "gix-validate", - "hex", "itoa", - "nom", "smallvec", "thiserror", + "winnow", ] [[package]] name = "gix-odb" -version = "0.50.2" +version = "0.51.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e827dbda6d3dabadb94cd437d0e0fe8c314a60d136a3235fc6f5bf7b96b976ac" +checksum = "c1dd295ca055d8270de23b6037176b03782de753f75c84dabb7713f7d7e229fd" dependencies = [ "arc-swap", "gix-date", @@ -1205,9 +1207,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.40.2" +version = "0.41.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "46f029a4dce9ac91da35c968c3abdcae573b3e52c123be86cbab3011599de533" +checksum = "e2e645c38138216b9de2f6279bfb1b8567de6f4539f8fa2761eea961d991f448" dependencies = [ "clru", "gix-chunk", @@ -1228,31 +1230,31 @@ dependencies = [ [[package]] name = "gix-packetline" -version = "0.16.4" +version = "0.16.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "eb532b34627186a9a2705a360f64f6a8feb34c42344b127f9f230687d85358bd" +checksum = "2a374cb5eba089e3c123df4d996eb00da411bb90ec92cb35bffeeb2d22ee106a" dependencies = [ "bstr", - "hex", + "faster-hex", "thiserror", ] [[package]] name = "gix-packetline-blocking" -version = "0.16.4" +version = "0.16.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "20276373def40fc3be7a86d09e1bb607d33dd6bf83e3504e83cd594e51438667" +checksum = "e39142400d3faa7057680ed3947c3b70e46b6a0b16a7c242ec8f0249e37518ba" dependencies = [ "bstr", - "hex", + "faster-hex", "thiserror", ] [[package]] name = "gix-path" -version = "0.8.4" +version = "0.9.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "18609c8cbec8508ea97c64938c33cd305b75dfc04a78d0c3b78b8b3fd618a77c" +checksum = "764b31ac54472e796f08be376eaeea3e30800949650566620809659d39969dbd" dependencies = [ "bstr", "gix-trace", @@ -1261,11 +1263,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gix-pathspec" +version = "0.1.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "b4ba6662a29a6332926494542f6144ee87a59df3c70a4c680ebd235b646d7866" +dependencies = [ + "bitflags 2.4.0", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror", +] + [[package]] name = "gix-prompt" -version = "0.5.5" +version = "0.6.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2c22decaf4a063ccae2b2108820c8630c01bd6756656df3fe464b32b8958a5ea" +checksum = "33ebf6f126413908bfbdc27bf69f6f8b94b674457546fab8ba613be22b917d33" dependencies = [ "gix-command", "gix-config-value", @@ -1276,9 +1293,9 @@ dependencies = [ [[package]] name = "gix-protocol" -version = "0.36.1" +version = "0.38.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "0f8cf8b48ad5510a6ea3c8b529f51fd0f31009a2e46579f3a0ed917669035170" +checksum = "9ea9a0acfb928bc0cccd6d9e4778ba367328098fe6553ab39d5763f128794bad" dependencies = [ "bstr", "btoi", @@ -1294,9 +1311,9 @@ dependencies = [ [[package]] name = "gix-quote" -version = "0.4.6" +version = "0.4.7" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "dfd80d3d0c733508df9449b1d3795da36083807e31d851d7d61d29af13bd4b0a" +checksum = "475c86a97dd0127ba4465fbb239abac9ea10e68301470c9791a6dd5351cdc905" dependencies = [ "bstr", "btoi", @@ -1305,9 +1322,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.33.3" +version = "0.35.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "25db11edd78bf33043d1969fff51c567a4b30edd77ab44f6f8eb460a4c14985d" +checksum = "993ce5c448a94038b8da1a8969c0facd6c1fbac509fa013344c580458f41527d" dependencies = [ "gix-actor", "gix-date", @@ -1320,15 +1337,15 @@ dependencies = [ "gix-tempfile", "gix-validate", "memmap2", - "nom", "thiserror", + "winnow", ] [[package]] name = "gix-refspec" -version = "0.14.1" +version = "0.16.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "d19a02bf740b326d6c082a7d6f754ebe56eef900986c5e91be7cf000df9ea18d" +checksum = "f3171923a0f9075feae790bb81d824c0c1f91a899df51508705d4957bacd006e" dependencies = [ "bstr", "gix-hash", @@ -1340,9 +1357,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.18.1" +version = "0.20.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "38a13500890435e3b9e7746bceda248646bfc69e259210884c98e29bb7a1aa6f" +checksum = "2443886b7c55e73a813f203fe8603b94ac5deb3dfad8812d25e731b81f569f27" dependencies = [ "bstr", "gix-date", @@ -1350,14 +1367,15 @@ dependencies = [ "gix-hashtable", "gix-object", "gix-revwalk", + "gix-trace", "thiserror", ] [[package]] name = "gix-revwalk" -version = "0.4.1" +version = "0.6.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "71d4cbaf3cfbfde2b81b5ee8b469aff42c34693ce0fe17fc3c244d5085307f2c" +checksum = "362f71e173364f67d02899388c4b3d2f6bac7c16c0f3a9bbc04683f984f59daa" dependencies = [ "gix-commitgraph", "gix-date", @@ -1370,21 +1388,36 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.8.4" +version = "0.9.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "9615cbd6b456898aeb942cd75e5810c382fbfc48dbbff2fa23ebd2d33dcbe9c7" +checksum = "0debc2e70613a077c257c2bb45ab4f652a550ae1d00bdca356633ea9de88a230" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "gix-path", "libc", "windows", ] +[[package]] +name = "gix-submodule" +version = "0.2.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "71cc3ecd5e2387102aa275fc88fcf36e0f0b9df23a1335bf6255327abbb9bb3f" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror", +] + [[package]] name = "gix-tempfile" -version = "7.0.2" +version = "8.0.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "fa28d567848cec8fdd77d36ad4f5f78ecfaba7d78f647d4f63c8ae1a2cec7243" +checksum = "cea558d3daf3b1d0001052b12218c66c8f84788852791333b633d7eeb6999db1" dependencies = [ "gix-fs", "libc", @@ -1403,9 +1436,9 @@ checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836" [[package]] name = "gix-transport" -version = "0.34.2" +version = "0.35.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "640cf03acc506e0350bc434dd6d7093d91343ed508d2c2166a41da856ab6e5e3" +checksum = "3521e96c5d7d65c1d6bd632820362ac30f66391108126a4a56adb0a5cfe85d77" dependencies = [ "base64", "bstr", @@ -1422,9 +1455,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.30.1" +version = "0.31.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e12e0fe428394226c37dd686ad64b09a04b569fe157d638b125b4a4c1e7e2df0" +checksum = "beecf2e4d8924cbe0cace0bd396f9b037fdf7db9799d5695fe70dcad959ed067" dependencies = [ "gix-commitgraph", "gix-date", @@ -1438,9 +1471,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.21.1" +version = "0.22.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4411bdbd1d46b35ae50e84c191660d437f89974e4236627785024be0b577170a" +checksum = "6059e15828df32027a7db9097e5a9baf320d2dcc10a4e1598ffe05be8dfd1fa6" dependencies = [ "bstr", "gix-features", @@ -1461,9 +1494,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.7.7" +version = "0.8.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ba9b3737b2cef3dcd014633485f0034b0f1a931ee54aeb7d8f87f177f3c89040" +checksum = "e05cab2b03a45b866156e052aa38619f4ece4adcb2f79978bfc249bc3b21b8c5" dependencies = [ "bstr", "thiserror", @@ -1471,15 +1504,13 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.23.1" +version = "0.24.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "9f8bb6dd57dc6c9dfa03cc2cf2cc0942edae405eb6dfd1c34dbd2be00a90cab2" +checksum = "a38eab0fdd752ecfa50130c127c9f42bd329bf7f4e52872f4ac24c12bbc02baf" dependencies = [ "bstr", - "filetime", "gix-attributes", "gix-features", - "gix-filter", "gix-fs", "gix-glob", "gix-hash", @@ -1487,15 +1518,57 @@ dependencies = [ "gix-index", "gix-object", "gix-path", +] + +[[package]] +name = "gix-worktree-state" +version = "0.1.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "44629a04d238493f0da657a0eee4d60086f0172c364ca4a71398b1898fda32a6" +dependencies = [ + "bstr", + "gix-features", + "gix-filter", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-index", + "gix-object", + "gix-path", + "gix-worktree", "io-close", "thiserror", ] +[[package]] +name = "globset" +version = "0.4.13" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "goblin" +version = "0.7.1" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -1534,12 +1607,6 @@ version = "0.3.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "home" version = "0.5.5" @@ -1549,17 +1616,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - [[package]] name = "http" version = "0.2.9" @@ -1590,9 +1646,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -1632,17 +1688,6 @@ dependencies = [ "tokio-rustls", ] -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.4.0" @@ -1707,35 +1752,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2 0.5.3", - "widestring", - "windows-sys 0.48.0", - "winreg 0.50.0", -] - [[package]] name = "ipnet" version = "2.8.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" -[[package]] -name = "is-terminal" -version = "0.4.9" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "itoa" version = "1.0.9" @@ -1772,15 +1794,14 @@ dependencies = [ [[package]] name = "krates" -version = "0.14.0" +version = "0.15.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ce26ee40ae43555ff346b9807d4c85e86d8e39c26e19da2d9894829f073b341a" +checksum = "2c4dd211bb631092ec6130de12b2914bdfca99980ed567648bc77cb6c28b5bda" dependencies = [ "cargo_metadata", "cfg-expr", "petgraph", "semver", - "tame-index", ] [[package]] @@ -1828,30 +1849,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - -[[package]] -name = "matches" -version = "0.1.10" +version = "0.4.20" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "maybe-async" @@ -1866,9 +1866,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" [[package]] name = "memmap2" @@ -1969,9 +1969,9 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "memchr", ] @@ -1982,6 +1982,12 @@ version = "1.18.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "parking_lot" version = "0.12.1" @@ -2000,9 +2006,9 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -2019,19 +2025,19 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 1.9.3", + "indexmap 2.0.0", ] [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -2045,21 +2051,21 @@ version = "0.3.27" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "platforms" -version = "3.0.2" +version = "3.1.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" dependencies = [ "serde", ] -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - [[package]] name = "proc-macro2" version = "1.0.66" @@ -2071,21 +2077,15 @@ dependencies = [ [[package]] name = "prodash" -version = "25.0.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c236e70b7f9b9ea00d33c69f63ec1ae6e9ae96118923cd37bd4e9c7396f0b107" - -[[package]] -name = "quick-error" -version = "1.2.3" +version = "25.0.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "1d67eb4220992a4a052a4bb03cf776e493ecb1a3a36bab551804153d63486af7" [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -2096,36 +2096,6 @@ version = "0.7.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - [[package]] name = "rayon" version = "1.7.0" @@ -2148,15 +2118,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -2168,9 +2129,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.4" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", @@ -2180,9 +2141,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.3.7" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", @@ -2191,15 +2152,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.20" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "async-compression", "base64", @@ -2220,6 +2181,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", + "rustls-native-certs", "rustls-pemfile", "serde", "serde_json", @@ -2228,23 +2190,12 @@ dependencies = [ "tokio-rustls", "tokio-util", "tower-service", - "trust-dns-resolver", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg 0.10.1", -] - -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", + "winreg", ] [[package]] @@ -2292,11 +2243,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.6" +version = "0.38.11" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -2305,9 +2256,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.7" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring", @@ -2315,6 +2266,18 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.3" @@ -2326,9 +2289,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.2" +version = "0.101.4" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ "ring", "untrusted", @@ -2336,9 +2299,9 @@ dependencies = [ [[package]] name = "rustsec" -version = "0.27.0" +version = "0.28.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "cabcfea780f9b2f75bc2eaae946621fa42cb18189f41cda4dee608ea73a9c397" +checksum = "56be49e9eab7fae34ca7a0a37a22d7ace05a72b34e31d83e7f0080066017f276" dependencies = [ "cargo-lock", "cvss", @@ -2372,12 +2335,41 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "sct" version = "0.7.0" @@ -2388,6 +2380,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.18" @@ -2399,29 +2414,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.180" +version = "1.0.188" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.180" +version = "1.0.188" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -2493,9 +2508,9 @@ checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -2573,15 +2588,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.1" +version = "0.25.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2597,9 +2612,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -2608,16 +2623,18 @@ dependencies = [ [[package]] name = "tame-index" -version = "0.2.5" +version = "0.5.4" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "93b8105f79989496b426b812cdbe61633dcb83f2b0b88b410949dc8b4d3f1c27" +checksum = "028ccde023b3ab64068b965a7fde9315cd234932370cdb7ec245bab2a8d536e0" dependencies = [ "bytes", "camino", + "crossbeam-channel", "gix", "home", "http", "memchr", + "rayon", "reqwest", "semver", "serde", @@ -2625,6 +2642,7 @@ dependencies = [ "sha2", "smol_str", "thiserror", + "tokio", "toml", "twox-hash", ] @@ -2643,13 +2661,13 @@ checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", "windows-sys 0.48.0", ] @@ -2665,29 +2683,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.47" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.47" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "time" -version = "0.3.24" +version = "0.3.28" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ "deranged", "itoa", @@ -2706,9 +2724,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.14" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" dependencies = [ "time-core", ] @@ -2730,18 +2748,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.5.3", "windows-sys 0.48.0", ] @@ -2817,21 +2834,9 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.26" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.28", -] - [[package]] name = "tracing-core" version = "0.1.31" @@ -2841,51 +2846,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "trust-dns-proto" -version = "0.22.0" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.22.0" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "lru-cache", - "parking_lot", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto", -] - [[package]] name = "try-lock" version = "0.2.4" @@ -2958,12 +2918,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna", "percent-encoding", "serde", ] @@ -3026,7 +2986,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-shared", ] @@ -3060,7 +3020,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3081,30 +3041,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - -[[package]] -name = "widestring" -version = "1.0.2" +version = "0.25.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "winapi" @@ -3143,7 +3084,7 @@ version = "0.48.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -3161,7 +3102,7 @@ version = "0.48.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -3181,17 +3122,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -3202,9 +3143,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -3214,9 +3155,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -3226,9 +3167,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -3238,9 +3179,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -3250,9 +3191,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -3262,9 +3203,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -3274,28 +3215,19 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.3" +version = "0.5.15" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index 404a6c475..8fd165eb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,10 @@ name = "cargo-deny" path = "src/cargo-deny/main.rs" [features] +default = ["reqwest/rustls-tls-webpki-roots", "tame-index/default"] +# Enables the use of OS native certificate store. +native-certs = ["reqwest/rustls-tls-native-roots", "tame-index/native-certs"] + #default = ["vendored-openssl", "vendored-libgit2"] # Allows the use of a vendored version openssl when compiling libgit, which allows # us to compile static executables (eg musl) and avoid system dependencies @@ -49,7 +53,7 @@ camino = "1.1" # Allows us to do eg cargo metadata operations without relying on an external cargo #cargo = { version = "0.71", optional = true } # Argument parsing, kept aligned with cargo -clap = { version = "4.0", features = ["derive", "env"] } +clap = { version = "4.3", features = ["derive", "env"] } # Used for diagnostic reporting codespan = "0.11" codespan-reporting = "0.11" @@ -57,18 +61,34 @@ codespan-reporting = "0.11" crossbeam = "0.8" # Logging utilities fern = "0.6" +# Glob matching +globset = "0.4" +# Native executable detection +goblin = { version = "0.7", default-features = false, features = [ + "elf32", + "elf64", + "mach32", + "mach64", + "pe32", + "pe64", +] } # We need to figure out HOME/CARGO_HOME in some cases home = "0.5" # Provides graphs on top of cargo_metadata -krates = { version = "0.14", features = ["prefer-index", "targets"] } +krates = { version = "0.15", features = ["targets"] } # Log macros log = "0.4" # Nicer sync primitives parking_lot = "0.12" # Moar brrrr rayon = "1.4" +# HTTP client backing gix, we don't use it directly but need it here for configuration +# due to ...reasons +reqwest = { version = "0.11", default-features = false } +# sha-256 hash calculation, already a dependency via rustls/etc +ring = "0.16" # Used for interacting with advisory databases -rustsec = { version = "0.27", default-features = false } +rustsec = { version = "0.28", default-features = false } # Parsing and checking of versions/version requirements semver = "1.0" # Gee what could it be @@ -81,7 +101,10 @@ spdx = "0.10" # Lazy strum = { version = "0.25", features = ["derive"] } # Index retrieval and querying -tame-index = { version = "0.2", features = ["git", "sparse"] } +tame-index = { version = "0.5", default-features = false, features = [ + "git", + "sparse", +] } # Timestamp emission time = { version = "0.3", default-features = false, features = [ "formatting", @@ -93,15 +116,18 @@ toml = "0.7" twox-hash = { version = "1.5", default-features = false } # Url parsing/manipulation url = "2.1" +# Directory traversal +walkdir = "2.3" # We clone/fetch advisory databases [dependencies.gix] -version = "0.50" +version = "0.52" default-features = false features = [ - "blocking-http-transport-reqwest-rust-tls", + "blocking-http-transport-reqwest", "blocking-network-client", "max-performance-safe", + "reqwest-for-configuration-only", ] [dev-dependencies] @@ -109,7 +135,7 @@ features = [ fs_extra = "1.3" # Snapshot testing insta = { version = "1.21", features = ["json"] } -tame-index = { version = "0.2", features = ["local-builder"] } +tame-index = { version = "0.5", features = ["local-builder"] } # We use this for creating fake crate directories for crawling license files on disk tempfile = "3.1.0" diff --git a/deny.toml b/deny.toml index 237a42fbf..c18420d7c 100644 --- a/deny.toml +++ b/deny.toml @@ -32,16 +32,14 @@ deny = [ skip = [ # indexmap + imara-diff { name = "hashbrown", version = "=0.12.3" }, - # trust-dns-proto uses an old version - { name = "idna", version = "=0.2.3" }, # petgraph + h2 use an old version { name = "indexmap", version = "=1.9.3" }, # hyper/tokio uses an old version { name = "socket2", version = "=0.4.9" }, # strum_macros + maybe-async { name = "syn", version = "=1.0.109" }, - # reqwest uses an old version - { name = "winreg", version = "=0.10.1" }, + # security-framework uses an ooooold version + { name = "bitflags", version = "=1.3.2" }, ] skip-tree = [ # Sigh @@ -70,9 +68,15 @@ allow = [ "ISC", ] exceptions = [ - { allow = ["Zlib"], name = "tinyvec" }, - { allow = ["Unicode-DFS-2016"], name = "unicode-ident" }, - { allow = ["OpenSSL"], name = "ring" }, + { allow = [ + "Zlib", + ], name = "tinyvec" }, + { allow = [ + "Unicode-DFS-2016", + ], name = "unicode-ident" }, + { allow = [ + "OpenSSL", + ], name = "ring" }, ] # Sigh diff --git a/src/advisories.rs b/src/advisories.rs index e82c8ec77..55301c77b 100644 --- a/src/advisories.rs +++ b/src/advisories.rs @@ -88,7 +88,10 @@ pub fn check( } for (krate, status) in yanked { - let Some(ind) = ctx.krates.nid_for_kid(&krate.id) else { log::warn!("failed to locate node id for '{krate}'"); continue }; + let Some(ind) = ctx.krates.nid_for_kid(&krate.id) else { + log::warn!("failed to locate node id for '{krate}'"); + continue; + }; if let Some(e) = status { if ctx.cfg.yanked.value != LintLevel::Allow { diff --git a/src/advisories/cfg.rs b/src/advisories/cfg.rs index 6725143ff..2c7bbf7dd 100644 --- a/src/advisories/cfg.rs +++ b/src/advisories/cfg.rs @@ -85,7 +85,12 @@ impl Default for Config { impl crate::cfg::UnvalidatedConfig for Config { type ValidCfg = ValidConfig; - fn validate(self, cfg_file: FileId, diags: &mut Vec) -> Self::ValidCfg { + fn validate( + self, + cfg_file: FileId, + _files: &mut crate::diag::Files, + diags: &mut Vec, + ) -> Self::ValidCfg { let mut ignored: Vec<_> = self.ignore.into_iter().map(AdvisoryId::from).collect(); ignored.sort(); @@ -352,9 +357,12 @@ mod test { advisories: Config, } - let cd: ConfigData = load("tests/cfg/advisories.toml"); + let mut cd: ConfigData = load("tests/cfg/advisories.toml"); let mut diags = Vec::new(); - let validated = cd.config.advisories.validate(cd.id, &mut diags); + let validated = cd + .config + .advisories + .validate(cd.id, &mut cd.files, &mut diags); assert!( !diags .iter() diff --git a/src/advisories/helpers/db.rs b/src/advisories/helpers/db.rs index c8a6c51f3..35727411b 100644 --- a/src/advisories/helpers/db.rs +++ b/src/advisories/helpers/db.rs @@ -243,7 +243,7 @@ fn fetch_and_checkout(repo: &mut gix::Repository) -> anyhow::Result<()> { { let mut config = repo.config_snapshot_mut(); config - .set_raw_value("committer", None, "name", "tame-index") + .set_raw_value("committer", None, "name", "cargo-deny") .context("failed to set `committer.name`")?; // Note we _have_ to set the email as well, but luckily gix does not actually // validate if it's a proper email or not :) @@ -353,13 +353,13 @@ fn fetch_and_checkout(repo: &mut gix::Repository) -> anyhow::Result<()> { .with_context(|| format!("failed to create index from tree '{root_tree}'"))?; let mut index = gix::index::File::from_state(index, repo.index_path()); - let opts = gix::worktree::checkout::Options { + let opts = gix::worktree::state::checkout::Options { destination_is_initially_empty: false, overwrite_existing: true, ..Default::default() }; - gix::worktree::checkout( + gix::worktree::state::checkout( &mut index, workdir, { @@ -669,6 +669,7 @@ impl<'db, 'k> Report<'db, 'k> { package, advisory: Some(advisory.metadata.clone()), versions: Some(advisory.versions.clone()), + affected: advisory.affected.clone(), }; if let Some(v) = warnings.get_mut(&kind) { diff --git a/src/advisories/helpers/index.rs b/src/advisories/helpers/index.rs index 572b8df02..48734f071 100644 --- a/src/advisories/helpers/index.rs +++ b/src/advisories/helpers/index.rs @@ -1,12 +1,13 @@ use crate::{Krate, Krates, Source}; -use anyhow::Context as _; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; -use std::{borrow::Cow, collections::BTreeMap}; +use std::collections::BTreeMap; use tame_index::{index::ComboIndexCache, Error, IndexLocation, IndexUrl}; +type YankMap = Vec<(semver::Version, bool)>; + pub struct Indices<'k> { pub indices: Vec<(&'k Source, Result)>, - pub cache: BTreeMap<(&'k str, &'k Source), tame_index::IndexKrate>, + pub cache: BTreeMap<(&'k str, &'k Source), YankMap>, } impl<'k> Indices<'k> { @@ -57,43 +58,41 @@ impl<'k> Indices<'k> { .iter() .find_map(|(url, index)| index.as_ref().ok().filter(|_i| src == *url))?; - index - .cached_krate(name.try_into().ok()?) - .ok()? - .map(|ik| ((name, src), ik)) + index.cached_krate(name.try_into().ok()?).ok()?.map(|ik| { + let yank_map = Self::load_index_krate(ik); + ((name, src), yank_map) + }) }) .collect(); Self { indices, cache } } + #[inline] + fn load_index_krate(ik: tame_index::IndexKrate) -> YankMap { + ik.versions + .into_iter() + .filter_map(|iv| Some((iv.version.parse().ok()?, iv.yanked))) + .collect() + } + #[inline] pub fn is_yanked(&self, krate: &'k Krate) -> anyhow::Result { + use anyhow::Context as _; + // Ignore non-registry crates when checking, as a crate sourced // locally or via git can have the same name as a registry package - let Some(src) = krate.source.as_ref().filter(|s| s.is_registry()) else { return Ok(false) }; - - let index_krate = if let Some(ik) = self.cache.get(&(krate.name.as_str(), src)) { - Cow::Borrowed(ik) - } else { - let index = self - .indices - .iter() - .find_map(|(url, index)| (src == *url).then_some(index.as_ref())) - .context("unable to find source index")? - .map_err(|err| anyhow::anyhow!("failed to load index: {err:#}"))?; - - let ik = index - .cached_krate(krate.name.as_str().try_into()?) - .context("failed to read crate from index cache")? - .context("unable to find crate in cache")?; - Cow::Owned(ik) + let Some(src) = krate.source.as_ref().filter(|s| s.is_registry()) else { + return Ok(false); }; - let is_yanked = index_krate - .versions + let cache_entry = self + .cache + .get(&(krate.name.as_str(), src)) + .context("unable to locate index metadata")?; + let is_yanked = cache_entry .iter() - .find_map(|kv| (kv.version == krate.version).then_some(kv.yanked)); + .find_map(|kv| (kv.0 == krate.version).then_some(kv.1)); Ok(is_yanked.unwrap_or_default()) } diff --git a/src/bans.rs b/src/bans.rs index b48a8abcb..95cb73f16 100644 --- a/src/bans.rs +++ b/src/bans.rs @@ -2,7 +2,7 @@ pub mod cfg; mod diags; mod graph; -use self::cfg::{TreeSkip, ValidConfig}; +use self::cfg::{TreeSkip, ValidBuildConfig, ValidConfig}; use crate::{ diag::{self, CfgCoord, FileId, KrateCoord}, Kid, Krate, Krates, LintLevel, @@ -58,7 +58,7 @@ fn matches<'v>(arr: &'v [cfg::Skrate], details: &Krate) -> Option, skip_crates: Vec, - skip_hits: bitvec::vec::BitVec, + skip_hits: BitVec, } use bitvec::prelude::*; @@ -204,7 +204,7 @@ pub fn check( tree_skipped, wildcards, allow_wildcard_paths, - allow_build_scripts, + build, } = ctx.cfg; let mut sink = sink.into(); @@ -343,383 +343,487 @@ pub fn check( } }; - for (i, krate) in ctx.krates.krates().enumerate() { - let mut pack = Pack::with_kid(Check::Bans, krate.id.clone()); - - // Check if the crate has been explicitly banned - if let Some(matches) = matches(&denied_ids, krate) { - for rm in matches { - let ban_cfg = CfgCoord { - file: file_id, - span: rm.id.span.clone(), - }; - - // The crate is banned, but it might have be allowed if it's wrapped - // by one or more particular crates - let is_allowed_by_wrapper = - if let Some(wrappers) = ban_wrappers.get(rm.index).and_then(|bw| bw.as_ref()) { - let nid = ctx.krates.nid_for_kid(&krate.id).unwrap(); - - // Ensure that every single crate that has a direct dependency - // on the banned crate is an allowed wrapper - ctx.krates.direct_dependents(nid).into_iter().all(|src| { - let (diag, is_allowed): (Diag, _) = - match wrappers.iter().find(|aw| aw.value == src.krate.name) { - Some(aw) => ( - diags::BannedAllowedByWrapper { - ban_cfg: ban_cfg.clone(), - ban_exception_cfg: CfgCoord { - file: file_id, - span: aw.span.clone(), - }, - banned_krate: krate, - wrapper_krate: src.krate, - } - .into(), - true, - ), - None => ( - diags::BannedUnmatchedWrapper { - ban_cfg: ban_cfg.clone(), - banned_krate: krate, - parent_krate: src.krate, - } - .into(), - false, - ), - }; - - pack.push(diag); - is_allowed - }) - } else { - false - }; + enum Sink<'k> { + Build(crossbeam::channel::Sender<(usize, &'k Krate, Pack)>), + NoBuild(diag::ErrorSink), + } - if !is_allowed_by_wrapper { - pack.push(diags::ExplicitlyBanned { krate, ban_cfg }); + impl<'k> Sink<'k> { + #[inline] + fn push(&mut self, index: usize, krate: &'k Krate, pack: Pack) { + match self { + Self::Build(tx) => tx.send((index, krate, pack)).unwrap(), + Self::NoBuild(sink) => { + if !pack.is_empty() { + sink.push(pack); + } } } } + } + + let (mut tx, rx) = if let Some(bc) = build { + let (tx, rx) = crossbeam::channel::unbounded(); + + (Sink::Build(tx), Some((bc, rx))) + } else { + (Sink::NoBuild(sink.clone()), None) + }; - if !allowed.is_empty() { - // Since only allowing specific crates is pretty draconian, - // also emit which allow filters actually passed each crate - match matches(&allowed, krate) { - Some(matches) => { + let (_, build_packs) = rayon::join( + || { + let last = ctx.krates.len() - 1; + for (i, krate) in ctx.krates.krates().enumerate() { + let mut pack = Pack::with_kid(Check::Bans, krate.id.clone()); + + // Check if the crate has been explicitly banned + if let Some(matches) = matches(&denied_ids, krate) { for rm in matches { - pack.push(diags::ExplicitlyAllowed { - krate, - allow_cfg: CfgCoord { - file: file_id, - span: rm.id.span.clone(), - }, - }); + let ban_cfg = CfgCoord { + file: file_id, + span: rm.id.span.clone(), + }; + + // The crate is banned, but it might have be allowed if it's wrapped + // by one or more particular crates + let is_allowed_by_wrapper = if let Some(wrappers) = + ban_wrappers.get(rm.index).and_then(|bw| bw.as_ref()) + { + let nid = ctx.krates.nid_for_kid(&krate.id).unwrap(); + + // Ensure that every single crate that has a direct dependency + // on the banned crate is an allowed wrapper + ctx.krates.direct_dependents(nid).into_iter().all(|src| { + let (diag, is_allowed): (Diag, _) = + match wrappers.iter().find(|aw| aw.value == src.krate.name) { + Some(aw) => ( + diags::BannedAllowedByWrapper { + ban_cfg: ban_cfg.clone(), + ban_exception_cfg: CfgCoord { + file: file_id, + span: aw.span.clone(), + }, + banned_krate: krate, + wrapper_krate: src.krate, + } + .into(), + true, + ), + None => ( + diags::BannedUnmatchedWrapper { + ban_cfg: ban_cfg.clone(), + banned_krate: krate, + parent_krate: src.krate, + } + .into(), + false, + ), + }; + + pack.push(diag); + is_allowed + }) + } else { + false + }; + + if !is_allowed_by_wrapper { + pack.push(diags::ExplicitlyBanned { krate, ban_cfg }); + } } } - None => { - pack.push(diags::NotAllowed { krate }); + + if !allowed.is_empty() { + // Since only allowing specific crates is pretty draconian, + // also emit which allow filters actually passed each crate + match matches(&allowed, krate) { + Some(matches) => { + for rm in matches { + pack.push(diags::ExplicitlyAllowed { + krate, + allow_cfg: CfgCoord { + file: file_id, + span: rm.id.span.clone(), + }, + }); + } + } + None => { + pack.push(diags::NotAllowed { krate }); + } + } } - } - } - let enabled_features = ctx.krates.get_enabled_features(&krate.id).unwrap(); + let enabled_features = ctx.krates.get_enabled_features(&krate.id).unwrap(); - let default_lint_level = if enabled_features.contains("default") { - if ctx.krates.workspace_members().any(|n| { - if let krates::Node::Krate { id, .. } = n { - id == &krate.id + let default_lint_level = if enabled_features.contains("default") { + if ctx.krates.workspace_members().any(|n| { + if let krates::Node::Krate { id, .. } = n { + id == &krate.id + } else { + false + } + }) { + workspace_default_features.as_ref() + } else { + external_default_features.as_ref() + } } else { - false - } - }) { - workspace_default_features.as_ref() - } else { - external_default_features.as_ref() - } - } else { - None - }; + None + }; - if let Some(ll) = default_lint_level { - if ll.value == LintLevel::Warn { - pack.push(diags::DefaultFeatureEnabled { - krate, - level: ll, - file_id, - }); - } - } + if let Some(ll) = default_lint_level { + if ll.value == LintLevel::Warn { + pack.push(diags::DefaultFeatureEnabled { + krate, + level: ll, + file_id, + }); + } + } - // Check if the crate has had features denied/allowed or are required to be exact - if let Some(matches) = matches(&feature_ids, krate) { - for rm in matches { - let feature_bans = &features[rm.index]; - - let feature_set_allowed = { - // Gather features that were present, but not explicitly allowed - let not_explicitly_allowed: Vec<_> = enabled_features - .iter() - .filter_map(|ef| { - if !feature_bans.allow.value.iter().any(|af| &af.value == ef) { - if ef == "default" { - if let Some(ll) = default_lint_level { - if ll.value != LintLevel::Deny { - return None; + // Check if the crate has had features denied/allowed or are required to be exact + if let Some(matches) = matches(&feature_ids, krate) { + for rm in matches { + let feature_bans = &features[rm.index]; + + let feature_set_allowed = { + // Gather features that were present, but not explicitly allowed + let not_explicitly_allowed: Vec<_> = enabled_features + .iter() + .filter_map(|ef| { + if !feature_bans.allow.value.iter().any(|af| &af.value == ef) { + if ef == "default" { + if let Some(ll) = default_lint_level { + if ll.value != LintLevel::Deny { + return None; + } + } } - } - } - Some(ef.as_str()) - } else { - None - } - }) - .collect(); + Some(ef.as_str()) + } else { + None + } + }) + .collect(); - if feature_bans.exact.value { - // Gather features allowed, but not present - let missing_allowed: Vec<_> = feature_bans - .allow - .value - .iter() - .filter_map(|af| { - if !enabled_features.contains(&af.value) { - Some(CfgCoord { - file: file_id, - span: af.span.clone(), + if feature_bans.exact.value { + // Gather features allowed, but not present + let missing_allowed: Vec<_> = feature_bans + .allow + .value + .iter() + .filter_map(|af| { + if !enabled_features.contains(&af.value) { + Some(CfgCoord { + file: file_id, + span: af.span.clone(), + }) + } else { + None + } }) + .collect(); + + if missing_allowed.is_empty() && not_explicitly_allowed.is_empty() { + true } else { - None + pack.push(diags::ExactFeaturesMismatch { + missing_allowed, + not_allowed: ¬_explicitly_allowed, + exact_coord: CfgCoord { + file: file_id, + span: feature_bans.exact.span.clone(), + }, + krate, + }); + false } - }) - .collect(); - - if missing_allowed.is_empty() && not_explicitly_allowed.is_empty() { - true - } else { - pack.push(diags::ExactFeaturesMismatch { - missing_allowed, - not_allowed: ¬_explicitly_allowed, - exact_coord: CfgCoord { - file: file_id, - span: feature_bans.exact.span.clone(), - }, - krate, - }); - false - } - } else { - // Mark the number of current diagnostics, if we add more - // the check has failed - let diag_count = pack.len(); - - // Add diagnostics if features were explicitly allowed, - // but didn't contain 1 or more features that were enabled - if !feature_bans.allow.value.is_empty() { - for feature in ¬_explicitly_allowed { - // Since the user has not specified `exact` we - // can also look at the full tree of features to - // determine if the feature is covered by an allowed - // parent feature - fn has_feature( - map: &std::collections::BTreeMap>, - parent: &str, - feature: &str, - ) -> bool { - if let Some(parent) = map.get(parent) { - parent.iter().any(|f| { - let pf = krates::ParsedFeature::from(f.as_str()); - - if let krates::Feature::Simple(feat) = pf.feat() { - if feat == feature { - true - } else { - has_feature(map, feat, feature) - } + } else { + // Mark the number of current diagnostics, if we add more + // the check has failed + let diag_count = pack.len(); + + // Add diagnostics if features were explicitly allowed, + // but didn't contain 1 or more features that were enabled + if !feature_bans.allow.value.is_empty() { + for feature in ¬_explicitly_allowed { + // Since the user has not specified `exact` we + // can also look at the full tree of features to + // determine if the feature is covered by an allowed + // parent feature + fn has_feature( + map: &std::collections::BTreeMap>, + parent: &str, + feature: &str, + ) -> bool { + if let Some(parent) = map.get(parent) { + parent.iter().any(|f| { + let pf = + krates::ParsedFeature::from(f.as_str()); + + if let krates::Feature::Simple(feat) = pf.feat() + { + if feat == feature { + true + } else { + has_feature(map, feat, feature) + } + } else { + false + } + }) } else { false } - }) - } else { - false + } + + if !feature_bans.allow.value.iter().any(|allowed| { + has_feature( + &krate.features, + allowed.value.as_str(), + feature, + ) + }) { + pack.push(diags::FeatureNotExplicitlyAllowed { + krate, + feature, + allowed: CfgCoord { + file: file_id, + span: feature_bans.allow.span.clone(), + }, + }); + } } } - if !feature_bans.allow.value.iter().any(|allowed| { - has_feature(&krate.features, allowed.value.as_str(), feature) - }) { - pack.push(diags::FeatureNotExplicitlyAllowed { + // If the default feature has been denied at a global + // level but not at the crate level, emit an error with + // the global span, otherwise the crate level setting, + // if the default feature was banned explicitly, takes + // precedence + if let Some(ll) = default_lint_level { + if ll.value == LintLevel::Deny + && !feature_bans + .allow + .value + .iter() + .any(|d| d.value == "default") + && !feature_bans.deny.iter().any(|d| d.value == "default") + { + pack.push(diags::DefaultFeatureEnabled { + krate, + level: ll, + file_id, + }); + } + } + + for feature in feature_bans + .deny + .iter() + .filter(|feat| enabled_features.contains(&feat.value)) + { + pack.push(diags::FeatureBanned { krate, feature, - allowed: CfgCoord { - file: file_id, - span: feature_bans.allow.span.clone(), - }, + file_id, }); } - } - } - // If the default feature has been denied at a global - // level but not at the crate level, emit an error with - // the global span, otherwise the crate level setting, - // if the default feature was banned explicitly, takes - // precedence - if let Some(ll) = default_lint_level { - if ll.value == LintLevel::Deny - && !feature_bans - .allow - .value - .iter() - .any(|d| d.value == "default") - && !feature_bans.deny.iter().any(|d| d.value == "default") + diag_count <= pack.len() + } + }; + + // If the crate isn't actually banned, but does reference + // features that don't exist, emit warnings about them so + // the user can cleanup their config. We _could_ emit these + // warnings if the crate is banned, but feature graphs in + // particular can be massive and adding warnings into the mix + // will just make parsing the error graphs harder + if feature_set_allowed { + for feature in feature_bans + .allow + .value + .iter() + .chain(feature_bans.deny.iter()) { - pack.push(diags::DefaultFeatureEnabled { - krate, - level: ll, - file_id, - }); + if !krate.features.contains_key(&feature.value) { + pack.push(diags::UnknownFeature { + krate, + feature, + file_id, + }); + } } } + } + } else if let Some(ll) = default_lint_level { + if ll.value == LintLevel::Deny { + pack.push(diags::DefaultFeatureEnabled { + krate, + level: ll, + file_id, + }); + } + } - for feature in feature_bans - .deny + if let Some(matches) = matches(&skipped, krate) { + for rm in matches { + pack.push(diags::Skipped { + krate, + skip_cfg: CfgCoord { + file: file_id, + span: rm.id.span.clone(), + }, + }); + + // Mark each skip filter that is hit so that we can report unused + // filters to the user so that they can cleanup their configs as + // their dependency graph changes over time + skip_hit.as_mut_bitslice().set(rm.index, true); + } + } else if !tree_skipper.matches(krate, &mut pack) { + if multi_detector.name != krate.name { + report_duplicates(&multi_detector, &mut sink); + + multi_detector.name = &krate.name; + multi_detector.dupes.clear(); + } + + multi_detector.dupes.push(i); + + if wildcards != LintLevel::Allow && !krate.is_git_source() { + let severity = match wildcards { + LintLevel::Warn => Severity::Warning, + LintLevel::Deny => Severity::Error, + LintLevel::Allow => unreachable!(), + }; + + let mut wildcards: Vec<_> = krate + .deps .iter() - .filter(|feat| enabled_features.contains(&feat.value)) - { - pack.push(diags::FeatureBanned { - krate, - feature, - file_id, + .filter(|dep| dep.req == VersionReq::STAR) + .collect(); + + if allow_wildcard_paths { + let is_private = krate.is_private(&[]); + + wildcards.retain(|dep| { + if is_private { + dep.path.is_none() + } else { + let is_path_dev_dependency = dep.path.is_some() + && dep.kind != DependencyKind::Development; + is_path_dev_dependency || dep.path.is_none() + } }); } - diag_count <= pack.len() - } - }; - - // If the crate isn't actually banned, but does reference - // features that don't exist, emit warnings about them so - // the user can cleanup their config. We _could_ emit these - // warnings if the crate is banned, but feature graphs in - // particular can be massive and adding warnings into the mix - // will just make parsing the error graphs harder - if feature_set_allowed { - for feature in feature_bans - .allow - .value - .iter() - .chain(feature_bans.deny.iter()) - { - if !krate.features.contains_key(&feature.value) { - pack.push(diags::UnknownFeature { + if !wildcards.is_empty() { + sink.push(diags::Wildcards { krate, - feature, - file_id, + severity, + wildcards, + allow_wildcard_paths, + cargo_spans: &cargo_spans, }); } } } - } - } else if let Some(ll) = default_lint_level { - if ll.value == LintLevel::Deny { - pack.push(diags::DefaultFeatureEnabled { - krate, - level: ll, - file_id, - }); - } - } - if let Some(matches) = matches(&skipped, krate) { - for rm in matches { - pack.push(diags::Skipped { - krate, - skip_cfg: CfgCoord { - file: file_id, - span: rm.id.span.clone(), - }, - }); + if i == last { + report_duplicates(&multi_detector, &mut sink); + } - // Mark each skip filter that is hit so that we can report unused - // filters to the user so that they can cleanup their configs as - // their dependency graph changes over time - skip_hit.as_mut_bitslice().set(rm.index, true); + tx.push(i, krate, pack); } - } else if !tree_skipper.matches(krate, &mut pack) { - if multi_detector.name != krate.name { - report_duplicates(&multi_detector, &mut sink); - multi_detector.name = &krate.name; - multi_detector.dupes.clear(); - } + drop(tx); + }, + || { + let Some((build_config, rx)) = rx else { + return None; + }; - multi_detector.dupes.push(i); + // Keep track of the individual crate configs so we can emit warnings + // if they're configured but not actually used + let bcv = parking_lot::Mutex::::new(BitVec::repeat( + false, + build_config.allow_executables.len(), + )); - if wildcards != LintLevel::Allow && !krate.is_git_source() { - let severity = match wildcards { - LintLevel::Warn => Severity::Warning, - LintLevel::Deny => Severity::Error, - LintLevel::Allow => unreachable!(), - }; + // Make all paths reported in build diagnostics be relative to cargo_home - let mut wildcards: Vec<_> = krate - .deps - .iter() - .filter(|dep| dep.req == VersionReq::STAR) - .collect(); + let cargo_home = home::cargo_home() + .map_err(|err| { + log::error!("unable to locate $CARGO_HOME: {err}"); + err + }) + .ok() + .and_then(|pb| { + crate::PathBuf::from_path_buf(pb) + .map_err(|pb| { + log::error!("$CARGO_HOME path '{}' is not utf-8", pb.display()); + }) + .ok() + }); - if allow_wildcard_paths { - let is_private = krate.is_private(&[]); + let pq = parking_lot::Mutex::new(std::collections::BTreeMap::new()); + rayon::scope(|s| { + let bc = &build_config; + let pq = &pq; + let bcv = &bcv; + let home = cargo_home.as_deref(); + + while let Ok((index, krate, mut pack)) = rx.recv() { + s.spawn(move |_s| { + if let Some(bcc) = + check_build(ctx.cfg.file_id, bc, home, krate, ctx.krates, &mut pack) + { + bcv.lock().set(bcc, true); + } - wildcards.retain(|dep| { - if is_private { - dep.path.is_none() - } else { - let is_path_dev_dependency = - dep.path.is_some() && dep.kind != DependencyKind::Development; - is_path_dev_dependency || dep.path.is_none() + if !pack.is_empty() { + pq.lock().insert(index, pack); } }); } - - if !wildcards.is_empty() { - sink.push(diags::Wildcards { - krate, - severity, - wildcards, - allow_wildcard_paths, - cargo_spans: &cargo_spans, + }); + + let unmatched_exe_configs = { + let mut pack = Pack::new(Check::Bans); + + for ve in bcv + .into_inner() + .into_iter() + .zip(build_config.allow_executables.into_iter()) + .filter_map(|(hit, ve)| if !hit { Some(ve) } else { None }) + { + pack.push(diags::UnmatchedBuildConfig { + unmatched: &ve, + file_id, }); } - } - } - - if let Some(allow_build_scripts) = &allow_build_scripts { - let has_build_script = krate - .targets - .iter() - .any(|t| t.kind.iter().any(|k| *k == "custom-build")); - - if has_build_script { - let allowed_build_script = allow_build_scripts.value.iter().any(|id| { - krate.name == id.name && crate::match_req(&krate.version, id.version.as_ref()) - }); - if !allowed_build_script { - pack.push(diags::BuildScriptNotAllowed { krate }); - } - } - } + pack + }; - if !pack.is_empty() { - sink.push(pack); + Some( + pq.into_inner() + .into_values() + .chain(Some(unmatched_exe_configs)), + ) + }, + ); + + if let Some(bps) = build_packs { + for bp in bps { + sink.push(bp); } } - report_duplicates(&multi_detector, &mut sink); - let mut pack = Pack::new(Check::Bans); for skip in skip_hit @@ -738,3 +842,433 @@ pub fn check( sink.push(pack); } + +pub fn check_build( + file_id: FileId, + config: &ValidBuildConfig, + home: Option<&crate::Path>, + krate: &Krate, + krates: &Krates, + pack: &mut Pack, +) -> Option { + if let Some(allow_build_scripts) = &config.allow_build_scripts { + let has_build_script = krate + .targets + .iter() + .any(|t| t.kind.iter().any(|k| *k == "custom-build")); + + if has_build_script { + let allowed_build_script = allow_build_scripts.value.iter().any(|id| { + krate.name == id.name && crate::match_req(&krate.version, id.version.as_ref()) + }); + + if !allowed_build_script { + pack.push(diags::BuildScriptNotAllowed { krate }); + } + } + } + + if config.executables == LintLevel::Allow { + return None; + } + + #[inline] + fn executes_at_buildtime(krate: &Krate) -> bool { + krate.targets.iter().any(|t| { + t.kind + .iter() + .any(|k| *k == "custom-build" || *k == "proc-macro") + }) + } + + fn needs_checking(krate: krates::NodeId, krates: &Krates) -> bool { + if executes_at_buildtime(&krates[krate]) { + return true; + } + + for dd in krates.direct_dependents(krate) { + if needs_checking(dd.node_id, krates) { + return true; + } + } + + false + } + + // Check if the krate is either a proc-macro, has a build-script, OR is a dependency + // of a crate that is/does + if !config.include_workspace + && krates.workspace_members().any(|n| { + if let krates::Node::Krate { id, .. } = n { + id == &krate.id + } else { + false + } + }) + || (!config.include_dependencies && !executes_at_buildtime(krate)) + || (config.include_dependencies + && !needs_checking(krates.nid_for_kid(&krate.id).unwrap(), krates)) + { + return None; + } + + let (kc_index, krate_config) = config + .allow_executables + .iter() + .enumerate() + .find_map(|(i, ae)| { + (ae.name.value == krate.name && crate::match_req(&krate.version, ae.version.as_ref())) + .then_some((i, ae)) + }) + .unzip(); + + // If the build script hashes to the same value and required features are not actually + // set on the crate, we can skip it + if let Some(kc) = krate_config { + if let Some((bsc, rf)) = kc.build_script.as_ref().zip(kc.required_features.as_ref()) { + if let Some(path) = krate + .targets + .iter() + .find_map(|t| (t.name == "build-script-build").then_some(&t.src_path)) + { + let root = &krate.manifest_path.parent().unwrap(); + match validate_file_checksum(path, &bsc.value) { + Ok(_) => { + pack.push(diags::ChecksumMatch { + path: diags::HomePath { path, root, home }, + checksum: bsc, + severity: None, + file_id, + }); + + // Emit an error if the user specifies features that don't exist + for rfeat in rf { + if !krate.features.contains_key(&rfeat.value) { + pack.push(diags::UnknownFeature { + krate, + feature: rfeat, + file_id, + }); + } + } + + let enabled = krates.get_enabled_features(&krate.id).unwrap(); + + let enabled_features: Vec<_> = + rf.iter().filter(|f| enabled.contains(&f.value)).collect(); + + // If none of the required-features are present then we + // can skip the rest of the check + if enabled_features.is_empty() { + return kc_index; + } + + pack.push(diags::FeaturesEnabled { + enabled_features, + file_id, + }); + } + Err(err) => { + pack.push(diags::ChecksumMismatch { + path: diags::HomePath { path, root, home }, + checksum: bsc, + severity: Some(Severity::Warning), + error: format!("build script failed checksum: {err:#}"), + file_id, + }); + } + } + } + } + } + + let root = krate.manifest_path.parent().unwrap(); + + let (tx, rx) = crossbeam::channel::unbounded(); + + let (_, checksum_diags) = rayon::join( + || { + // Avoids doing a ton of heap allocations when doing globset matching + let mut matches = Vec::new(); + let is_git_src = krate.is_git_source(); + + for entry in walkdir::WalkDir::new(root) + .sort_by_file_name() + .into_iter() + .filter_entry(|entry| { + // Skip git folders for git sources, they won't be present in + // regular packages, and the example scripts in typical + // clones are...not interesting + !is_git_src + || (entry.path().file_name() == Some(std::ffi::OsStr::new(".git")) + && entry.path().parent() == Some(root.as_std_path())) + }) + { + let Ok(entry) = entry else { + continue; + }; + + if entry.file_type().is_dir() { + continue; + } + + let absolute_path = match crate::PathBuf::from_path_buf(entry.into_path()) { + Ok(p) => p, + Err(path) => { + pack.push( + crate::diag::Diagnostic::warning() + .with_message(format!("path {path:?} is not utf-8, skipping")), + ); + continue; + } + }; + + let path = &absolute_path; + + let Ok(rel_path) = path.strip_prefix(root) else { + pack.push(crate::diag::Diagnostic::error().with_message(format!( + "path '{path}' is not relative to crate root '{root}'" + ))); + continue; + }; + + let candidate = globset::Candidate::new(rel_path); + + if let Some(kc) = krate_config { + // First just check if the file has been explicitly allowed without a + // checksum so we don't even need to bother going more in depth + let ae = kc.allow.as_ref().and_then(|aexes| { + aexes + .binary_search_by(|ae| ae.path.value.as_path().cmp(rel_path)) + .ok() + .map(|i| &aexes[i]) + }); + + if let Some(ae) = ae { + if ae.checksum.is_none() { + pack.push(diags::ExplicitPathAllowance { + allowed: ae, + file_id, + }); + continue; + } + } + + // Check if the path matches an allowed glob pattern + if let Some(ag) = &kc.allow_globs { + if let Some(matches) = ag.matches(&candidate, &mut matches) { + pack.push(diags::GlobAllowance { + path: diags::HomePath { path, root, home }, + globs: matches, + file_id, + }); + continue; + } + } + + // If the file had a checksum specified, verify it still matches, + // otherwise fail + if let Some(checksum) = ae.as_ref().and_then(|ae| ae.checksum.as_ref()) { + let _ = tx.send((absolute_path, checksum)); + continue; + } + } + + // Check if the file matches a disallowed glob pattern + if let Some(matches) = config.script_extensions.matches(&candidate, &mut matches) { + pack.push(diags::DisallowedByExtension { + path: diags::HomePath { path, root, home }, + globs: matches, + file_id, + }); + continue; + } + + // Save the most ambiguous/expensive check for last, does this look + // like a native executable or script without extension? + let diag: Diag = match check_is_executable(path, !config.include_archives) { + Ok(None) => continue, + Ok(Some(exe_kind)) => diags::DetectedExecutable { + path: diags::HomePath { path, root, home }, + interpreted: config.interpreted, + exe_kind, + } + .into(), + Err(error) => diags::UnableToCheckPath { + path: diags::HomePath { path, root, home }, + error, + } + .into(), + }; + + pack.push(diag); + } + + drop(tx); + }, + || { + // Note that since we ship off the checksum validation to a threads the order is + // not guaranteed, so we just put them in a btreemap so they are consistently + // ordered and don't trigger test errors or cause confusing output for users + let checksum_diags = parking_lot::Mutex::new(std::collections::BTreeMap::new()); + rayon::scope(|s| { + while let Ok((path, checksum)) = rx.recv() { + s.spawn(|_s| { + let absolute_path = path; + let path = &absolute_path; + if let Err(err) = validate_file_checksum(&absolute_path, &checksum.value) { + let diag: Diag = diags::ChecksumMismatch { + path: diags::HomePath { path, root, home }, + checksum, + severity: None, + error: format!("{err:#}"), + file_id, + } + .into(); + + checksum_diags.lock().insert(absolute_path, diag); + } else { + let diag: Diag = diags::ChecksumMatch { + path: diags::HomePath { path, root, home }, + checksum, + severity: None, + file_id, + } + .into(); + + checksum_diags.lock().insert(absolute_path, diag); + } + }); + } + }); + + checksum_diags.into_inner().into_values() + }, + ); + + for diag in checksum_diags { + pack.push(diag); + } + + kc_index +} + +pub(crate) enum ExecutableKind { + Native(goblin::Hint), + Interpreted(String), +} + +fn check_is_executable( + path: &crate::Path, + exclude_archives: bool, +) -> anyhow::Result> { + use std::io::Read; + + let mut file = std::fs::File::open(path)?; + let mut header = [0u8; 16]; + let read = file.read(&mut header)?; + if read != header.len() { + return Ok(None); + } + + match goblin::peek_bytes(&header) + .map_err(|err| anyhow::format_err!("failed to peek bytes: {err}"))? + { + // Archive objects/libraries are not great (generally) to have in + // crate packages, but they are not as easily + goblin::Hint::Archive if exclude_archives => Ok(None), + goblin::Hint::Unknown(_) => { + // Check for shebang scripts + if header[..2] != [0x23, 0x21] { + return Ok(None); + } + + // If we have a shebang, look to see if we have the newline, otherwise we need to read more bytes + let mut hdr = [0u8; 256]; + let header = if !header.iter().any(|b| *b == b'\n') { + hdr[..16].copy_from_slice(&header); + let read = file.read(&mut hdr[16..])?; + &hdr[..read + 16] + } else { + &header[..] + }; + + let parse = || { + let line_end = header.iter().position(|b| *b == b'\n')?; + let line = std::str::from_utf8(&header[..line_end]).ok()?; + + // If it's a rust file, ignore it if the shebang is actually + // an inner attribute + if path.extension() == Some("rs") && line.starts_with("#![") { + return None; + } + + // Shebangs scripts can't have any spaces in the actual interpreter, but there + // can be an optional space between the shebang and the start of the interpreter + let mut items = line.split(' '); + let maybe_interpreter = items.next()?; + let interpreter = if maybe_interpreter.ends_with("#!") { + items.next()? + } else { + maybe_interpreter + }; + + // Handle (typically) /usr/bin/env being used as level of indirection + // to make running scripts more friendly to run on a variety + // of systems + if interpreter.ends_with("/env") { + items.next() + } else if let Some((_, bin)) = interpreter.rsplit_once('/') { + Some(bin) + } else { + Some(interpreter) + } + }; + + Ok(parse().map(|s| ExecutableKind::Interpreted(s.to_owned()))) + } + hint => Ok(Some(ExecutableKind::Native(hint))), + } +} + +/// Validates the buffer matches the expected SHA-256 checksum +fn validate_checksum( + mut stream: impl std::io::Read, + expected: &cfg::Checksum, +) -> anyhow::Result<()> { + let digest = { + let mut dc = ring::digest::Context::new(&ring::digest::SHA256); + let mut chunk = [0; 8 * 1024]; + loop { + let read = stream.read(&mut chunk)?; + if read == 0 { + break; + } + dc.update(&chunk[..read]); + } + dc.finish() + }; + + let digest = digest.as_ref(); + if digest != expected.0 { + let mut hs = [0u8; 64]; + const CHARS: &[u8] = b"0123456789abcdef"; + for (i, &byte) in digest.iter().enumerate() { + let i = i * 2; + hs[i] = CHARS[(byte >> 4) as usize]; + hs[i + 1] = CHARS[(byte & 0xf) as usize]; + } + + let digest = std::str::from_utf8(&hs).unwrap(); + anyhow::bail!("checksum mismatch, calculated {digest}"); + } + + Ok(()) +} + +#[inline] +fn validate_file_checksum(path: &crate::Path, expected: &cfg::Checksum) -> anyhow::Result<()> { + let file = std::fs::File::open(path)?; + validate_checksum(std::io::BufReader::new(file), expected)?; + Ok(()) +} diff --git a/src/bans/builtin_globs.toml b/src/bans/builtin_globs.toml new file mode 100644 index 000000000..44e1a3d42 --- /dev/null +++ b/src/bans/builtin_globs.toml @@ -0,0 +1,19 @@ +# List of "common" patterns for scripting languages or easily executable +# compiled languages that could be used for local execution with build scripts +# or proc macros. Obviously this list is not and never can be complete since +# in most cases extensions are only for humans and most tools will happily +# execute scripts/code they can regardless of extension (eg. shell scripts), +# and besides that, an _actually_ malicious crate could generate files on demand, +# download from a remote location, or, really, anything +globs = [ + "*.bat", "*.cmd", # batch + "*.go", # Go `go run ` + "*.java", # Java `java ` + "*.js", "*._js", "*.es", "*.es6", # javascript + "*.pl", "*.perl", "*.pm", # perl + "*.6pl", "*.6pm", "*.p6", "*.p6l", "*.p6m", "*.pl6", "*.pm6", "*.t", # perl 6 + "*.ps1", "*.psd1", "*.psm1", # powershell + "*.py", # python + "*.rb", # ruby + "*.sh", "*.bash", "*.zsh", # shell +] diff --git a/src/bans/cfg.rs b/src/bans/cfg.rs index b003f3ac9..e459f537f 100644 --- a/src/bans/cfg.rs +++ b/src/bans/cfg.rs @@ -85,6 +85,151 @@ impl GraphHighlight { } } +#[derive(Clone)] +#[cfg_attr(test, derive(Debug, PartialEq, Eq))] +pub struct Checksum(pub [u8; 32]); + +pub enum ChecksumParseError { + /// The checksum string had an invalid length + InvalidLength(usize), + /// The checksum string contained a non-hex character + InvalidValue(char), +} + +impl std::str::FromStr for Checksum { + type Err = ChecksumParseError; + + fn from_str(data: &str) -> Result { + if data.len() != 64 { + return Err(ChecksumParseError::InvalidLength(data.len())); + } + + let mut array = [0u8; 32]; + + for (ind, chunk) in data.as_bytes().chunks(2).enumerate() { + #[inline] + fn parse_hex(b: u8) -> Result { + Ok(match b { + b'A'..=b'F' => b - b'A' + 10, + b'a'..=b'f' => b - b'a' + 10, + b'0'..=b'9' => b - b'0', + c => { + return Err(ChecksumParseError::InvalidValue(c as char)); + } + }) + } + + let mut cur = parse_hex(chunk[0])?; + cur <<= 4; + cur |= parse_hex(chunk[1])?; + + array[ind] = cur; + } + + Ok(Self(array)) + } +} + +impl<'de> Deserialize<'de> for Checksum { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::Error; + struct HexStrVisitor; + + impl<'de> serde::de::Visitor<'de> for HexStrVisitor { + type Value = Checksum; + + fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "a sha-256 hex encoded string") + } + + fn visit_str(self, data: &str) -> Result { + data.parse().map_err(|err| match err { + ChecksumParseError::InvalidLength(len) => { + serde::de::Error::invalid_length(len, &"a string with 64 characters") + } + ChecksumParseError::InvalidValue(c) => serde::de::Error::invalid_value( + serde::de::Unexpected::Char(c), + &"a hexadecimal character", + ), + }) + } + + fn visit_borrowed_str(self, data: &'de str) -> Result { + self.visit_str(data) + } + } + + deserializer.deserialize_str(HexStrVisitor) + } +} + +#[derive(Deserialize, Clone)] +#[cfg_attr(test, derive(Debug, PartialEq, Eq))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct AllowedExecutable { + /// The crate-relative path to the executable + pub path: Spanned, + /// An optional sha-256 checksum to ensure that the executable is matched exactly + pub checksum: Option>, +} + +#[derive(Deserialize, Clone)] +#[cfg_attr(test, derive(Debug, PartialEq, Eq))] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct Executables { + pub name: Spanned, + pub version: Option, + pub build_script: Option>, + /// List of features that, if matched, means the build script/proc macro is + /// not actually executed/run + pub required_features: Option>>, + /// List of glob patterns that are allowed. This is much more loose than + /// `allow`, but can be useful in scenarios where things like test suites or + /// the like that contain many scripts/test executables that are present in + /// the packged source, but are (hopefully) not actually read or executed + /// during builds + pub allow_globs: Option>>, + /// One or more executables that are allowed. If not set all executables are + /// allowed. + pub allow: Option>, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub struct BuildConfig { + /// List of crates that are allowed to have build scripts. If this is set, + /// any crates with a build script that aren't listed here will be banned + pub allow_build_scripts: Option>>, + /// Lint level for when executables are detected within crates with build + /// scripts or are proc macros, or are a dependency of either of them + #[serde(default = "crate::lint_deny")] + pub executables: LintLevel, + /// List of script extensions that are considered to be executable. These + /// are always in addition to the builtin ones. + pub script_extensions: Option>>, + /// The list of allowed executables, by crate + pub allow_executables: Option>, + /// If true, enables the built-in glob patterns + #[serde(default)] + pub enable_builtin_globs: bool, + /// If true, all dependencies of proc macro crates or crates with build + /// scripts are also checked for executables/glob patterns + #[serde(default)] + pub include_dependencies: bool, + /// If true, workspace crates are included + #[serde(default)] + pub include_workspace: bool, + /// If true, archive files are counted as native executables + #[serde(default)] + pub include_archives: bool, + /// The lint level for interpreted scripts + #[serde(default = "crate::lint_allow")] + pub interpreted: LintLevel, +} + #[derive(Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct Config { @@ -129,8 +274,11 @@ pub struct Config { /// thus this rule will not effect public packages. #[serde(default)] pub allow_wildcard_paths: bool, - /// List of crates that are allowed to have a build step. + /// Deprecated and moved into `build.allow_build_scripts`, will eventually + /// be removed pub allow_build_scripts: Option>>, + /// Options for crates that run at build time + pub build: Option, } impl Default for Config { @@ -148,6 +296,7 @@ impl Default for Config { wildcards: LintLevel::Allow, allow_wildcard_paths: false, allow_build_scripts: None, + build: None, } } } @@ -155,7 +304,12 @@ impl Default for Config { impl crate::cfg::UnvalidatedConfig for Config { type ValidCfg = ValidConfig; - fn validate(self, cfg_file: FileId, diags: &mut Vec) -> Self::ValidCfg { + fn validate( + self, + cfg_file: FileId, + files: &mut crate::diag::Files, + diags: &mut Vec, + ) -> Self::ValidCfg { let from = |s: Spanned| { Skrate::new( KrateId { @@ -296,6 +450,170 @@ impl crate::cfg::UnvalidatedConfig for Config { }) .collect(); + let build = if let Some(bc) = self.build { + // Give higher precedence to the user's extensions + let mut gsb = GlobsetBuilder::new(); + if let Some(extensions) = bc.script_extensions { + for ext in extensions { + // This top level config should only be extensions, not glob patterns + if !ext.value.is_ascii() { + diags.push( + Diagnostic::error() + .with_message("non-ascii file extension provided") + .with_labels(vec![Label::primary(cfg_file, ext.span.clone()) + .with_message("invalid extension")]), + ); + continue; + } + + if let Some(i) = ext.value.chars().position(|c| !c.is_ascii_alphanumeric()) { + diags.push( + Diagnostic::error() + .with_message("invalid file extension provided") + .with_labels(vec![ + Label::primary(cfg_file, ext.span.clone()) + .with_message("extension"), + Label::secondary( + cfg_file, + ext.span.start + i..ext.span.start + i + 1, + ) + .with_message("invalid character"), + ]), + ); + continue; + } + + match globset::Glob::new(&format!("*.{}", ext.value)) { + Ok(glob) => { + gsb.add(glob, GlobPattern::User(ext)); + } + Err(err) => { + diags.push( + Diagnostic::error() + .with_message(format!("invalid glob pattern: {err}")) + .with_labels(vec![Label::primary(cfg_file, ext.span.clone()) + .with_message("extension")]), + ); + } + } + } + } + + if bc.enable_builtin_globs { + load_builtin_globs(files, &mut gsb); + } + + let script_extensions = gsb.build().unwrap_or_else(|err| { + diags + .push(Diagnostic::error().with_message(format!( + "failed to build script extensions glob set: {err}" + ))); + ValidGlobSet::default() + }); + + let allow_executables = if let Some(aexes) = bc.allow_executables { + let mut aex = Vec::new(); + + for aexe in aexes { + let allow_globs = if let Some(allow_globs) = aexe.allow_globs { + let mut gsb = GlobsetBuilder::new(); + + for ag in allow_globs { + match globset::Glob::new(&ag.value) { + Ok(glob) => { + gsb.add(glob, GlobPattern::User(ag)); + } + Err(err) => { + diags.push( + Diagnostic::error() + .with_message(format!("invalid glob pattern: {err}")) + .with_labels(vec![Label::primary( + cfg_file, + ag.span.clone(), + )]), + ); + } + } + } + + match gsb.build() { + Ok(set) => Some(set), + Err(err) => { + diags.push(Diagnostic::error().with_message(format!( + "failed to build script extensions glob set: {err}" + ))); + None + } + } + } else { + None + }; + + let allow = aexe.allow.map(|mut aexes| { + aexes.retain(|ae| { + let keep = ae.path.value.is_relative(); + if !keep { + diags.push( + Diagnostic::error() + .with_message("absolute paths are not allowed") + .with_labels(vec![Label::primary( + cfg_file, + ae.path.span.clone(), + )]), + ); + } + + keep + }); + aexes.sort_by(|a, b| a.path.value.cmp(&b.path.value)); + aexes + }); + + aex.push(ValidExecutables { + name: aexe.name, + version: aexe.version, + build_script: aexe.build_script, + required_features: aexe.required_features, + allow, + allow_globs, + }); + } + + aex + } else { + Vec::new() + }; + + Some(ValidBuildConfig { + allow_build_scripts: bc.allow_build_scripts, + executables: bc.executables, + script_extensions, + allow_executables, + include_dependencies: bc.include_dependencies, + include_workspace: bc.include_workspace, + include_archives: bc.include_archives, + interpreted: bc.interpreted, + }) + } else if let Some(allow_build_scripts) = self.allow_build_scripts { + diags.push(Diagnostic::warning() + .with_message("[bans.allow-build-scripts] has been deprecated in favor of [bans.build.allow-build-scripts], this will become an error in the future") + .with_labels(vec![ + Label::primary(cfg_file, allow_build_scripts.span.clone()) + ])); + Some(ValidBuildConfig { + allow_build_scripts: Some(allow_build_scripts), + executables: LintLevel::Allow, + script_extensions: ValidGlobSet::default(), + allow_executables: Vec::new(), + include_dependencies: false, + include_workspace: false, + include_archives: false, + interpreted: LintLevel::Warn, + }) + } else { + None + }; + ValidConfig { file_id: cfg_file, multiple_versions: self.multiple_versions, @@ -314,22 +632,30 @@ impl crate::cfg::UnvalidatedConfig for Config { .into_iter() .map(crate::Spanned::from) .collect(), - allow_build_scripts: self.allow_build_scripts.map(|v| { - Spanned::new( - v.value - .into_iter() - .map(|id| KrateId { - name: id.name, - version: id.version, - }) - .collect(), - v.span, - ) - }), + build, } } } +fn load_builtin_globs(files: &mut crate::diag::Files, gsb: &mut GlobsetBuilder) { + const BUILTIN_GLOBS: &str = include_str!("builtin_globs.toml"); + + #[derive(Deserialize)] + struct Builtin { + globs: Vec>, + } + + let bi: Builtin = toml::from_str(BUILTIN_GLOBS).expect("failed to parse builtin_globs.toml"); + let file_id = files.add("builtin_globs.toml", BUILTIN_GLOBS.to_owned()); + + for glob in bi.globs { + gsb.add( + globset::Glob::new(&glob.value).expect("failed to parse builtin glob"), + GlobPattern::Builtin((glob, file_id)), + ); + } +} + #[inline] pub(crate) fn exact_match<'v>(arr: &'v [Skrate], id: &'_ KrateId) -> Option<&'v Skrate> { arr.iter().find(|sid| *sid == id) @@ -356,6 +682,87 @@ pub(crate) struct KrateFeatures { pub features: Features, } +pub enum GlobPattern { + Builtin((Spanned, FileId)), + User(Spanned), +} + +struct GlobsetBuilder { + builder: globset::GlobSetBuilder, + patterns: Vec, +} + +impl GlobsetBuilder { + fn new() -> Self { + Self { + builder: globset::GlobSetBuilder::new(), + patterns: Vec::new(), + } + } + + fn add(&mut self, glob: globset::Glob, pattern: GlobPattern) { + self.builder.add(glob); + self.patterns.push(pattern); + } + + fn build(self) -> anyhow::Result { + use anyhow::Context as _; + let set = self.builder.build().context("unable to build globset")?; + + Ok(ValidGlobSet { + set, + patterns: self.patterns, + }) + } +} + +pub struct ValidGlobSet { + set: globset::GlobSet, + /// Patterns in the globset for lint output + patterns: Vec, +} + +impl Default for ValidGlobSet { + fn default() -> Self { + Self { + set: globset::GlobSet::empty(), + patterns: Vec::new(), + } + } +} + +impl ValidGlobSet { + #[inline] + pub fn matches( + &self, + path: &globset::Candidate<'_>, + indices: &mut Vec, + ) -> Option> { + self.set.matches_candidate_into(path, indices); + (!indices.is_empty()).then(|| indices.iter().map(|i| &self.patterns[*i]).collect()) + } +} + +pub struct ValidExecutables { + pub name: Spanned, + pub version: Option, + pub build_script: Option>, + pub required_features: Option>>, + pub allow_globs: Option, + pub allow: Option>, +} + +pub struct ValidBuildConfig { + pub allow_build_scripts: Option>>, + pub executables: LintLevel, + pub script_extensions: ValidGlobSet, + pub allow_executables: Vec, + pub include_dependencies: bool, + pub include_workspace: bool, + pub include_archives: bool, + pub interpreted: LintLevel, +} + pub struct ValidConfig { pub file_id: FileId, pub multiple_versions: LintLevel, @@ -370,7 +777,7 @@ pub struct ValidConfig { pub(crate) tree_skipped: Vec>, pub wildcards: LintLevel, pub allow_wildcard_paths: bool, - pub allow_build_scripts: Option>>, + pub build: Option, } #[cfg(test)] @@ -408,10 +815,10 @@ mod test { bans: Config, } - let cd: ConfigData = load("tests/cfg/bans.toml"); + let mut cd: ConfigData = load("tests/cfg/bans.toml"); let mut diags = Vec::new(); - let validated = cd.config.bans.validate(cd.id, &mut diags); + let validated = cd.config.bans.validate(cd.id, &mut cd.files, &mut diags); assert!(diags.is_empty()); assert_eq!(validated.file_id, cd.id); diff --git a/src/bans/diags.rs b/src/bans/diags.rs index fc4603dd4..4704ccd61 100644 --- a/src/bans/diags.rs +++ b/src/bans/diags.rs @@ -1,5 +1,7 @@ +use std::fmt; + use crate::{ - bans::KrateId, + bans::{cfg, KrateId}, diag::{ CfgCoord, Check, Diag, Diagnostic, FileId, GraphNode, KrateCoord, Label, Pack, Severity, }, @@ -36,6 +38,16 @@ pub enum Code { FeatureBanned, UnknownFeature, DefaultFeatureEnabled, + PathAllowed, + PathAllowedByGlob, + ChecksumMatch, + ChecksumMismatch, + DisallowedByExtension, + DetectedExecutable, + DetectedExecutableScript, + UnableToCheckPath, + FeaturesEnabled, + UnmatchedBuildConfig, } impl From for String { @@ -480,3 +492,298 @@ impl From> for Diag { } } } + +pub(crate) struct HomePath<'a> { + pub(crate) path: &'a crate::Path, + pub(crate) root: &'a crate::Path, + pub(crate) home: Option<&'a crate::Path>, +} + +impl<'a> fmt::Display for HomePath<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(rel_path) = self.home.and_then(|home| self.path.strip_prefix(home).ok()) { + f.write_str("$CARGO_HOME/")?; + f.write_str(rel_path.as_str()) + } else if let Ok(rel_path) = self.path.strip_prefix(self.root) { + f.write_str("$crate/")?; + f.write_str(rel_path.as_str()) + } else { + f.write_str(self.path.as_str()) + } + } +} + +pub(crate) struct ExplicitPathAllowance<'a> { + pub(crate) allowed: &'a cfg::AllowedExecutable, + pub(crate) file_id: FileId, +} + +impl From> for Diag { + fn from(pa: ExplicitPathAllowance<'_>) -> Diag { + let mut labels = + vec![Label::primary(pa.file_id, pa.allowed.path.span.clone()) + .with_message("allowed path")]; + + labels.extend(pa.allowed.checksum.as_ref().map(|chk| { + Label::secondary(pa.file_id, chk.span.clone()).with_message("matched checksum") + })); + let diag = Diagnostic::new(Severity::Help) + .with_message("file explicitly allowed") + .with_code(Code::PathAllowed) + .with_labels(labels); + + Diag { + diag, + // Not really helpful to show graphs for these + graph_nodes: Default::default(), + extra: None, + with_features: false, + } + } +} + +#[inline] +fn globs_to_labels(file_id: FileId, globs: Vec<&cfg::GlobPattern>) -> Vec