diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index 4090692f..62b7ccdd 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -1,24 +1,30 @@ +name: Semgrep OSS scan on: pull_request: {} + push: + branches: [main, master] workflow_dispatch: {} - push: - branches: - - main - - master schedule: - - cron: '0 0 * * *' -name: Semgrep config + - cron: '0 0 20 * *' +concurrency: + group: semgrep-${{ github.event_name }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +permissions: + contents: read jobs: semgrep: - name: semgrep/ci - runs-on: ubuntu-latest - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} - SEMGREP_URL: https://cloudflare.semgrep.dev - SEMGREP_APP_URL: https://cloudflare.semgrep.dev - SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version - container: - image: semgrep/semgrep + name: semgrep-oss + runs-on: ubuntu-slim steps: - - uses: actions/checkout@v4 - - run: semgrep ci + - uses: actions/checkout@v5 + with: + fetch-depth: 1 + - id: cache-semgrep + uses: actions/cache@v5 + with: + path: ~/.local + key: semgrep-1.160.0-${{ runner.os }} + - if: steps.cache-semgrep.outputs.cache-hit != 'true' + run: pip install --user semgrep==1.160.0 + - run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" + - run: semgrep scan --config=auto diff --git a/Cargo.lock b/Cargo.lock index e0190b3a..89b4260e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "1.0.0" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -70,15 +70,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.14" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "1.0.0" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "autocfg" @@ -138,15 +138,15 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "5c6f81257d10a0f602a294ae4182251151ff97dbb504ef9afcdda4a64b24d9b4" [[package]] name = "cast" @@ -175,9 +175,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.60" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -227,18 +227,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.5.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "c5caf74d17c3aec5495110c34cc3f78644bfa89af6c8993ed4de2790e49b6499" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.5.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "370daa45065b80218950227371916a1633217ae42b2715b2287b606dcd618e24" dependencies = [ "anstream", "anstyle", @@ -248,15 +248,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "colorchoice" -version = "1.0.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "criterion" @@ -344,9 +344,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.10" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" dependencies = [ "serde", "serde_core", @@ -365,9 +365,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.4.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" @@ -420,20 +420,20 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi 5.3.0", + "r-efi", "wasip2", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" dependencies = [ "cfg-if", "libc", - "r-efi 6.0.0", + "r-efi", "wasip2", "wasip3", ] @@ -466,9 +466,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -493,12 +493,12 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "indexmap" -version = "2.14.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.16.1", "serde", "serde_core", ] @@ -529,15 +529,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.95" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -551,15 +551,15 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.185" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "linux-raw-sys" -version = "0.12.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" @@ -593,9 +593,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -603,9 +603,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -624,9 +624,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.4" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" @@ -705,9 +705,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.5.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ "toml_edit", ] @@ -723,9 +723,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -736,12 +736,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - [[package]] name = "rand" version = "0.9.4" @@ -773,9 +767,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -816,9 +810,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "rustc-demangle" @@ -837,9 +831,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags", "errno", @@ -865,9 +859,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.28" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "seq-macro" @@ -931,9 +925,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.1.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ "serde_core", ] @@ -970,9 +964,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.117" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -981,12 +975,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.27.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.1", "once_cell", "rustix", "windows-sys", @@ -1031,10 +1025,10 @@ dependencies = [ "indexmap", "serde_core", "serde_spanned", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", - "winnow 0.7.15", + "winnow", ] [[package]] @@ -1046,41 +1040,32 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", - "toml_datetime 1.1.1+spec-1.1.0", + "toml_datetime", "toml_parser", - "winnow 1.0.1", + "winnow", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ - "winnow 1.0.1", + "winnow", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "typeid" @@ -1142,9 +1127,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.118" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -1157,9 +1142,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.118" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1167,9 +1152,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.118" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ "bumpalo", "proc-macro2", @@ -1180,9 +1165,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.118" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] @@ -1223,9 +1208,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.95" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -1288,15 +1273,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" - -[[package]] -name = "winnow" -version = "1.0.1" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -1459,18 +1438,18 @@ checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 1aa27938..a6183265 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -255,7 +255,8 @@ impl<'i, 's> LexWith<'i, &FilterParser<'s>> for IdentifierExpr { match item { Identifier::Field(field) => Ok((IdentifierExpr::Field(field.to_owned()), input)), Identifier::Function(function) => { - FunctionCallExpr::lex_with_function(input, parser, function) + let nested_parser = parser.with_increased_nesting(skip_space(input))?; + FunctionCallExpr::lex_with_function(input, &nested_parser, function) .map(|(call, input)| (IdentifierExpr::FunctionCallExpr(call), input)) } } @@ -798,9 +799,9 @@ mod tests { use crate::ast::logical_expr::LogicalExpr; use crate::execution_context::ExecutionContext; use crate::functions::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, SimpleFunctionDefinition, SimpleFunctionImpl, - SimpleFunctionOptParam, SimpleFunctionParam, + AllFunction, CompiledFunction, FunctionArgKind, FunctionArgs, FunctionDefinition, + FunctionDefinitionContext, FunctionParam, FunctionParamError, SimpleFunctionDefinition, + SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, }; use crate::lhs_types::{Array, Map}; use crate::list_matcher::{ListDefinition, ListMatcher}; @@ -906,12 +907,7 @@ mod tests { &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box< - dyn for<'i, 'a> Fn(FunctionArgs<'i, 'a>) -> Option> - + Sync - + Send - + 'static, - > { + ) -> CompiledFunction { Box::new(|args| { let value_array = Array::try_from(args.next().unwrap().unwrap()).unwrap(); let keep_array = Array::try_from(args.next().unwrap().unwrap()).unwrap(); @@ -970,6 +966,8 @@ mod tests { tcp.port: Int, tcp.ports: Array(Int), array.of.bool: Array(Bool), + map.bool.arr: Map(Array(Bool)), + map.bytes.arr: Map(Array(Bytes)), http.parts: Array(Array(Bytes)), }; builder @@ -986,6 +984,7 @@ mod tests { }, ) .unwrap(); + builder.add_function("all", AllFunction::default()).unwrap(); builder .add_function( "echo", @@ -2636,6 +2635,34 @@ mod tests { assert_eq!(expr.execute_one(ctx), false); } + #[test] + fn test_any_all_functions_with_missing_arrays() { + let ctx = &mut ExecutionContext::new(&SCHEME); + ctx.set_field_value( + field("map.bool.arr"), + Map::new(Type::Array(Type::Bool.into())), + ) + .unwrap(); + ctx.set_field_value( + field("map.bytes.arr"), + Map::new(Type::Array(Type::Bytes.into())), + ) + .unwrap(); + + let execute = |input| SCHEME.parse(input).unwrap().compile().execute(ctx).unwrap(); + + assert_eq!(execute(r#"any(map.bool.arr["missing"])"#), false); + assert_eq!(execute(r#"all(map.bool.arr["missing"])"#), false); + assert_eq!( + execute(r#"any(map.bytes.arr["missing"][*] matches "bar")"#), + false + ); + assert_eq!( + execute(r#"all(map.bytes.arr["missing"][*] matches "bar")"#), + true + ); + } + #[test] fn test_map_each_nested() { let expr = assert_ok!( diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index c9808941..c0656c91 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -8,7 +8,7 @@ use crate::ast::logical_expr::{LogicalExpr, UnaryOp}; use crate::compiler::Compiler; use crate::filter::{CompiledExpr, CompiledValueExpr, CompiledValueResult}; use crate::functions::{ - ExactSizeChain, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, + CompiledFunction, ExactSizeChain, FunctionDefinition, FunctionDefinitionContext, FunctionParam, FunctionParamError, }; use crate::lex::{Lex, LexError, LexErrorKind, LexResult, LexWith, expect, skip_space, span}; @@ -272,11 +272,9 @@ impl ValueExpr for FunctionCallExpr { let first = args.remove(0); #[inline(always)] - fn compute<'s, 'a, I: ExactSizeIterator>>( + fn compute<'a, I: ExactSizeIterator>>( first: CompiledValueResult<'a>, - call: &( - dyn for<'b> Fn(FunctionArgs<'_, 'b>) -> Option> + Sync + Send + 's - ), + call: &CompiledFunction, return_type: Type, f: impl Fn(LhsValue<'a>) -> I, ) -> CompiledValueResult<'a> { @@ -512,8 +510,9 @@ impl GetType for FunctionCallExpr { impl<'i> LexWith<'i, &FilterParser<'_>> for FunctionCallExpr { fn lex_with(input: &'i str, parser: &FilterParser<'_>) -> LexResult<'i, Self> { let (function, rest) = FunctionRef::lex_with(input, parser.scheme)?; + let nested_parser = parser.with_increased_nesting(skip_space(rest))?; - Self::lex_with_function(rest, parser, function) + Self::lex_with_function(rest, &nested_parser, function) } } @@ -566,6 +565,44 @@ mod tests { args.next()?.ok() } + #[test] + fn test_function_call_nesting_limit() { + let mut parser = FilterParser::new(&SCHEME); + parser.set_max_nesting_depth(2); + + assert_err!( + parser.lex_as::("echo ( echo ( echo ( http.host ) ) )"), + LexErrorKind::NestingLimitExceeded { limit: 2 }, + "( http.host ) ) )" + ); + } + + #[test] + fn test_value_expr_function_call_nesting_limit() { + let mut parser = FilterParser::new(&SCHEME); + parser.set_max_nesting_depth(2); + + assert_err!( + parser.lex_as::("echo ( echo ( echo ( http.host ) ) )"), + LexErrorKind::NestingLimitExceeded { limit: 2 }, + "( http.host ) ) )" + ); + } + + #[test] + fn test_logical_argument_nesting_limit_is_counted_via_function_and_parentheses() { + let mut parser = FilterParser::new(&SCHEME); + parser.set_max_nesting_depth(1); + + assert_err!( + parser.lex_as::( + "any ( ( http.request.headers.is_empty or http.request.headers.is_empty ) )" + ), + LexErrorKind::NestingLimitExceeded { limit: 1 }, + "( http.request.headers.is_empty or http.request.headers.is_empty ) )" + ); + } + fn len_function<'a>(args: FunctionArgs<'_, 'a>) -> Option> { match args.next()? { Ok(LhsValue::Bytes(bytes)) => Some(LhsValue::Int(i64::try_from(bytes.len()).unwrap())), diff --git a/engine/src/ast/logical_expr.rs b/engine/src/ast/logical_expr.rs index 4f1790a0..bb3e60a8 100644 --- a/engine/src/ast/logical_expr.rs +++ b/engine/src/ast/logical_expr.rs @@ -82,18 +82,20 @@ impl LogicalExpr { } fn lex_simple_expr<'i>(input: &'i str, parser: &FilterParser<'_>) -> LexResult<'i, Self> { - Ok(if let Ok(input) = expect(input, "(") { - let input = skip_space(input); - let (expr, input) = LogicalExpr::lex_with(input, parser)?; + Ok(if let Ok(rest) = expect(input, "(") { + let nested_parser = parser.with_increased_nesting(input)?; + let input = skip_space(rest); + let (expr, input) = LogicalExpr::lex_with(input, &nested_parser)?; let input = skip_space(input); let input = expect(input, ")")?; ( LogicalExpr::Parenthesized(Box::new(ParenthesizedExpr { expr })), input, ) - } else if let Ok((op, input)) = UnaryOp::lex(input) { - let input = skip_space(input); - let (arg, input) = Self::lex_simple_expr(input, parser)?; + } else if let Ok((op, rest)) = UnaryOp::lex(input) { + let nested_parser = parser.with_increased_nesting(input)?; + let input = skip_space(rest); + let (arg, input) = Self::lex_simple_expr(input, &nested_parser)?; ( LogicalExpr::Unary { op, @@ -550,6 +552,46 @@ fn test() { } ); + assert_ok!( + FilterParser::new(scheme).lex_as("t and (t or t)"), + LogicalExpr::Combining { + op: LogicalOp::And, + items: vec![ + t_expr(), + LogicalExpr::Parenthesized(Box::new(ParenthesizedExpr { + expr: LogicalExpr::Combining { + op: LogicalOp::Or, + items: vec![t_expr(), t_expr()], + }, + })), + ], + } + ); + + assert_ok!( + FilterParser::new(scheme).lex_as("t and (t or (t and t))"), + LogicalExpr::Combining { + op: LogicalOp::And, + items: vec![ + t_expr(), + LogicalExpr::Parenthesized(Box::new(ParenthesizedExpr { + expr: LogicalExpr::Combining { + op: LogicalOp::Or, + items: vec![ + t_expr(), + LogicalExpr::Parenthesized(Box::new(ParenthesizedExpr { + expr: LogicalExpr::Combining { + op: LogicalOp::And, + items: vec![t_expr(), t_expr()], + }, + })), + ], + }, + })), + ], + } + ); + { let expr = assert_ok!( FilterParser::new(scheme).lex_as("at and af"), @@ -879,6 +921,42 @@ fn test() { not_expr(parenthesized_expr(not_expr(not_expr(at_expr())))) ); + { + let mut parser = FilterParser::new(scheme); + parser.set_max_nesting_depth(1); + assert_err!( + parser.lex_as::("((t))"), + LexErrorKind::NestingLimitExceeded { limit: 1 }, + "(t))" + ); + } + + { + let mut parser = FilterParser::new(scheme); + parser.set_max_nesting_depth(1); + assert_err!( + parser.lex_as::("!!t"), + LexErrorKind::NestingLimitExceeded { limit: 1 }, + "!t" + ); + } + + { + let mut parser = FilterParser::new(scheme); + parser.set_max_nesting_depth(2); + assert_ok!(parser.lex_as("!!t"), not_expr(not_expr(t_expr()))); + } + + { + let mut parser = FilterParser::new(scheme); + parser.set_max_nesting_depth(0); + assert_err!( + parser.lex_as::("t and (t or t)"), + LexErrorKind::NestingLimitExceeded { limit: 0 }, + "(t or t)" + ); + } + { let expr = assert_ok!( FilterParser::new(scheme).lex_as("not t && f"), diff --git a/engine/src/ast/parse.rs b/engine/src/ast/parse.rs index 562703d5..a9b79ffc 100644 --- a/engine/src/ast/parse.rs +++ b/engine/src/ast/parse.rs @@ -106,6 +106,9 @@ pub struct ParserSettings { /// Maximum number of star metacharacters allowed in a wildcard. /// Default: unlimited pub wildcard_star_limit: usize, + /// Maximum nesting depth allowed while parsing. + /// Default: 128 + pub max_nesting_depth: u16, } impl Default for ParserSettings { @@ -117,6 +120,7 @@ impl Default for ParserSettings { // Default value extracted from the regex crate. regex_dfa_size_limit: 2 * (1 << 20), wildcard_star_limit: usize::MAX, + max_nesting_depth: 128, } } } @@ -126,6 +130,7 @@ impl Default for ParserSettings { pub struct FilterParser<'s> { pub(crate) scheme: &'s Scheme, pub(crate) settings: ParserSettings, + current_nesting_depth: u16, } impl<'s> FilterParser<'s> { @@ -135,13 +140,18 @@ impl<'s> FilterParser<'s> { Self { scheme, settings: ParserSettings::default(), + current_nesting_depth: 0, } } /// Creates a new parser with the specified settings. #[inline] pub fn with_settings(scheme: &'s Scheme, settings: ParserSettings) -> Self { - Self { scheme, settings } + Self { + scheme, + settings, + current_nesting_depth: 0, + } } /// Returns the [`Scheme`](struct@Scheme) for which this parser has been constructor for. @@ -158,6 +168,25 @@ impl<'s> FilterParser<'s> { L::lex_with(input, self) } + #[inline] + pub(crate) fn with_increased_nesting<'i>( + &self, + span: &'i str, + ) -> Result { + if self.current_nesting_depth >= self.settings.max_nesting_depth { + Err(( + LexErrorKind::NestingLimitExceeded { + limit: self.settings.max_nesting_depth, + }, + span, + )) + } else { + let mut nested = self.clone(); + nested.current_nesting_depth += 1; + Ok(nested) + } + } + /// Parses a filter expression into an AST form. pub fn parse<'i>(&self, input: &'i str) -> Result> { complete(self.lex_as(input.trim())).map_err(|err| ParseError::new(input, err)) @@ -209,4 +238,16 @@ impl<'s> FilterParser<'s> { pub fn wildcard_get_star_limit(&self) -> usize { self.settings.wildcard_star_limit } + + /// Set the maximum nesting depth allowed while parsing. + #[inline] + pub fn set_max_nesting_depth(&mut self, max_nesting_depth: u16) { + self.settings.max_nesting_depth = max_nesting_depth; + } + + /// Get the maximum nesting depth allowed while parsing. + #[inline] + pub fn max_nesting_depth(&self) -> u16 { + self.settings.max_nesting_depth + } } diff --git a/engine/src/functions/all.rs b/engine/src/functions/all.rs index b78cb8e8..152aed41 100644 --- a/engine/src/functions/all.rs +++ b/engine/src/functions/all.rs @@ -1,10 +1,9 @@ use crate::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, - FunctionParamError, GetType, LhsValue, ParserSettings, Type, + CompiledFunction, FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, }; use std::iter::once; -#[inline] fn all_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { let arg = args.next().expect("expected 1 argument, got 0"); if args.next().is_some() { @@ -58,12 +57,11 @@ impl FunctionDefinition for AllFunction { (1, Some(0)) } - fn compile<'s>( - &'s self, + fn compile( + &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { + ) -> CompiledFunction { Box::new(all_impl) } } diff --git a/engine/src/functions/any.rs b/engine/src/functions/any.rs index a9f90b76..66199d33 100644 --- a/engine/src/functions/any.rs +++ b/engine/src/functions/any.rs @@ -1,10 +1,9 @@ use crate::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, - FunctionParamError, GetType, LhsValue, ParserSettings, Type, + CompiledFunction, FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, }; use std::iter::once; -#[inline] fn any_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { let arg = args.next().expect("expected 1 argument, got 0"); if args.next().is_some() { @@ -58,12 +57,11 @@ impl FunctionDefinition for AnyFunction { (1, Some(0)) } - fn compile<'s>( - &'s self, + fn compile( + &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { + ) -> CompiledFunction { Box::new(any_impl) } } diff --git a/engine/src/functions/concat.rs b/engine/src/functions/concat.rs index 1d493d93..681b099e 100644 --- a/engine/src/functions/concat.rs +++ b/engine/src/functions/concat.rs @@ -1,6 +1,7 @@ use crate::{ - Array, Bytes, ExpectedType, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, + Array, Bytes, CompiledFunction, ExpectedType, FunctionArgs, FunctionDefinition, + FunctionDefinitionContext, FunctionParam, FunctionParamError, GetType, LhsValue, + ParserSettings, Type, }; use std::iter::once; @@ -19,6 +20,7 @@ impl ConcatFunction { } } +#[inline] fn concat_array<'a>(accumulator: Array<'a>, args: FunctionArgs<'_, 'a>) -> Array<'a> { let mut args = args.flat_map(|arg| arg.ok()); let Some(first) = args.next() else { @@ -43,6 +45,7 @@ fn concat_array<'a>(accumulator: Array<'a>, args: FunctionArgs<'_, 'a>) -> Array Array::try_from_vec(val_type, vec).unwrap() } +#[inline] fn concat_bytes<'a>(mut accumulator: Vec, args: FunctionArgs<'_, 'a>) -> Bytes<'a> { for arg in args { match arg { @@ -54,6 +57,25 @@ fn concat_bytes<'a>(mut accumulator: Vec, args: FunctionArgs<'_, 'a>) -> Byt accumulator.into() } +fn concat_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { + while let Some(arg) = args.next() { + match arg { + Ok(LhsValue::Array(array)) => { + return Some(LhsValue::Array(concat_array(array, args))); + } + Ok(LhsValue::Bytes(bytes)) => { + return Some(LhsValue::Bytes(concat_bytes( + bytes.into_owned().into(), + args, + ))); + } + Err(_) => (), + _ => unreachable!(), + } + } + None +} + pub(crate) const EXPECTED_TYPES: [ExpectedType; 2] = [ExpectedType::Array, ExpectedType::Type(Type::Bytes)]; @@ -90,30 +112,12 @@ impl FunctionDefinition for ConcatFunction { (2, None) } - fn compile<'s>( - &'s self, + fn compile( + &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { - Box::new(|args| { - while let Some(arg) = args.next() { - match arg { - Ok(LhsValue::Array(array)) => { - return Some(LhsValue::Array(concat_array(array, args))); - } - Ok(LhsValue::Bytes(bytes)) => { - return Some(LhsValue::Bytes(concat_bytes( - bytes.into_owned().into(), - args, - ))); - } - Err(_) => (), - _ => unreachable!(), - } - } - None - }) + ) -> CompiledFunction { + Box::new(concat_impl) } } @@ -133,7 +137,7 @@ mod tests { .into_iter(); assert_eq!( Some(LhsValue::Bytes(Bytes::Borrowed(b"helloworld"))), - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) + concat_impl(&mut args) ); } @@ -148,7 +152,7 @@ mod tests { .into_iter(); assert_eq!( Some(LhsValue::Bytes(Bytes::Borrowed(b"helloworldhello2world2"))), - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) + concat_impl(&mut args) ); } @@ -159,7 +163,7 @@ mod tests { let mut args = vec![Ok(arg1), Ok(arg2)].into_iter(); assert_eq!( Some(LhsValue::Array(Array::from_iter([1, 2, 3, 4, 5, 6]))), - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) + concat_impl(&mut args) ); } @@ -167,7 +171,7 @@ mod tests { #[should_panic] fn test_concat_function_bad_arg_type() { let mut args = vec![Ok(LhsValue::from(2))].into_iter(); - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args); + concat_impl(&mut args); } #[test] diff --git a/engine/src/functions/mod.rs b/engine/src/functions/mod.rs index a1ef9736..c23e5a0f 100644 --- a/engine/src/functions/mod.rs +++ b/engine/src/functions/mod.rs @@ -396,6 +396,13 @@ impl std::fmt::Debug for FunctionDefinitionContext { } } +/// A compiled function that can be called during filter execution. +/// +/// Returned by [`FunctionDefinition::compile`] after a function call expression +/// has been validated and compiled. +pub type CompiledFunction = + Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static>; + /// Trait to implement function pub trait FunctionDefinition: Debug + Send + Sync { /// Custom context to store information during parsing @@ -427,7 +434,7 @@ pub trait FunctionDefinition: Debug + Send + Sync { &self, params: &mut dyn ExactSizeIterator>, ctx: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static>; + ) -> CompiledFunction; } // Simple function APIs @@ -553,8 +560,7 @@ impl FunctionDefinition for SimpleFunctionDefinition { &self, params: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { + ) -> CompiledFunction { let params_count = params.len(); let opt_params = &self.opt_params[(params_count - self.params.len())..]; let implementation = self.implementation; diff --git a/engine/src/lex.rs b/engine/src/lex.rs index 4fcc5633..d6cdcf0d 100644 --- a/engine/src/lex.rs +++ b/engine/src/lex.rs @@ -150,6 +150,13 @@ pub enum LexErrorKind { /// Name of the list name: String, }, + + /// Maximum nesting depth exceeded while parsing. + #[error("maximum nesting depth exceeded (limit: {limit})")] + NestingLimitExceeded { + /// The configured maximum nesting depth. + limit: u16, + }, } pub type LexError<'i> = (LexErrorKind, &'i str); diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 5595bb3f..cf149bb4 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -96,13 +96,13 @@ pub use self::filter::{ CompiledExpr, CompiledOneExpr, CompiledValueExpr, CompiledVecExpr, Filter, FilterValue, }; pub use self::functions::{ - AllFunction, AnyFunction, CIDRFunction, ConcatFunction, DecodeBase64Function, EndsWithFunction, - FunctionArgInvalidConstantError, FunctionArgKind, FunctionArgKindMismatchError, FunctionArgs, - FunctionDefinition, FunctionDefinitionContext, FunctionParam, FunctionParamError, LenFunction, - LowerFunction, RegexReplaceFunction, RemoveBytesFunction, SimpleFunctionArgKind, - SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, - StartsWithFunction, SubstringFunction, UUID4Function, UrlDecodeFunction, - WildcardReplaceFunction, + AllFunction, AnyFunction, CIDRFunction, CompiledFunction, ConcatFunction, DecodeBase64Function, + EndsWithFunction, FunctionArgInvalidConstantError, FunctionArgKind, + FunctionArgKindMismatchError, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + FunctionParam, FunctionParamError, LenFunction, LowerFunction, RegexReplaceFunction, + RemoveBytesFunction, SimpleFunctionArgKind, SimpleFunctionDefinition, SimpleFunctionImpl, + SimpleFunctionOptParam, SimpleFunctionParam, StartsWithFunction, SubstringFunction, + UUID4Function, UrlDecodeFunction, WildcardReplaceFunction, }; pub use self::lex::LexErrorKind; pub use self::lhs_types::{Array, Bytes, Map, MapIter, TypedArray, TypedMap};