diff --git a/LICENSE.md b/LICENSE.md index e05ee8721cf..0a1e0ee9d27 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,23 +1,18 @@ -Copyright (C) 2024 Quickwit, Inc. +Copyright (C) 2024-Present Quickwit, Inc. -Quickwit is offered under the [GNU Affero General Public License v3.0](https://opensource.org/licenses/AGPL-3.0) -and as commercial software. -A copy of the AGPL license can be found in [LICENSE_AGPLv3.0.txt](LICENSE_AGPLv3.0.txt) +Source code in this directory are licensed either under +- Both the AGPL and the Quickwit Enterprise License. +- the Quickwit Enterprise License -# Commercial Licensing -For commercial licensing, contact us at hello@quickwit.io. +Source files that are license under both the AGPL and the Quickwit enterprise +are prefixed explicitly with the AGPL license header. +Source files that are strictly licensed under the Quickwit Enterprise License +are prefixed by the Quickwit Enterprise License header. -# AGPL -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. +A copy of the AGPL license can be found in [LICENSE_AGPLv3.0.txt](LICENSE_AGPLv3.0.txt) +A copy of the Quickwit Enterprise license can be found in [LICENSE_QUICKWIT_ENTERPRISE.txt](LICENSE_QUICKWIT_ENTERPRISE.txt) -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. +# To purchase a Quickwit Enterprise License -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . +To purchase Quickwit Enteprise License, contact us at hello@quickwit.io. diff --git a/LICENSE_QUICKWIT_ENTERPRISE.txt b/LICENSE_QUICKWIT_ENTERPRISE.txt new file mode 100644 index 00000000000..4ccf95a362b --- /dev/null +++ b/LICENSE_QUICKWIT_ENTERPRISE.txt @@ -0,0 +1,21 @@ +The Quickwit Enterprise Edition (EE) license +Copyright (c) 2024-present Quickwit Inc. + +With regard to the Quickwit Software: + +This software and associated documentation files (the "Software") may only be +used in production, if you (and any entity that you represent) hold a valid +Quickwit Enterprise license corresponding to your usage. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +For all third party components incorporated into the Quickwit Software, those +components are licensed under the original license provided by the owner of the +applicable component. + diff --git a/quickwit/Cargo.lock b/quickwit/Cargo.lock index d39e91442fd..a0fd3ee03c1 100644 --- a/quickwit/Cargo.lock +++ b/quickwit/Cargo.lock @@ -463,7 +463,7 @@ dependencies = [ "once_cell", "percent-encoding", "regex-lite", - "sha2", + "sha2 0.10.8", "tracing", "url", ] @@ -579,7 +579,7 @@ dependencies = [ "p256", "percent-encoding", "ring 0.17.8", - "sha2", + "sha2 0.10.8", "subtle", "time", "tracing", @@ -614,7 +614,7 @@ dependencies = [ "md-5", "pin-project-lite", "sha1", - "sha2", + "sha2 0.10.8", "tracing", ] @@ -911,7 +911,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sha2", + "sha2 0.10.8", "time", "url", "uuid", @@ -1042,6 +1042,57 @@ dependencies = [ "yansi", ] +[[package]] +name = "biscuit-auth" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95490f2c91dc452247d00a2fb4779bcedb7693e669354fa1fe2a96679f4950cc" +dependencies = [ + "base64 0.13.1", + "biscuit-parser", + "biscuit-quote", + "ed25519-dalek", + "getrandom 0.1.16", + "hex", + "nom", + "prost 0.10.4", + "prost-types 0.10.1", + "rand 0.8.5", + "rand_core 0.6.4", + "regex", + "sha2 0.9.9", + "thiserror", + "time", + "zeroize", +] + +[[package]] +name = "biscuit-parser" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9fd6da963e73f7e6db729c3bd76784863ba405b15acbbb5cb08ebc2adbd3bf" +dependencies = [ + "hex", + "nom", + "proc-macro2", + "quote", + "thiserror", + "time", +] + +[[package]] +name = "biscuit-quote" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0071fe3634b644a8df1434e3e14841e480c4238059c66a94e479b7eff98c2bd3" +dependencies = [ + "biscuit-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -1093,6 +1144,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1589,8 +1649,8 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2895653b4d9f1538a83970077cb01dfc77a4810524e51a110944688e916b18e" dependencies = [ - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "tonic", "tracing-core", ] @@ -1607,7 +1667,7 @@ dependencies = [ "futures", "hdrhistogram", "humantime", - "prost-types", + "prost-types 0.11.9", "serde", "serde_json", "thread_local", @@ -1880,6 +1940,33 @@ dependencies = [ "cipher", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "darling" version = "0.13.4" @@ -2064,13 +2151,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -2169,6 +2265,31 @@ dependencies = [ "signature 1.6.4", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.13.0" @@ -2199,7 +2320,7 @@ dependencies = [ "base16ct", "crypto-bigint 0.4.9", "der 0.6.1", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", @@ -2439,6 +2560,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "filetime" version = "0.2.25" @@ -2786,8 +2913,8 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a3b24a3f57be08afc02344e693afb55e48172c9c2ab86ff3fdb8efff550e4b9" dependencies = [ - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "tonic", ] @@ -2814,7 +2941,7 @@ dependencies = [ "google-cloud-gax", "google-cloud-googleapis", "google-cloud-token", - "prost-types", + "prost-types 0.11.9", "thiserror", "tokio", "tokio-util", @@ -2998,7 +3125,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -4065,7 +4192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -4495,7 +4622,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", - "sha2", + "sha2 0.10.8", "thiserror", "url", ] @@ -4711,7 +4838,7 @@ dependencies = [ "opentelemetry-semantic-conventions", "opentelemetry_api", "opentelemetry_sdk", - "prost", + "prost 0.11.9", "reqwest", "thiserror", "tokio", @@ -4726,7 +4853,7 @@ checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" dependencies = [ "opentelemetry_api", "opentelemetry_sdk", - "prost", + "prost 0.11.9", "tonic", ] @@ -4868,7 +4995,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ "ecdsa", "elliptic-curve", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -4945,10 +5072,10 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest", + "digest 0.10.7", "hmac", "password-hash", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -4957,7 +5084,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest", + "digest 0.10.7", "hmac", ] @@ -5068,7 +5195,7 @@ checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -5182,7 +5309,7 @@ dependencies = [ "der 0.7.9", "pbkdf2 0.12.2", "scrypt", - "sha2", + "sha2 0.10.8", "spki 0.7.3", ] @@ -5603,6 +5730,16 @@ dependencies = [ "unarray", ] +[[package]] +name = "prost" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" +dependencies = [ + "bytes", + "prost-derive 0.10.1", +] + [[package]] name = "prost" version = "0.11.9" @@ -5610,7 +5747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.11.9", ] [[package]] @@ -5627,14 +5764,27 @@ dependencies = [ "multimap", "petgraph", "prettyplease 0.1.25", - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "regex", "syn 1.0.109", "tempfile", "which", ] +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "prost-derive" version = "0.11.9" @@ -5648,13 +5798,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost 0.10.4", +] + [[package]] name = "prost-types" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "prost", + "prost 0.11.9", ] [[package]] @@ -5706,9 +5866,9 @@ dependencies = [ "oauth2", "openidconnect", "pem 1.1.1", - "prost", + "prost 0.11.9", "prost-build", - "prost-derive", + "prost-derive 0.11.9", "rand 0.8.5", "regex", "serde", @@ -5911,7 +6071,7 @@ dependencies = [ "futures", "http 0.2.12", "mockall", - "prost", + "prost 0.11.9", "quickwit-actors", "quickwit-codegen", "quickwit-common", @@ -5983,6 +6143,7 @@ dependencies = [ "once_cell", "quickwit-common", "quickwit-doc-mapper", + "quickwit-license", "quickwit-proto", "regex", "serde", @@ -6140,7 +6301,7 @@ dependencies = [ "oneshot", "openssl", "proptest", - "prost", + "prost 0.11.9", "pulsar", "quickwit-actors", "quickwit-aws", @@ -6188,7 +6349,7 @@ dependencies = [ "mockall", "mrecordlog", "once_cell", - "prost", + "prost 0.11.9", "quickwit-actors", "quickwit-cluster", "quickwit-codegen", @@ -6247,8 +6408,8 @@ dependencies = [ "async-trait", "itertools 0.13.0", "once_cell", - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "quickwit-actors", "quickwit-cluster", "quickwit-common", @@ -6349,6 +6510,16 @@ dependencies = [ "warp", ] +[[package]] +name = "quickwit-license" +version = "0.8.0" +dependencies = [ + "anyhow", + "biscuit-auth", + "thiserror", + "tracing", +] + [[package]] name = "quickwit-macros" version = "0.8.0" @@ -6410,7 +6581,7 @@ dependencies = [ "async-trait", "hex", "once_cell", - "prost", + "prost 0.11.9", "quickwit-common", "quickwit-config", "quickwit-ingest", @@ -6439,9 +6610,9 @@ dependencies = [ "http 0.2.12", "mockall", "opentelemetry", - "prost", + "prost 0.11.9", "prost-build", - "prost-types", + "prost-types 0.11.9", "quickwit-actors", "quickwit-codegen", "quickwit-common", @@ -6526,7 +6697,7 @@ dependencies = [ "once_cell", "postcard", "proptest", - "prost", + "prost 0.11.9", "quickwit-common", "quickwit-config", "quickwit-directories", @@ -6578,8 +6749,8 @@ dependencies = [ "opentelemetry", "percent-encoding", "pprof", - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "quickwit-actors", "quickwit-cluster", "quickwit-common", @@ -6954,7 +7125,7 @@ dependencies = [ "serde", "serde_json", "sha1", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -7114,14 +7285,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", - "digest", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8 0.10.2", "rand_core 0.6.4", - "sha2", + "sha2 0.10.8", "signature 2.2.0", "spki 0.7.3", "subtle", @@ -7158,7 +7329,7 @@ version = "7.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74" dependencies = [ - "sha2", + "sha2 0.10.8", "walkdir", ] @@ -7379,7 +7550,7 @@ checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ "pbkdf2 0.12.2", "salsa20", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -7713,7 +7884,7 @@ checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -7724,7 +7895,20 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", ] [[package]] @@ -7735,7 +7919,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -7744,7 +7928,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest", + "digest 0.10.7", "keccak", ] @@ -7794,7 +7978,7 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -7804,7 +7988,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -7983,7 +8167,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "smallvec", "sqlformat", "thiserror", @@ -8023,7 +8207,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -8046,7 +8230,7 @@ dependencies = [ "byteorder", "bytes", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -8067,7 +8251,7 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.8", "smallvec", "sqlx-core", "stringprep", @@ -8106,7 +8290,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "smallvec", "sqlx-core", "stringprep", @@ -8855,7 +9039,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", + "prost 0.11.9", "rustls-pemfile", "tokio", "tokio-rustls", @@ -9364,7 +9548,7 @@ dependencies = [ "serde", "serde_json", "sha-1", - "sha2", + "sha2 0.10.8", "sha3", "snafu", "strip-ansi-escapes", diff --git a/quickwit/Cargo.toml b/quickwit/Cargo.toml index 82419148e2f..b91068fe5a3 100644 --- a/quickwit/Cargo.toml +++ b/quickwit/Cargo.toml @@ -34,6 +34,7 @@ members = [ "quickwit-serve", "quickwit-storage", "quickwit-telemetry", + "quickwit-license", ] # The following list excludes `quickwit-metastore-utils` and `quickwit-lambda` @@ -87,6 +88,8 @@ async-speed-limit = "0.4" async-trait = "0.1" base64 = "0.22" binggan = { version = "0.14" } +biscuit-auth = "5.0.0" + bytes = { version = "1", features = ["serde"] } bytesize = { version = "1.3.0", features = ["serde"] } bytestring = "1.3.0" @@ -317,6 +320,7 @@ quickwit-ingest = { path = "quickwit-ingest" } quickwit-integration-tests = { path = "quickwit-integration-tests" } quickwit-jaeger = { path = "quickwit-jaeger" } quickwit-janitor = { path = "quickwit-janitor" } +quickwit-license = { path = "quickwit-license" } quickwit-macros = { path = "quickwit-macros" } quickwit-metastore = { path = "quickwit-metastore" } quickwit-opentelemetry = { path = "quickwit-opentelemetry" } diff --git a/quickwit/quickwit-cli/Cargo.toml b/quickwit/quickwit-cli/Cargo.toml index d403eef2922..6542536aca1 100644 --- a/quickwit/quickwit-cli/Cargo.toml +++ b/quickwit/quickwit-cli/Cargo.toml @@ -79,6 +79,7 @@ quickwit-metastore = { workspace = true, features = ["testsuite"] } quickwit-storage = { workspace = true, features = ["testsuite"] } [features] +enterprise = ["quickwit-config/enterprise"] jemalloc = ["dep:tikv-jemalloc-ctl", "dep:tikv-jemallocator"] ci-test = [] pprof = ["quickwit-serve/pprof"] diff --git a/quickwit/quickwit-config/Cargo.toml b/quickwit/quickwit-config/Cargo.toml index 7cf75818444..3fba782c0ea 100644 --- a/quickwit/quickwit-config/Cargo.toml +++ b/quickwit/quickwit-config/Cargo.toml @@ -37,6 +37,7 @@ vrl = { workspace = true, optional = true } quickwit-common = { workspace = true } quickwit-doc-mapper = { workspace = true } +quickwit-license = { workspace = true, optional = true } quickwit-proto = { workspace = true } [dev-dependencies] @@ -47,3 +48,4 @@ quickwit-proto = { workspace = true, features = ["testsuite"] } [features] testsuite = [] vrl = ["dep:vrl"] +enterprise = ["quickwit-license"] diff --git a/quickwit/quickwit-config/src/node_config/serialize.rs b/quickwit/quickwit-config/src/node_config/serialize.rs index 8a1337636cf..5a6ead19e18 100644 --- a/quickwit/quickwit-config/src/node_config/serialize.rs +++ b/quickwit/quickwit-config/src/node_config/serialize.rs @@ -213,6 +213,8 @@ struct NodeConfigBuilder { #[serde(rename = "jaeger")] #[serde(default)] jaeger_config: JaegerConfig, + #[serde(default)] + license: Option, } impl NodeConfigBuilder { @@ -305,6 +307,15 @@ impl NodeConfigBuilder { .map(|gossip_interval_ms| Duration::from_millis(gossip_interval_ms as u64)) .unwrap_or(DEFAULT_GOSSIP_INTERVAL); + // Environment variable takes precedence for license too. + #[cfg(feature = "enterprise")] + if let Some(license_str) = env_vars.get("QW_LICENSE").or(self.license.as_ref()) { + if let Err(error) = quickwit_license::set_license(license_str) { + tracing::error!(error=?error, "invalid license"); + std::process::exit(1); + } + } + let node_config = NodeConfig { cluster_id: self.cluster_id.resolve(env_vars)?, node_id, diff --git a/quickwit/quickwit-license/Cargo.toml b/quickwit/quickwit-license/Cargo.toml new file mode 100644 index 00000000000..ebaa9711ed1 --- /dev/null +++ b/quickwit/quickwit-license/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "quickwit-license" +version.workspace = true +edition.workspace = true +homepage.workspace = true +documentation.workspace = true +repository.workspace = true +authors.workspace = true +license = "Quickwit Enterprise License" + +[dependencies] +biscuit-auth = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } diff --git a/quickwit/quickwit-license/LICENSE.md b/quickwit/quickwit-license/LICENSE.md new file mode 100644 index 00000000000..aee1609739b --- /dev/null +++ b/quickwit/quickwit-license/LICENSE.md @@ -0,0 +1,20 @@ +The Quickwit Enterprise Edition (EE) license +Copyright (c) 2024-present Quickwit Inc. + +With regard to the Quickwit Software: + +This software and associated documentation files (the "Software") may only be +used in production, if you (and any entity that you represent) hold a valid +Quickwit Enterprise license corresponding to your usage. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +For all third party components incorporated into the Quickwit Software, those +components are licensed under the original license provided by the owner of the +applicable component. diff --git a/quickwit/quickwit-license/src/lib.rs b/quickwit/quickwit-license/src/lib.rs new file mode 100644 index 00000000000..dc4f0c01cb0 --- /dev/null +++ b/quickwit/quickwit-license/src/lib.rs @@ -0,0 +1,233 @@ +// The Quickwit Enterprise Edition (EE) license +// Copyright (c) 2024-present Quickwit Inc. +// +// With regard to the Quickwit Software: +// +// This software and associated documentation files (the "Software") may only be +// used in production, if you (and any entity that you represent) hold a valid +// Quickwit Enterprise license corresponding to your usage. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// For all third party components incorporated into the Quickwit Software, those +// components are licensed under the original license provided by the owner of the +// applicable component. + +use std::str::FromStr; +use std::sync::OnceLock; +use std::time::SystemTime; + +use biscuit_auth::builder::{Predicate, Rule, Term}; +use biscuit_auth::builder_ext::AuthorizerExt; +use biscuit_auth::macros::biscuit; +use biscuit_auth::{Authorizer, Biscuit, PublicKey}; +use tracing::{error, info}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("invalid biscuit")] + Unverified, + #[error("invalid parameter {0}")] + InvalidParameter(String), + #[error("license expired")] + LicenseExpired, +} + +#[cfg(test)] +const QUICKWIT_PUBLIC_KEY_HEX: &'static str = + "5a81acfc945c7c64c3e95a0c8ce2caafec7c496e76db9ff528755eca7fc16c25"; + +#[cfg(not(test))] +const QUICKWIT_PUBLIC_KEY_HEX: &'static str = + "32d02f39dbfcf6e70d0eceae3e4055c82fad8df7c9a062b89b21e3efd05c1d3f"; + +#[derive(Debug)] +pub struct License { + pub license_level: LicenseLevel, + pub licensee: String, +} + +fn extract_single_key_value(authorizer: &mut Authorizer, key: &str) -> Result { + let head_predicate = Predicate::new( + "data".to_string(), + vec![Term::Variable("placeholder".to_string())], + ); + let body_predicate = Predicate::new( + key.to_string(), + vec![Term::Variable("placeholder".to_string())], + ); + let rule = Rule::new(head_predicate, vec![body_predicate], Vec::new(), Vec::new()); + let values: Vec<(String,)> = authorizer + .query(rule) + .map_err(|_| Error::InvalidParameter(key.to_string()))?; //r#"data($license_level) <- license($license_level)"#) + if values.len() != 1 { + return Err(Error::InvalidParameter(key.to_string())); + } + let value_str = values.into_iter().next().unwrap().0; + Ok(value_str) +} + +fn extract_license(license_str: &str) -> Result { + let quickwit_public_key = + PublicKey::from_bytes_hex(QUICKWIT_PUBLIC_KEY_HEX).expect("Invalid public key"); + let biscuit = + Biscuit::from_base64(license_str, quickwit_public_key).map_err(|_| Error::Unverified)?; + let mut authorizer = Authorizer::new(); + authorizer.set_time(); + authorizer + .add_token(&biscuit) + .map_err(|_| Error::Unverified)?; + authorizer.add_allow_all(); + authorizer.authorize().map_err(|_| Error::LicenseExpired)?; + let license_level_str: String = extract_single_key_value(&mut authorizer, "license_level")?; + let licensee: String = extract_single_key_value(&mut authorizer, "licensee")?; + let license_level = LicenseLevel::from_str(&license_level_str) + .map_err(|_| Error::InvalidParameter("license_level".to_string()))?; + Ok(License { + license_level, + licensee, + }) +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub enum LicenseLevel { + Community, + Gold, +} + +impl LicenseLevel { + fn name(&self) -> &'static str { + match self { + LicenseLevel::Community => "community", + LicenseLevel::Gold => "gold", + } + } +} + +impl FromStr for LicenseLevel { + type Err = anyhow::Error; + + fn from_str(license_str: &str) -> anyhow::Result { + match license_str { + "gold" => Ok(Self::Gold), + _ => Err(anyhow::anyhow!("Unknown license level: {}", license_str)), + } + } +} + +static LICENSE: OnceLock = OnceLock::new(); + +pub fn set_license(license_hex_str: &str) -> Result<(), Error> { + let license = extract_license(license_hex_str)?; + if let Err(_license) = LICENSE.set(license) { + // Someone already set the license. + error!("license already set, this should not happen"); + } + let license = LICENSE.get().unwrap(); + info!( + "enabling {:?} license for {}", + license.license_level, + license.licensee.as_str() + ); + Ok(()) +} + +pub fn get_license_level() -> LicenseLevel { + #[cfg(not(test))] + const DEFAULT_LICENSE_LEVEL: LicenseLevel = LicenseLevel::Community; + #[cfg(test)] + const DEFAULT_LICENSE_LEVEL: LicenseLevel = LicenseLevel::Gold; + LICENSE + .get() + .map(|license| license.license_level) + .unwrap_or(DEFAULT_LICENSE_LEVEL) +} + +use biscuit_auth::builder_ext::BuilderExt; + +pub fn create_license(license_level: LicenseLevel, licensee: &str, expiration_date: SystemTime) -> biscuit_auth::builder::BiscuitBuilder { + let license_level_str = license_level.name(); + let mut biscuit_builder = biscuit!( + r#"license_level({license_level_str}); + licensee({licensee}); + "#, + ); + biscuit_builder.check_expiration_date(expiration_date); + biscuit_builder +} + +#[cfg(test)] +mod tests { + use std::time::SystemTime; + + use biscuit_auth::macros::biscuit; + use biscuit_auth::{KeyPair, PrivateKey}; + + use crate::LicenseLevel; + + const QUICKWIT_PRIVATE_KEY_HEX: &str = + "43fec56169112de681ab5935fdda7d589b79ba430bd128bc85d18a592813d0b6"; + const QUICKWIT_INVALID_PRIVATE_KEY_HEX: &str = + "42fec56169112de681ab5935fdda7d589b79ba430bd128bc85d18a592813d0b6"; + + #[test] + fn test_license_success() { + let private_key: PrivateKey = PrivateKey::from_bytes_hex(QUICKWIT_PRIVATE_KEY_HEX).unwrap(); + let key_pair = KeyPair::from(&private_key); + let biscuit = super::create_license(LicenseLevel::Gold, "LittleBlue Inc.", SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(2_077_439_515)) + .build(&key_pair) + .unwrap(); + let license_str = biscuit.to_base64().unwrap(); + + let license = super::extract_license(&license_str).unwrap(); + assert_eq!(license.license_level, LicenseLevel::Gold); + assert_eq!(&license.licensee, "LittleBlue Inc."); + } + + #[test] + fn test_license_invalid_private_key() { + let private_key: PrivateKey = + PrivateKey::from_bytes_hex(QUICKWIT_INVALID_PRIVATE_KEY_HEX).unwrap(); + let key_pair = KeyPair::from(&private_key); + let biscuit = super::create_license(LicenseLevel::Gold, "LittleBlue Inc.", SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(2_077_439_515)) + .build(&key_pair) + .unwrap(); + let license_str = biscuit.to_base64().unwrap(); + let err = super::extract_license(&license_str).unwrap_err(); + assert!(matches!(err, super::Error::Unverified)); + } + + #[test] + fn test_license_expired() { + let private_key: PrivateKey = PrivateKey::from_bytes_hex(QUICKWIT_PRIVATE_KEY_HEX).unwrap(); + let key_pair = KeyPair::from(&private_key); + let biscuit = super::create_license(LicenseLevel::Gold, "LittleBlue Inc.", SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_730_370_989)) + .build(&key_pair) + .unwrap(); + let license_str = biscuit.to_base64().unwrap(); + let err = super::extract_license(&license_str).unwrap_err(); + assert!(matches!(err, super::Error::LicenseExpired)); + } + + #[test] + fn test_missing_licensee() { + let private_key: PrivateKey = PrivateKey::from_bytes_hex(QUICKWIT_PRIVATE_KEY_HEX).unwrap(); + let key_pair = KeyPair::from(&private_key); + let biscuit = biscuit!( + r#"license_level("gold"); + check if time($time), $time <= 2035-05-30T20:00:00Z; + "#, + ) + .build(&key_pair) + .unwrap(); + let license_str = biscuit.to_base64().unwrap(); + let err = super::extract_license(&license_str).unwrap_err(); + assert!(matches!(err, super::Error::InvalidParameter(_))); + } +} diff --git a/quickwit/quickwit-proto/src/codegen/jaeger/jaeger.api_v2.rs b/quickwit/quickwit-proto/src/codegen/jaeger/jaeger.api_v2.rs index 42a2f109167..b34d2868413 100644 --- a/quickwit/quickwit-proto/src/codegen/jaeger/jaeger.api_v2.rs +++ b/quickwit/quickwit-proto/src/codegen/jaeger/jaeger.api_v2.rs @@ -92,7 +92,6 @@ pub mod trace { } } /// Note that both Span and Batch may contain a Process. -/// /// This is different from the Thrift model which was only used /// for transport, because Proto model is also used by the backend /// as the domain model, where once a batch is received it is split diff --git a/quickwit/quickwit-proto/src/codegen/quickwit/quickwit.search.rs b/quickwit/quickwit-proto/src/codegen/quickwit/quickwit.search.rs index 473f1ec42f1..189019162f8 100644 --- a/quickwit/quickwit-proto/src/codegen/quickwit/quickwit.search.rs +++ b/quickwit/quickwit-proto/src/codegen/quickwit/quickwit.search.rs @@ -371,7 +371,6 @@ pub struct Hit { pub index_id: ::prost::alloc::string::String, } /// A partial hit, is a hit for which we have not fetch the content yet. -/// /// Instead, it holds a document_uri which is enough information to /// go and fetch the actual document data, by performing a `get_doc(...)` /// request. diff --git a/quickwit/quickwit-serve/src/build_info.rs b/quickwit/quickwit-serve/src/build_info.rs index 229897af996..f13bfc3194c 100644 --- a/quickwit/quickwit-serve/src/build_info.rs +++ b/quickwit/quickwit-serve/src/build_info.rs @@ -32,6 +32,7 @@ pub struct BuildInfo { pub commit_short_hash: &'static str, pub commit_tags: Vec, pub version: String, + pub edition: &'static str, } impl BuildInfo { @@ -68,7 +69,15 @@ impl BuildInfo { .cloned() .unwrap_or_else(|| concat!(env!("CARGO_PKG_VERSION"), "-nightly").to_string()); - Self { + let edition = { + if cfg!(feature="enterprise") { + "enterprise" + } else { + "community" + } + }; + + BuildInfo { build_date: env!("BUILD_DATE"), build_profile: env!("BUILD_PROFILE"), build_target: env!("BUILD_TARGET"), @@ -78,6 +87,7 @@ impl BuildInfo { commit_short_hash, commit_tags, version, + edition, } }) } @@ -85,7 +95,8 @@ impl BuildInfo { pub fn get_version_text() -> String { let build_info = Self::get(); format!( - "{} ({} {} {})", + "{} {} ({} {} {})", + build_info.edition, build_info.cargo_pkg_version, build_info.build_target, build_info.commit_date, diff --git a/quickwit/.license_header.txt b/quickwit/scripts/.agpl.license_header.txt similarity index 99% rename from quickwit/.license_header.txt rename to quickwit/scripts/.agpl.license_header.txt index 5dcb755bc8a..f77c3c4c9ba 100644 --- a/quickwit/.license_header.txt +++ b/quickwit/scripts/.agpl.license_header.txt @@ -16,4 +16,3 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - diff --git a/quickwit/scripts/.ee.license_header.txt b/quickwit/scripts/.ee.license_header.txt new file mode 100644 index 00000000000..9a1485ca763 --- /dev/null +++ b/quickwit/scripts/.ee.license_header.txt @@ -0,0 +1,20 @@ +// The Quickwit Enterprise Edition (EE) license +// Copyright (c) {\d+}-present Quickwit Inc. +// +// With regard to the Quickwit Software: +// +// This software and associated documentation files (the "Software") may only be +// used in production, if you (and any entity that you represent) hold a valid +// Quickwit Enterprise license corresponding to your usage. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// For all third party components incorporated into the Quickwit Software, those +// components are licensed under the original license provided by the owner of the +// applicable component. diff --git a/quickwit/scripts/check_license_headers.sh b/quickwit/scripts/check_license_headers.sh index d36f24e8aff..6684b2023ba 100755 --- a/quickwit/scripts/check_license_headers.sh +++ b/quickwit/scripts/check_license_headers.sh @@ -2,6 +2,8 @@ RESULT=0 +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + for file in $(git ls-files | \ grep "build\|src\|proto" | \ grep -e "\.proto\|\.rs\|\.ts" | \ @@ -10,9 +12,13 @@ for file in $(git ls-files | \ grep -v "/codegen/" \ ) do - diff <(sed 's/{\\d+}/2024/' .license_header.txt) <(head -n 19 $file) > /dev/null - DIFFRESULT=$? - if [ $DIFFRESULT -ne 0 ]; then + # echo "Checking $file"; + diff <(sed 's/{\\d+}/2024/' "${SCRIPT_DIR}/.agpl.license_header.txt") <(head -n 18 $file) > /dev/null + HAS_AGPL_LICENSE=$? + diff <(sed 's/{\\d+}/2024/' "${SCRIPT_DIR}/.ee.license_header.txt") <(head -n 20 $file) > /dev/null + HAS_EE_LICENSE=$? + HAS_LICENSE_HEADER=$(( $HAS_AGPL_LICENSE ^ $HAS_EE_LICENSE )) + if [ $HAS_LICENSE_HEADER -ne 1 ]; then grep -q -i 'begin quickwit-codegen' $file GREPRESULT=$? if [ $GREPRESULT -ne 0 ]; then