diff --git a/Cargo.lock b/Cargo.lock index 1aa554a2..a04428df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,9 +168,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -234,9 +234,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -284,9 +284,9 @@ checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" [[package]] name = "cc" -version = "1.0.98" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" [[package]] name = "cfg-if" @@ -599,9 +599,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" @@ -630,12 +630,13 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set", - "regex", + "regex-automata", + "regex-syntax", ] [[package]] @@ -689,9 +690,9 @@ dependencies = [ [[package]] name = "fraction" -version = "0.13.1" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3027ae1df8d41b4bed2241c8fdad4acc1e7af60c8e17743534b545e77182d678" +checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" dependencies = [ "lazy_static", "num", @@ -961,7 +962,7 @@ version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbd06203b1a9b33a78c88252a625031b094d9e1b647260070c25b09910c0a804" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "gix-path", "libc", @@ -987,9 +988,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367ee9093b0c2b04fd04c5c7c8b6a1082713534eab537597ae343663a518fa99" +checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0" dependencies = [ "bstr", "itoa", @@ -1087,7 +1088,7 @@ version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a29ad0990cf02c48a7aac76ed0dbddeb5a0d070034b83675cc3bbf937eace4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "gix-features", "gix-path", @@ -1133,7 +1134,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d8c5a5f1c58edcbc5692b174cda2703aba82ed17d7176ff4c1752eb48b1b167" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "filetime", "fnv", @@ -1183,7 +1184,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d57dec54544d155a495e01de947da024471e1825d7d3f2724301c07a310d6184" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "gix-commitgraph", "gix-date", "gix-hash", @@ -1279,9 +1280,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23623cf0f475691a6d943f898c4d0b89f5c1a2a64d0f92bce0e0322ee6528783" +checksum = "ca987128ffb056d732bd545db5db3d8b103d252fbf083c2567bb0796876619a4" dependencies = [ "bstr", "gix-trace", @@ -1296,7 +1297,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76cab098dc10ba2d89f634f66bf196dea4d7db4bf10b75c7a9c201c55a2ee19" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "gix-attributes", "gix-config-value", @@ -1420,7 +1421,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fddc27984a643b20dd03e97790555804f98cf07404e0e552c0ad8133266a79a1" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "gix-path", "libc", "windows-sys 0.52.0", @@ -1485,7 +1486,7 @@ version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f20cb69b63eb3e4827939f42c05b7756e3488ef49c25c412a876691d568ee2a0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "gix-commitgraph", "gix-date", "gix-hash", @@ -1624,12 +1625,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -1683,12 +1678,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1696,9 +1691,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "human_format" @@ -1728,19 +1723,20 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.26.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http", "hyper", "hyper-util", - "rustls", + "rustls 0.23.10", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -1880,6 +1876,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1959,13 +1964,13 @@ dependencies = [ [[package]] name = "jsonschema" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" +checksum = "ec0afd06142c9bcb03f4a8787c77897a87b6be9c4918f1946c33caa714c27578" dependencies = [ "ahash", "anyhow", - "base64 0.21.7", + "base64 0.22.1", "bytecount", "fancy-regex", "fraction", @@ -2021,9 +2026,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -2043,7 +2048,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -2101,9 +2106,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -2160,9 +2165,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minijinja" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7165d0e94806d52ad5295e4b54a95176d831814840bc067298ca647e1c956338" +checksum = "e136ef580d7955019ab0a407b68d77c292a9976907e217900f3f76bc8f6dc1a4" dependencies = [ "aho-corasick", "memo-map", @@ -2179,9 +2184,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -2292,16 +2297,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "num_threads" version = "0.1.7" @@ -2313,9 +2308,9 @@ dependencies = [ [[package]] name = "object" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] @@ -2441,7 +2436,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -2591,9 +2586,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2608,6 +2603,53 @@ dependencies = [ "human_format", ] +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.10", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.23.10", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -2717,11 +2759,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -2749,9 +2791,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -2760,15 +2802,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "regorus" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77dd872918e5c172bd42ac49716f89a15e35be513bba3d902e355a531529a87f" +checksum = "b74c40edcecf90b1f39ecc7bd445e31d361b570fdd483c892542da6fbf117195" dependencies = [ "anyhow", "chrono", @@ -2777,12 +2819,11 @@ dependencies = [ "data-encoding", "hex", "hmac", - "itertools 0.12.1", + "itertools 0.13.0", "jsonschema", "jsonwebtoken", "lazy_static", "md-5", - "num", "rand 0.8.5", "regex", "scientific", @@ -2808,9 +2849,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -2832,7 +2873,8 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "quinn", + "rustls 0.23.10", "rustls-pemfile", "rustls-pki-types", "serde", @@ -2872,13 +2914,19 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -2899,6 +2947,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -2967,9 +3029,9 @@ dependencies = [ [[package]] name = "scientific" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc53198b8e237c451c68dba8411a1f8bd92787657689f24d67ae3d6b98c39f59" +checksum = "38a4b339a8de779ecb098a772ecbba2ace74e23ed959a5b4f30631d8bf1799a8" dependencies = [ "scientific-macro", ] @@ -3039,9 +3101,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", @@ -3191,9 +3253,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "supports-color" @@ -3218,9 +3280,9 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -3229,9 +3291,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "system-configuration" @@ -3358,9 +3420,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" dependencies = [ "tinyvec_macros", ] @@ -3381,7 +3443,6 @@ dependencies = [ "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "windows-sys 0.48.0", @@ -3389,11 +3450,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.10", "rustls-pki-types", "tokio", ] @@ -3479,9 +3540,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -3591,7 +3664,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls", + "rustls 0.22.4", "rustls-pki-types", "rustls-webpki", "url", @@ -3600,9 +3673,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -3617,15 +3690,15 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" dependencies = [ "getrandom", "rand 0.8.5", @@ -3959,9 +4032,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] diff --git a/crates/weaver_checker/Cargo.toml b/crates/weaver_checker/Cargo.toml index 539f4ee7..a5728b23 100644 --- a/crates/weaver_checker/Cargo.toml +++ b/crates/weaver_checker/Cargo.toml @@ -24,7 +24,8 @@ walkdir.workspace = true globset.workspace = true miette.workspace = true -regorus = { version = "0.1.5", default-features = false, features = [ +regorus = { version = "0.2.0", default-features = false, features = [ + "std", "arc", "base64", "base64url", diff --git a/crates/weaver_checker/src/lib.rs b/crates/weaver_checker/src/lib.rs index 705dc4df..94ea90ab 100644 --- a/crates/weaver_checker/src/lib.rs +++ b/crates/weaver_checker/src/lib.rs @@ -3,6 +3,7 @@ #![allow(rustdoc::broken_intra_doc_links)] #![doc = include_str!("../README.md")] +use std::collections::HashSet; use std::fmt::{Display, Formatter}; use std::path::Path; @@ -11,8 +12,8 @@ use miette::Diagnostic; use serde::Serialize; use serde_json::to_value; use walkdir::DirEntry; -use weaver_common::diagnostic::{DiagnosticMessage, DiagnosticMessages}; +use weaver_common::diagnostic::{DiagnosticMessage, DiagnosticMessages}; use weaver_common::error::{format_errors, handle_errors, WeaverError}; use crate::violation::Violation; @@ -146,6 +147,13 @@ impl Display for PolicyStage { pub struct Engine { // The `regorus` policy engine. engine: regorus::Engine, + // Flag to enable the coverage report. + coverage_enabled: bool, + // Number of policy packages added. + policy_package_count: usize, + // Policy packages loaded. This is used to check if a policy package has been imported + // before evaluating it. + policy_packages: HashSet, } impl Engine { @@ -155,21 +163,36 @@ impl Engine { Default::default() } + /// Enables the coverage report. + pub fn enable_coverage(&mut self) { + self.engine.set_enable_coverage(true); + self.coverage_enabled = true; + } + /// Adds a policy file to the policy engine. /// A policy file is a `rego` file that contains the policies to be evaluated. /// /// # Arguments /// /// * `policy_path` - The path to the policy file. - pub fn add_policy>(&mut self, policy_path: P) -> Result<(), Error> { + pub fn add_policy>(&mut self, policy_path: P) -> Result { let policy_path_str = policy_path.as_ref().to_string_lossy().to_string(); - self.engine + let policy_package = self + .engine .add_policy_from_file(policy_path) .map_err(|e| Error::InvalidPolicyFile { file: policy_path_str.clone(), error: e.to_string(), }) + .inspect(|_| { + self.policy_package_count += 1; + })?; + // Add the policy package defined in the imported policy file. + // Nothing prevent multiple policy files to import the same policy package. + // All the rules will be combined and evaluated together. + _ = self.policy_packages.insert(policy_package.clone()); + Ok(policy_package) } /// Adds all the policy files present in the given directory that match the @@ -224,9 +247,16 @@ impl Engine { handle_errors(errors)?; + self.policy_package_count += added_policy_count; Ok(added_policy_count) } + /// Returns the number of policy packages added to the policy engine. + #[must_use] + pub fn policy_package_count(&self) -> usize { + self.policy_package_count + } + /// Adds a data document to the policy engine. /// /// Data versus Input: In essence, data is about what the policy engine @@ -280,7 +310,14 @@ impl Engine { /// Returns a list of violations based on the policies, the data, the /// input, and the given policy stage. + #[allow(clippy::print_stdout)] // Used to display the coverage (debugging purposes only) pub fn check(&mut self, stage: PolicyStage) -> Result, Error> { + // If we don't have any policy package that matches the stage, + // return an empty list of violations. + if !self.policy_packages.contains(&format!("data.{}", stage)) { + return Ok(vec![]); + } + let value = self .engine .eval_rule(format!("data.{}.deny", stage)) @@ -288,6 +325,24 @@ impl Engine { error: e.to_string(), })?; + // Print the coverage report if enabled + // This is useful for debugging purposes + if self.coverage_enabled { + let report = + self.engine + .get_coverage_report() + .map_err(|e| Error::ViolationEvaluationError { + error: e.to_string(), + })?; + let pretty_report = + report + .to_string_pretty() + .map_err(|e| Error::ViolationEvaluationError { + error: e.to_string(), + })?; + println!("{}", pretty_report); + } + // convert `regorus` value to `serde_json` value let json_value = to_value(&value).map_err(|e| Error::ViolationEvaluationError { error: e.to_string(), @@ -317,7 +372,8 @@ mod tests { #[test] fn test_policy() -> Result<(), Box> { let mut engine = Engine::new(); - engine.add_policy("data/policies/otel_policies.rego")?; + let policy_package = engine.add_policy("data/policies/otel_policies.rego")?; + assert_eq!(policy_package, "data.before_resolution"); let old_semconv = std::fs::read_to_string("data/registries/registry.network.old.yaml")?; let old_semconv: Value = serde_yaml::from_str(&old_semconv)?; @@ -378,7 +434,7 @@ mod tests { #[test] fn test_invalid_violation_object() { let mut engine = Engine::new(); - engine + _ = engine .add_policy("data/policies/invalid_violation_object.rego") .unwrap(); diff --git a/crates/weaver_codegen_test/semconv_registry/http-post-resolution-policies.rego b/crates/weaver_codegen_test/semconv_registry/http-post-resolution-policies.rego new file mode 100644 index 00000000..518106ec --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/http-post-resolution-policies.rego @@ -0,0 +1,21 @@ +package after_resolution + +# Example of rules that will be applied on resolved semconv files + +# Detect `http.request.method` attribute and consider it invalid. +# This is just an example for testing purposes. +deny[invalid_attr_violation("invalid_http_attr", group.id, attr.name)] { + group := input.groups[_] + attr := group.attributes[_] + attr.name == "http.request.method" +} + +invalid_attr_violation(violation_id, group_id, attr_id) = violation { + violation := { + "id": violation_id, + "type": "semconv_attribute", + "category": "attrigute", + "group": group_id, + "attr": attr_id, + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/metrics-post-resolution-policies.rego b/crates/weaver_codegen_test/semconv_registry/metrics-post-resolution-policies.rego new file mode 100644 index 00000000..8908bc7c --- /dev/null +++ b/crates/weaver_codegen_test/semconv_registry/metrics-post-resolution-policies.rego @@ -0,0 +1,21 @@ +package after_resolution + +# Example of rules that will be applied on resolved semconv files + +# Detect `system.cpu.logical_number` attribute and consider it invalid. +# This is just an example for testing purposes. +deny[invalid_attr_violation("invalid_metric_attr", group.id, attr.name)] { + group := input.groups[_] + attr := group.attributes[_] + attr.name == "system.cpu.logical_number" +} + +invalid_attr_violation(violation_id, group_id, attr_id) = violation { + violation := { + "id": violation_id, + "type": "semconv_attribute", + "category": "attrigute", + "group": group_id, + "attr": attr_id, + } +} \ No newline at end of file diff --git a/crates/weaver_codegen_test/semconv_registry/otel_policies.rego b/crates/weaver_codegen_test/semconv_registry/otel-pre-resolution-policies.rego similarity index 100% rename from crates/weaver_codegen_test/semconv_registry/otel_policies.rego rename to crates/weaver_codegen_test/semconv_registry/otel-pre-resolution-policies.rego diff --git a/crates/weaver_common/src/diagnostic.rs b/crates/weaver_common/src/diagnostic.rs index e1f9ce26..6559d3f7 100644 --- a/crates/weaver_common/src/diagnostic.rs +++ b/crates/weaver_common/src/diagnostic.rs @@ -39,7 +39,7 @@ pub struct MietteDiagnosticExt { } /// A generic and serializable representation of a diagnostic message -#[derive(Debug, serde::Serialize)] +#[derive(Debug, serde::Serialize, Clone)] pub struct DiagnosticMessage { /// The error pub(crate) error: serde_json::Value, @@ -48,7 +48,7 @@ pub struct DiagnosticMessage { } /// A list of diagnostic messages -#[derive(Debug, serde::Serialize)] +#[derive(Debug, serde::Serialize, Clone)] #[serde(transparent)] pub struct DiagnosticMessages(Vec); @@ -86,6 +86,18 @@ impl DiagnosticMessages { Self(diag_msgs) } + /// Creates an empty list of diagnostic messages + #[must_use] + pub fn empty() -> Self { + Self(Vec::new()) + } + + /// Extends the current `DiagnosticMessages` with the provided + /// `DiagnosticMessages`. + pub fn extend(&mut self, diag_msgs: DiagnosticMessages) { + self.0.extend(diag_msgs.0); + } + /// Logs all the diagnostic messages pub fn log(&self, logger: impl Logger) { self.0 @@ -139,6 +151,43 @@ impl DiagnosticMessages { } } +/// An extension trait for `Result` that captures the diagnostic messages +pub trait ResultExt { + /// Captures the diagnostic messages into the provided `DiagnosticMessages` + /// or returns the value if there are no diagnostic messages. + fn capture_diag_msgs_into(self, diags: &mut DiagnosticMessages) -> Option; + + /// Combines the diagnostic messages with the provided `DiagnosticMessages` + /// and returns the `ok` value or the combined `DiagnosticMessages`. + fn combine_diag_msgs_with(self, diags: &DiagnosticMessages) -> Result; +} + +impl ResultExt for Result +where + E: Into, +{ + fn capture_diag_msgs_into(self, diags: &mut DiagnosticMessages) -> Option { + match self { + Ok(v) => Some(v), + Err(diag_msgs) => { + diags.extend(diag_msgs.into()); + None + } + } + } + + fn combine_diag_msgs_with(self, diags: &DiagnosticMessages) -> Result { + match self { + Ok(v) => Ok(v), + Err(errs) => { + let mut diag_msgs: DiagnosticMessages = errs.into(); + diag_msgs.extend(diags.clone()); + Err(diag_msgs) + } + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/weaver_semconv/src/path.rs b/crates/weaver_semconv/src/path.rs index a83484c9..575d3a4d 100644 --- a/crates/weaver_semconv/src/path.rs +++ b/crates/weaver_semconv/src/path.rs @@ -2,6 +2,8 @@ //! Semantic convention registry path. +use std::fmt::{Display, Formatter}; + use serde::{Deserialize, Serialize}; /// A semantic convention registry path. @@ -23,3 +25,16 @@ pub enum RegistryPath { path: Option, }, } + +impl Display for RegistryPath { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let path = match self { + RegistryPath::Local { path_pattern } => format!("LocalRegistry:{}", path_pattern), + RegistryPath::GitUrl { git_url, path } => match path { + Some(path) => format!("GitRegistry:{}/{:?}", git_url, path), + None => format!("GitRegistry:{}", git_url), + }, + }; + f.write_str(&path) + } +} diff --git a/crates/weaver_semconv/src/semconv.rs b/crates/weaver_semconv/src/semconv.rs index f4d17d91..b0cb41cd 100644 --- a/crates/weaver_semconv/src/semconv.rs +++ b/crates/weaver_semconv/src/semconv.rs @@ -302,7 +302,10 @@ mod tests { let semconv_url = "http://unknown.com/unknown-semconv.yaml"; let semconv_spec = SemConvSpec::from_url(semconv_url); assert!(semconv_spec.is_err()); - assert!(matches!(semconv_spec.unwrap_err(), RegistryNotFound { .. })); + assert!(matches!( + semconv_spec.unwrap_err(), + InvalidSemConvSpec { .. } + )); } #[test] diff --git a/src/registry/check.rs b/src/registry/check.rs index 13d556b8..af795c6b 100644 --- a/src/registry/check.rs +++ b/src/registry/check.rs @@ -2,18 +2,25 @@ //! Check a semantic convention registry. -use crate::registry::RegistryArgs; -use crate::util::{ - check_policies, load_semconv_specs, resolve_semconv_specs, semconv_registry_path_from, -}; -use crate::{DiagnosticArgs, ExitDirectives}; -use clap::Args; use std::path::PathBuf; + +use clap::Args; + use weaver_cache::Cache; -use weaver_common::diagnostic::DiagnosticMessages; +use weaver_checker::PolicyStage; +use weaver_common::diagnostic::{DiagnosticMessages, ResultExt}; +use weaver_common::error::handle_errors; use weaver_common::Logger; +use weaver_forge::registry::ResolvedRegistry; use weaver_semconv::registry::SemConvRegistry; +use crate::registry::RegistryArgs; +use crate::util::{ + check_policies, check_policy_stage, init_policy_engine, load_semconv_specs, + resolve_semconv_specs, semconv_registry_path_from, +}; +use crate::{DiagnosticArgs, ExitDirectives}; + /// Parameters for the `registry check` sub-command #[derive(Debug, Args)] pub struct RegistryCheckArgs { @@ -30,6 +37,10 @@ pub struct RegistryCheckArgs { #[arg(long, default_value = "false")] pub skip_policies: bool, + /// Display the policy coverage report (useful for debugging). + #[arg(long, default_value = "false")] + pub display_policy_coverage: bool, + /// Parameters to specify the diagnostic format. #[command(flatten)] pub diagnostic: DiagnosticArgs, @@ -42,6 +53,7 @@ pub(crate) fn command( cache: &Cache, args: &RegistryCheckArgs, ) -> Result { + let mut diag_msgs = DiagnosticMessages::empty(); logger.loading(&format!("Checking registry `{}`", args.registry.registry)); let registry_id = "default"; @@ -51,19 +63,68 @@ pub(crate) fn command( // Load the semantic convention registry into a local cache. // No parsing errors should be observed. let semconv_specs = load_semconv_specs(®istry_path, cache, logger.clone())?; - - if !args.skip_policies { - check_policies( + let mut policy_engine = if !args.skip_policies { + Some(init_policy_engine( ®istry_path, cache, &args.policies, - &semconv_specs, - logger.clone(), - )?; + args.display_policy_coverage, + )?) + } else { + None + }; + + if let Some(policy_engine) = policy_engine.as_ref() { + // Check the policies against the semantic convention specifications before resolution. + // All violations should be captured into an ongoing list of diagnostic messages which + // will be combined with the final result of future stages. + // `check_policies` either returns `()` or diagnostic messages, and `capture_diag_msgs_into` updates the + // provided parameters with any diagnostic messages produced by `check_policies`. + // In this specific case, `capture_diag_msgs_into` returns either `Some(())` or `None` + // if diagnostic messages have been captured. Therefore, it is acceptable to ignore the result in this + // particular case. + _ = check_policies(policy_engine, &semconv_specs, logger.clone()) + .capture_diag_msgs_into(&mut diag_msgs); } let mut registry = SemConvRegistry::from_semconv_specs(registry_id, semconv_specs); - _ = resolve_semconv_specs(&mut registry, logger.clone())?; + // Resolve the semantic convention specifications. + // If there are any resolution errors, they should be captured into the ongoing list of + // diagnostic messages and returned immediately because there is no point in continuing + // as the resolution is a prerequisite for the next stages. + let resolved_schema = + resolve_semconv_specs(&mut registry, logger.clone()).combine_diag_msgs_with(&diag_msgs)?; + + if let Some(policy_engine) = policy_engine.as_mut() { + // Convert the resolved schemas into a resolved registry. + // If there are any policy violations, they should be captured into the ongoing list of + // diagnostic messages and returned immediately because there is no point in continuing + // as the registry resolution is a prerequisite for the next stages. + let resolved_registry = ResolvedRegistry::try_from_resolved_registry( + resolved_schema + .registry(registry_id) + .expect("Failed to get the registry from the resolved schema"), + resolved_schema.catalog(), + ) + .combine_diag_msgs_with(&diag_msgs)?; + + // Check the policies against the resolved registry (`PolicyState::AfterResolution`). + let errs = check_policy_stage( + policy_engine, + PolicyStage::AfterResolution, + ®istry_path.to_string(), + &resolved_registry, + ); + + // Append the policy errors to the ongoing list of diagnostic messages and if there are + // any errors, return them immediately. + if let Err(err) = handle_errors(errs) { + diag_msgs.extend(err.into()); + } + if !diag_msgs.is_empty() { + return Err(diag_msgs); + } + } Ok(ExitDirectives { exit_code: 0, @@ -77,11 +138,13 @@ mod tests { use crate::cli::{Cli, Commands}; use crate::registry::check::RegistryCheckArgs; - use crate::registry::{RegistryArgs, RegistryCommand, RegistryPath, RegistrySubCommand}; + use crate::registry::{ + semconv_registry, RegistryArgs, RegistryCommand, RegistryPath, RegistrySubCommand, + }; use crate::run_command; #[test] - fn test_registry_check() { + fn test_registry_check_exit_code() { let logger = TestLogger::new(); let cli = Cli { debug: 0, @@ -96,6 +159,7 @@ mod tests { }, policies: vec![], skip_policies: true, + display_policy_coverage: false, diagnostic: Default::default(), }), })), @@ -119,6 +183,7 @@ mod tests { }, policies: vec![], skip_policies: false, + display_policy_coverage: false, diagnostic: Default::default(), }), })), @@ -128,4 +193,37 @@ mod tests { // The command should exit with an error code. assert_eq!(exit_directive.exit_code, 1); } + + #[test] + fn test_semconv_registry() { + let logger = TestLogger::new(); + + let registry_cmd = RegistryCommand { + command: RegistrySubCommand::Check(RegistryCheckArgs { + registry: RegistryArgs { + registry: RegistryPath::Local( + "crates/weaver_codegen_test/semconv_registry/".to_owned(), + ), + registry_git_sub_dir: None, + }, + policies: vec![], + skip_policies: false, + display_policy_coverage: false, + diagnostic: Default::default(), + }), + }; + + let cmd_result = semconv_registry(logger.clone(), ®istry_cmd); + // Violations should be observed. + assert!(cmd_result.command_result.is_err()); + if let Err(diag_msgs) = cmd_result.command_result { + assert!(!diag_msgs.is_empty()); + assert_eq!( + diag_msgs.len(), + 13 /* before resolution */ + + 3 /* metric after resolution */ + + 9 /* http after resolution */ + ); + } + } } diff --git a/src/registry/generate.rs b/src/registry/generate.rs index de371385..0413cac2 100644 --- a/src/registry/generate.rs +++ b/src/registry/generate.rs @@ -18,7 +18,8 @@ use weaver_semconv::registry::SemConvRegistry; use crate::registry::{Error, RegistryArgs}; use crate::util::{ - check_policies, load_semconv_specs, resolve_semconv_specs, semconv_registry_path_from, + check_policies, init_policy_engine, load_semconv_specs, resolve_semconv_specs, + semconv_registry_path_from, }; use crate::{DiagnosticArgs, ExitDirectives}; @@ -101,13 +102,8 @@ pub(crate) fn command( let semconv_specs = load_semconv_specs(®istry_path, cache, logger.clone())?; if !args.skip_policies { - check_policies( - ®istry_path, - cache, - &args.policies, - &semconv_specs, - logger.clone(), - )?; + let policy_engine = init_policy_engine(®istry_path, cache, &args.policies, false)?; + check_policies(&policy_engine, &semconv_specs, logger.clone())?; } let mut registry = SemConvRegistry::from_semconv_specs(registry_id, semconv_specs); diff --git a/src/registry/resolve.rs b/src/registry/resolve.rs index 2713108d..0eef24d3 100644 --- a/src/registry/resolve.rs +++ b/src/registry/resolve.rs @@ -15,7 +15,8 @@ use weaver_semconv::registry::SemConvRegistry; use crate::format::{apply_format, Format}; use crate::registry::RegistryArgs; use crate::util::{ - check_policies, load_semconv_specs, resolve_semconv_specs, semconv_registry_path_from, + check_policies, init_policy_engine, load_semconv_specs, resolve_semconv_specs, + semconv_registry_path_from, }; use crate::{DiagnosticArgs, ExitDirectives}; @@ -79,13 +80,8 @@ pub(crate) fn command( let semconv_specs = load_semconv_specs(®istry_path, cache, logger.clone())?; if !args.skip_policies { - check_policies( - ®istry_path, - cache, - &args.policies, - &semconv_specs, - logger.clone(), - )?; + let policy_engine = init_policy_engine(®istry_path, cache, &args.policies, false)?; + check_policies(&policy_engine, &semconv_specs, logger.clone())?; } let mut registry = SemConvRegistry::from_semconv_specs(registry_id, semconv_specs); diff --git a/src/util.rs b/src/util.rs index df0abca0..8764a1c9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,10 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -//! Set of utility functions to resolve a semantic convention registry and check policies. -//! This module is used by the `schema` and `registry` commands. +//! Utility functions for resolving a semantic convention registry and checking policies. +//! This module supports the `schema` and `registry` commands. use crate::registry::RegistryPath; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use serde::Serialize; use std::path::PathBuf; use weaver_cache::Cache; use weaver_checker::Error::{InvalidPolicyFile, PolicyViolation}; @@ -17,7 +18,12 @@ use weaver_resolver::SchemaResolver; use weaver_semconv::registry::SemConvRegistry; use weaver_semconv::semconv::SemConvSpec; -/// Convert a `RegistryPath` to a `weaver_semconv::path::RegistryPath`. +/// Converts a `RegistryPath` to a `weaver_semconv::path::RegistryPath`. +/// +/// # Arguments +/// +/// * `registry`: A reference to a registry of telemetry schema. This is considered identifying for that registry, e.g a git url or local file path. +/// * `path`: An optional string representing a sub-directory in the registry identifying path where model/yaml files are located. pub(crate) fn semconv_registry_path_from( registry: &RegistryPath, path: &Option, @@ -33,13 +39,18 @@ pub(crate) fn semconv_registry_path_from( } } -/// Load the semantic convention specifications from a registry path. +/// Loads the semantic convention specifications from a registry path. /// /// # Arguments /// /// * `registry_path` - The path to the semantic convention registry. -/// * `cache` - The cache to use for loading the registry. -/// * `log` - The logger to use for logging messages. +/// * `cache` - The cache for loading the registry. +/// * `log` - The logger for logging messages. +/// +/// # Returns +/// +/// A `Result` containing a vector of tuples with file names and `SemConvSpec` on success, +/// or a `weaver_resolver::Error` on failure. pub(crate) fn load_semconv_specs( registry_path: &weaver_semconv::path::RegistryPath, cache: &Cache, @@ -53,12 +64,98 @@ pub(crate) fn load_semconv_specs( Ok(semconv_specs) } -/// Check the policies of a semantic convention registry. +/// Initializes the policy engine with policies from the registry and command line. +/// +/// # Arguments +/// +/// * `registry_path` - The path to the semantic convention registry. +/// * `cache` - The cache for loading the registry. +/// * `policies` - A list of paths to policy files. +/// * `policy_coverage` - A flag to enable policy coverage. +/// +/// # Returns +/// +/// A `Result` containing the initialized `Engine` on success, or `DiagnosticMessages` +/// on failure. +pub(crate) fn init_policy_engine( + registry_path: &weaver_semconv::path::RegistryPath, + cache: &Cache, + policies: &[PathBuf], + policy_coverage: bool, +) -> Result { + let mut engine = Engine::new(); + + if policy_coverage { + engine.enable_coverage(); + } + + // Add policies from the registry + let (registry_path, _) = SchemaResolver::path_to_registry(registry_path, cache)?; + _ = engine.add_policies(registry_path.as_path(), "*.rego")?; + + // Add policies from the command line + for policy in policies { + _ = engine.add_policy(policy)?; + } + + Ok(engine) +} + +/// Runs the policy engine on a serializable input and returns +/// a list of policy violations represented as errors. +/// +/// # Arguments +/// +/// * `policy_engine` - The policy engine. +/// * `policy_stage` - The policy stage to check. +/// * `policy_file` - The policy file to check. +/// * `input` - The input to check. +/// +/// # Returns +/// +/// A list of policy violations represented as errors. +pub(crate) fn check_policy_stage( + policy_engine: &mut Engine, + policy_stage: PolicyStage, + policy_file: &str, + input: &T, +) -> Vec { + let mut errors = vec![]; + + match policy_engine.set_input(input) { + Ok(_) => match policy_engine.check(policy_stage) { + Ok(violations) => { + for violation in violations { + errors.push(PolicyViolation { + provenance: policy_file.to_owned(), + violation, + }); + } + } + Err(e) => errors.push(InvalidPolicyFile { + file: policy_file.to_owned(), + error: e.to_string(), + }), + }, + Err(e) => errors.push(InvalidPolicyFile { + file: policy_file.to_owned(), + error: e.to_string(), + }), + } + errors +} + +/// Checks the policies of a semantic convention registry. /// /// # Arguments /// -/// * `policy_engine` - The pre-configured policy engine to use for checking the policies. +/// * `policy_engine` - The pre-configured policy engine for checking policies. /// * `semconv_specs` - The semantic convention specifications to check. +/// +/// # Returns +/// +/// A `Result` which is `Ok` if all policies are checked successfully, or an `Error` +/// if any policy violations occur. pub(crate) fn check_policy( policy_engine: &Engine, semconv_specs: &[(String, SemConvSpec)], @@ -70,29 +167,12 @@ pub(crate) fn check_policy( // Create a local policy engine inheriting the policies // from the global policy engine let mut policy_engine = policy_engine.clone(); - let mut errors = vec![]; - - match policy_engine.set_input(semconv) { - Ok(_) => match policy_engine.check(PolicyStage::BeforeResolution) { - Ok(violations) => { - for violation in violations { - errors.push(PolicyViolation { - provenance: path.clone(), - violation, - }); - } - } - Err(e) => errors.push(InvalidPolicyFile { - file: path.to_string(), - error: e.to_string(), - }), - }, - Err(e) => errors.push(InvalidPolicyFile { - file: path.to_string(), - error: e.to_string(), - }), - } - errors + check_policy_stage( + &mut policy_engine, + PolicyStage::BeforeResolution, + path, + semconv, + ) }) .collect::>(); @@ -100,33 +180,25 @@ pub(crate) fn check_policy( Ok(()) } -/// Check the policies of a semantic convention registry. +/// Checks the policies of a semantic convention registry. /// /// # Arguments /// -/// * `policies` - The list of policy files to check. +/// * `policy_engine` - The policy engine. /// * `semconv_specs` - The semantic convention specifications to check. -/// * `logger` - The logger to use for logging messages. +/// * `logger` - The logger for logging messages. +/// +/// # Returns +/// +/// A `Result` which is `Ok` if all policies are checked successfully, +/// or `DiagnosticMessages` if any policy violations occur. pub(crate) fn check_policies( - registry_path: &weaver_semconv::path::RegistryPath, - cache: &Cache, - policies: &[PathBuf], + policy_engine: &Engine, semconv_specs: &[(String, SemConvSpec)], logger: impl Logger + Sync + Clone, ) -> Result<(), DiagnosticMessages> { - let mut engine = Engine::new(); - - // Add policies from the registry - let (registry_path, _) = SchemaResolver::path_to_registry(registry_path, cache)?; - let added_policies_count = engine.add_policies(registry_path.as_path(), "*.rego")?; - - // Add policies from the command line - for policy in policies { - engine.add_policy(policy)?; - } - - if added_policies_count + policies.len() > 0 { - check_policy(&engine, semconv_specs).map_err(|e| { + if policy_engine.policy_package_count() > 0 { + check_policy(policy_engine, semconv_specs).map_err(|e| { if let Error::CompoundError(errors) = e { DiagnosticMessages::from_errors(errors) } else { @@ -140,13 +212,17 @@ pub(crate) fn check_policies( Ok(()) } -/// Resolve the semantic convention specifications and return the resolved schema. +/// Resolves the semantic convention specifications and returns the resolved schema. /// /// # Arguments /// -/// * `registry_id` - The ID of the semantic convention registry. -/// * `semconv_specs` - The semantic convention specifications to resolve. -/// * `logger` - The logger to use for logging messages. +/// * `registry` - The semantic convention registry to resolve. +/// * `logger` - The logger for logging messages. +/// +/// # Returns +/// +/// A `Result` containing the `ResolvedTelemetrySchema` on success, or +/// `DiagnosticMessages` on failure. pub(crate) fn resolve_semconv_specs( registry: &mut SemConvRegistry, logger: impl Logger + Sync + Clone, diff --git a/tests/registry_check.rs b/tests/registry_check.rs index a9d9f346..fa95c6a9 100644 --- a/tests/registry_check.rs +++ b/tests/registry_check.rs @@ -43,6 +43,9 @@ fn test_cli_interface() { // We should be able to parse the JSON output from stdout. let stdout = String::from_utf8(output.stdout).expect("Invalid UTF-8"); let json_value: Vec = serde_json::from_str(&stdout).expect("Invalid JSON"); - // We expect 13 policy violations. - assert_eq!(json_value.len(), 13); + // We expect 25 policy violations. + // - 13 violations before resolution + // - 3 violations for metrics after resolution + // - 9 violations for http after resolution + assert_eq!(json_value.len(), 25); }