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