From 7da1b22256874d3346025135422219fb6f8bb0e7 Mon Sep 17 00:00:00 2001 From: Luca Zaninotto Date: Mon, 17 Nov 2025 11:44:31 +0100 Subject: [PATCH 1/9] chore: Init e2e test suite Init a new Rust project to serve as e2e test suite Signed-off-by: Luca Zaninotto --- tools/e2e_test/.gitignore | 14 ++++++++++++++ tools/e2e_test/Cargo.lock | 7 +++++++ tools/e2e_test/Cargo.toml | 6 ++++++ tools/e2e_test/src/main.rs | 3 +++ 4 files changed, 30 insertions(+) create mode 100644 tools/e2e_test/.gitignore create mode 100644 tools/e2e_test/Cargo.lock create mode 100644 tools/e2e_test/Cargo.toml create mode 100644 tools/e2e_test/src/main.rs diff --git a/tools/e2e_test/.gitignore b/tools/e2e_test/.gitignore new file mode 100644 index 000000000..b2c29a5aa --- /dev/null +++ b/tools/e2e_test/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug +target + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Generated by cargo mutants +# Contains mutation testing data +**/mutants.out*/ diff --git a/tools/e2e_test/Cargo.lock b/tools/e2e_test/Cargo.lock new file mode 100644 index 000000000..a6d4f7285 --- /dev/null +++ b/tools/e2e_test/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "e2e_test" +version = "0.1.0" diff --git a/tools/e2e_test/Cargo.toml b/tools/e2e_test/Cargo.toml new file mode 100644 index 000000000..1db3b64d1 --- /dev/null +++ b/tools/e2e_test/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "e2e_test" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/tools/e2e_test/src/main.rs b/tools/e2e_test/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/tools/e2e_test/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 874fc22ad69ffe03580bd0cb22ac92fb3693d8f2 Mon Sep 17 00:00:00 2001 From: Luca Zaninotto Date: Mon, 17 Nov 2025 15:32:53 +0100 Subject: [PATCH 2/9] chore: Init image credentials creation e2e test Signed-off-by: Luca Zaninotto --- tools/e2e_test/.gitignore | 3 + tools/e2e_test/Cargo.lock | 2211 ++++++ tools/e2e_test/Cargo.lock.license | 18 + tools/e2e_test/Cargo.toml | 26 + .../create_image_credentials.graphql | 27 + .../graphql/queries/image_credentials.graphql | 25 + tools/e2e_test/graphql/schema.graphql | 6607 +++++++++++++++++ tools/e2e_test/graphql/schema.graphql.license | 3 + tools/e2e_test/src/image_credentials/mod.rs | 70 + .../mutations/create_image_credentials.rs | 52 + .../src/image_credentials/mutations/mod.rs | 19 + .../queries/get_image_credentials.rs | 45 + .../src/image_credentials/queries/mod.rs | 19 + tools/e2e_test/src/main.rs | 32 +- tools/e2e_test/src/suite/client.rs | 54 + tools/e2e_test/src/suite/config.rs | 43 + tools/e2e_test/src/suite/mod.rs | 20 + 17 files changed, 9272 insertions(+), 2 deletions(-) create mode 100644 tools/e2e_test/Cargo.lock.license create mode 100644 tools/e2e_test/graphql/mutations/create_image_credentials.graphql create mode 100644 tools/e2e_test/graphql/queries/image_credentials.graphql create mode 100644 tools/e2e_test/graphql/schema.graphql create mode 100644 tools/e2e_test/graphql/schema.graphql.license create mode 100644 tools/e2e_test/src/image_credentials/mod.rs create mode 100644 tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs create mode 100644 tools/e2e_test/src/image_credentials/mutations/mod.rs create mode 100644 tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs create mode 100644 tools/e2e_test/src/image_credentials/queries/mod.rs create mode 100644 tools/e2e_test/src/suite/client.rs create mode 100644 tools/e2e_test/src/suite/config.rs create mode 100644 tools/e2e_test/src/suite/mod.rs diff --git a/tools/e2e_test/.gitignore b/tools/e2e_test/.gitignore index b2c29a5aa..0e50bf173 100644 --- a/tools/e2e_test/.gitignore +++ b/tools/e2e_test/.gitignore @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 SECO Mind Srl +# SPDX-License-Identifier: CC0-1.0 + # Generated by Cargo # will have compiled files and executables debug diff --git a/tools/e2e_test/Cargo.lock b/tools/e2e_test/Cargo.lock index a6d4f7285..765896cc5 100644 --- a/tools/e2e_test/Cargo.lock +++ b/tools/e2e_test/Cargo.lock @@ -2,6 +2,2217 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cc" +version = "1.2.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "e2e_test" version = "0.1.0" +dependencies = [ + "clap", + "eyre", + "graphql_client", + "log", + "rand", + "reqwest 0.12.24", + "serde", + "tokio", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "graphql-introspection-query" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2a4732cf5140bd6c082434494f785a19cfb566ab07d1382c3671f5812fed6d" +dependencies = [ + "serde", +] + +[[package]] +name = "graphql-parser" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a818c0d883d7c0801df27be910917750932be279c7bc82dc541b8769425f409" +dependencies = [ + "combine", + "thiserror", +] + +[[package]] +name = "graphql_client" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a50cfdc7f34b7f01909d55c2dcb71d4c13cbcbb4a1605d6c8bd760d654c1144b" +dependencies = [ + "graphql_query_derive", + "reqwest 0.11.27", + "serde", + "serde_json", +] + +[[package]] +name = "graphql_client_codegen" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e27ed0c2cf0c0cc52c6bcf3b45c907f433015e580879d14005386251842fb0a" +dependencies = [ + "graphql-introspection-query", + "graphql-parser", + "heck 0.4.1", + "lazy_static", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "graphql_query_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83febfa838f898cfa73dfaa7a8eb69ff3409021ac06ee94cfb3d622f6eeb1a97" +dependencies = [ + "graphql_client_codegen", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper 1.8.1", + "hyper-util", + "rustls 0.23.35", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.8.1", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.1", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.10.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "hyper-tls 0.5.0", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-rustls 0.27.7", + "hyper-tls 0.6.0", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.103.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.10.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.1", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls 0.23.35", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.10.0", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.110", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] diff --git a/tools/e2e_test/Cargo.lock.license b/tools/e2e_test/Cargo.lock.license new file mode 100644 index 000000000..fec65eb06 --- /dev/null +++ b/tools/e2e_test/Cargo.lock.license @@ -0,0 +1,18 @@ +This file is part of Edgehog. + +Copyright 2025 SECO Mind Srl + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 +SPDX-License-Identifier: CC0-1.0 diff --git a/tools/e2e_test/Cargo.toml b/tools/e2e_test/Cargo.toml index 1db3b64d1..03cb9a1d8 100644 --- a/tools/e2e_test/Cargo.toml +++ b/tools/e2e_test/Cargo.toml @@ -1,6 +1,32 @@ +# This file is part of Edgehog. +# +# Copyright 2025 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + [package] name = "e2e_test" version = "0.1.0" edition = "2024" [dependencies] +clap = { version = "4.5.53", features = ["derive", "env"] } +eyre = "0.6.12" +graphql_client = { version = "0.14.0", features = ["reqwest", "reqwest-blocking", "reqwest-crate", "reqwest-rustls"] } +log = "0.4.29" +rand = "0.9.2" +reqwest = { version = "0.12.24", features = ["json"] } +serde = "1.0.228" +tokio = { version = "1.48.0", features = ["full"] } diff --git a/tools/e2e_test/graphql/mutations/create_image_credentials.graphql b/tools/e2e_test/graphql/mutations/create_image_credentials.graphql new file mode 100644 index 000000000..02e8c8e96 --- /dev/null +++ b/tools/e2e_test/graphql/mutations/create_image_credentials.graphql @@ -0,0 +1,27 @@ +# This file is part of Edgehog. +# +# Copyright 2025 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +mutation CreateImageCredentials($input: CreateImageCredentialsInput!) { + createImageCredentials(input: $input) { + result { + label + username + id + } + } +} diff --git a/tools/e2e_test/graphql/queries/image_credentials.graphql b/tools/e2e_test/graphql/queries/image_credentials.graphql new file mode 100644 index 000000000..60c1bba05 --- /dev/null +++ b/tools/e2e_test/graphql/queries/image_credentials.graphql @@ -0,0 +1,25 @@ +# This file is part of Edgehog. +# +# Copyright 2025 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +query GetImageCredentials($id: ID!) { + imageCredentials(id: $id) { + label + username + id + } +} diff --git a/tools/e2e_test/graphql/schema.graphql b/tools/e2e_test/graphql/schema.graphql new file mode 100644 index 000000000..ba59e24b1 --- /dev/null +++ b/tools/e2e_test/graphql/schema.graphql @@ -0,0 +1,6607 @@ +schema { + subscription: RootSubscriptionType + mutation: RootMutationType + query: RootQueryType +} + +input ContainerCreateWithNestedImageInput { + id: ID + reference: String + imageCredentialsId: ID +} + +input ContainerCreateWithNestedNetworksInput { + id: ID +} + +input ContainerCreateWithNestedVolumesInput { + id: ID + target: String +} + +input ContainerCreateWithNestedDeviceMappingsInput { + pathOnHost: String! + pathInContainer: String! + cgroupPermissions: String! +} + +input CampaignCampaignMechanismFirmwareUpgradeInput { + baseImageId: ID + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Update Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + + """ + The maximum number of in progress updates. The Update Campaign will have + at most this number of OTA Operations that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int + + """ + The number of attempts that have to be tried before giving up on the + update of a specific target (and considering it an error). Note that the + update is retried only if the OTA Request doesn't get acknowledged from the + device. + """ + requestRetries: Int + + """ + The timeout (in seconds) Edgehog has to wait before considering an OTA + Request lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int + + """ + This boolean flag determines if the Base Image will be pushed to the + Device even if it already has a greater version of the Base Image. + """ + forceDowngrade: Boolean +} + +"An object representing the properties of a Firmware Upgrade campaign mechanism." +type FirmwareUpgrade { + """ + This boolean flag determines if the Base Image will be pushed to the + Device even if it already has a greater version of the Base Image. + """ + forceDowngrade: Boolean! + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Update Campaign terminates with + a failure. + """ + maxFailurePercentage: Float! + + """ + The maximum number of in progress updates. The Update Campaign will have + at most this number of OTA Operations that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int! + + """ + The number of attempts that have to be tried before giving up on the + update of a specific target (and considering it an error). Note that the + update is retried only if the OTA Request doesn't get acknowledged from the + device. + """ + requestRetries: Int! + + """ + The timeout (in seconds) Edgehog has to wait before considering an OTA + Request lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int! + + baseImageId: Int! + + "The base image distributed by the update campaign." + baseImage: BaseImage! +} + +input CampaignCampaignMechanismDeploymentUpgradeInput { + releaseId: ID + + targetReleaseId: ID + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int +} + +"An object representing the properties of a Upgrade deployment campaign mechanism." +type DeploymentUpgrade { + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float! + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int! + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int! + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int! + + releaseId: ID + + targetReleaseId: ID + + "The release deployed by the mechanism." + release: Release + + "The release used for upgrading by the deployment campaign." + targetRelease: Release +} + +input CampaignCampaignMechanismDeploymentDeleteInput { + releaseId: ID + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int +} + +"An object representing the properties of a Delete deployment campaign mechanism." +type DeploymentDelete { + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float! + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int! + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int! + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int! + + releaseId: ID + + "The release deployed by the mechanism." + release: Release +} + +input CampaignCampaignMechanismDeploymentStopInput { + releaseId: ID + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int +} + +"An object representing the properties of a Stop deployment campaign mechanism." +type DeploymentStop { + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float! + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int! + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int! + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int! + + releaseId: ID + + "The release deployed by the mechanism." + release: Release +} + +input CampaignCampaignMechanismDeploymentStartInput { + releaseId: ID + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int +} + +"An object representing the properties of a Start deployment campaign mechanism." +type DeploymentStart { + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Campaign terminates with + a failure. + """ + maxFailurePercentage: Float! + + """ + The maximum number of in progress operations. The Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int! + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int! + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int! + + releaseId: ID + + "The release deployed by the mechanism." + release: Release +} + +input CampaignCampaignMechanismDeploymentDeployInput { + releaseId: ID + + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Deployment Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + + """ + The maximum number of in progress deployments. The Update Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int +} + +"An object representing the properties of a Deploy deployment campaign mechanism." +type DeploymentDeploy { + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the Deployment Campaign terminates with + a failure. + """ + maxFailurePercentage: Float! + + """ + The maximum number of in progress deployments. The Update Campaign will + have at most this number of Deployments that are started but not yet + finished (either successfully or not). + """ + maxInProgressOperations: Int! + + """ + The number of attempts that have to be tried before giving up on the + deploy of a specific target (and considering it an error). Note that the + deployment is retried only if the Deployment doesn't get acknowledged from the + device. + """ + requestRetries: Int! + + """ + The timeout (in seconds) Edgehog has to wait before considering a + Deployment lost (and possibly retry). It must be at least 30 seconds. + """ + requestTimeoutSeconds: Int! + + releaseId: ID + + "The release deployed by the mechanism." + release: Release +} + +""" +Describes the position of a device. + +The field holds information about the GPS coordinates of the device, +which are estimated by means of Edgehog's geolocation modules and the +data published by the device. +""" +type Position { + "The latitude coordinate." + latitude: Float! + + "The longitude coordinate." + longitude: Float! + + "The accuracy of the measurement, in meters." + accuracy: Float + + "The altitude coordinate." + altitude: Float + + "The accuracy of the altitude measurement, in meters." + altitudeAccuracy: Float + + "The measured heading." + heading: Float + + "The measured speed." + speed: Float + + "The date and time at which the measurement was made." + timestamp: DateTime! + + "Describes how the position was calculated." + source: String +} + +"Describes a network interface of a device." +type NetworkInterface { + "The identifier of the network interface." + name: String! + + "The normalized physical address." + macAddress: String + + "The connection technology." + technology: NetworkInterfaceTechnology +} + +""" +Describes the place where a device is located. + +The field holds information about the device's address, which is +estimated by means of Edgehog's geolocation modules and the data +published by the device. +""" +type Location { + "The formatted address associated with the location." + formattedAddress: String! + + "The date and time at which the location was measured." + timestamp: DateTime! + + "Describes how the location was calculated." + source: String +} + +"Describes a battery slot of a device." +type BatterySlot { + "Battery level measurement absolute error [0.0-100.0]." + levelAbsoluteError: Float + + "Battery level estimated percentage [0.0%-100.0%]." + levelPercentage: Float + + "The identifier of the battery slot." + slot: String! + + "The current status of the battery." + status: BatterySlotStatus +} + +"Describes a modem of a device." +type Modem { + "The operator apn address." + apn: String + + "Carrier operator name." + carrier: String + + "Unique identifier of the cell." + cellId: Int + + "The modem IMEI code." + imei: String + + "The SIM IMSI code." + imsi: String + + "The Local Area Code." + localAreaCode: Int + + "The cell tower's Mobile Country Code (MCC)." + mobileCountryCode: Int + + "The cell tower's Mobile Network Code." + mobileNetworkCode: Int + + "The GSM\/LTE registration status of the modem." + registrationStatus: ModemRegistrationStatus + + "Signal strength in dBm." + rssi: Float + + "The identifier of the modem." + slot: String! + + "The access technology of the serving cell." + technology: ModemTechnology +} + +input CampaignMechanismInput { + deploymentDelete: CampaignCampaignMechanismDeploymentDeleteInput + deploymentDeploy: CampaignCampaignMechanismDeploymentDeployInput + deploymentStart: CampaignCampaignMechanismDeploymentStartInput + deploymentStop: CampaignCampaignMechanismDeploymentStopInput + deploymentUpgrade: CampaignCampaignMechanismDeploymentUpgradeInput + firmwareUpgrade: CampaignCampaignMechanismFirmwareUpgradeInput +} + +union CampaignMechanism = DeploymentDelete | DeploymentDeploy | DeploymentStart | DeploymentStop | DeploymentUpgrade | FirmwareUpgrade + +enum CampaignTargetStatus { + "Something went wrong while attempting operation on the target." + FAILED + + "The campaign target is waiting for the campaign to start." + IDLE + + "The campaign is in progress." + IN_PROGRESS + + "The operation has executed successfully on the target." + SUCCESSFUL +} + +enum CampaignOutcome { + "The campaign has finished with a failure." + FAILURE + + "The campaign has finished successfully." + SUCCESS +} + +enum CampaignStatus { + "The campaign has finished." + FINISHED + + "The campaign has been created but is not being rolled-out yet." + IDLE + + "The campaign is being rolled-out." + IN_PROGRESS +} + +enum OtaOperationStatusCode { + "The OTA Operation was canceled" + CANCELED + + "An internal error was encountered" + INTERNAL_ERROR + + "The OTA Operation failed due to an invalid base image" + INVALID_BASE_IMAGE + + "The OTA Operation contained invalid data" + INVALID_REQUEST + + "An IO error was encountered" + IO_ERROR + + "A network error was encountered" + NETWORK_ERROR + + "The OTA Operation timed out while sending the request to the device" + REQUEST_TIMEOUT + + "A system rollback has occurred" + SYSTEM_ROLLBACK + + "An OTA Operation is already in progress on the device" + UPDATE_ALREADY_IN_PROGRESS +} + +enum OtaOperationStatus { + "The OTA operation was acknowledged from the device" + ACKNOWLEDGED + + "The device deployed the update" + DEPLOYED + + "The device is deploying the update" + DEPLOYING + + "The device is downloading the update" + DOWNLOADING + + "A recoverable error happened during the OTA operation" + ERROR + + "The OTA operation ended with a failure. This is a final state of the OTA Operation" + FAILURE + + "The OTA operation was created and is waiting an acknowledgment from the device" + PENDING + + "The device is in the process of rebooting" + REBOOTING + + "The OTA operation ended successfully. This is a final state of the OTA Operation" + SUCCESS +} + +enum ForwarderSessionStatus { + "The device is connected to the forwarder." + CONNECTED + + "The device is connecting to the forwarder." + CONNECTING +} + +enum NetworkInterfaceTechnology { + "Bluetooth." + BLUETOOTH + + "Cellular." + CELLULAR + + "Ethernet." + ETHERNET + + "WiFi." + WIFI +} + +enum BatterySlotStatus { + "The battery is charging." + CHARGING + + "The battery is discharging." + DISCHARGING + + "The battery is either in a charging or in an idle state, since the hardware doesn't allow to distinguish between them." + EITHER_IDLE_OR_CHARGING + + "The battery is in a failed state." + FAILURE + + "The battery is idle." + IDLE + + "The battery is removed." + REMOVED + + "The battery status cannot be determined." + UNKNOWN +} + +enum ModemRegistrationStatus { + "Not registered, modem is not currently searching a new operator to register to." + NOT_REGISTERED + + "Registered, home network." + REGISTERED + + "Registered, roaming." + REGISTERED_ROAMING + + "Registration denied." + REGISTRATION_DENIED + + "Not registered, but modem is currently searching a new operator to register to." + SEARCHING_OPERATOR + + "Unknown (e.g. out of GERAN\/UTRAN\/E-UTRAN coverage)." + UNKNOWN +} + +enum ModemTechnology { + "E-UTRAN." + EUTRAN + + "GSM." + GSM + + "GSM Compact." + GSM_COMPACT + + "GSM with EGPRS." + GSM_EGPRS + + "UTRAN." + UTRAN + + "UTRAN with HSDPA." + UTRAN_HSDPA + + "UTRAN with HSDPA and HSUPA." + UTRAN_HSDPA_HSUPA + + "UTRAN with HSUPA." + UTRAN_HSUPA +} + +enum DeviceCapability { + "The device provides information about its base image." + BASE_IMAGE + + "The device provides information about its battery status." + BATTERY_STATUS + + "The device provides information about its cellular connection." + CELLULAR_CONNECTION + + "The device supports commands, for example the rebooting command." + COMMANDS + + "The device supports running applications using containers." + CONTAINER_MANAGEMENT + + "The device can be geolocated." + GEOLOCATION + + "The device provides information about its hardware." + HARDWARE_INFO + + "The device can be asked to blink its LED in a specific pattern." + LED_BEHAVIORS + + "The device can provide information about its network interfaces." + NETWORK_INTERFACE_INFO + + "The device provides information about its operating system." + OPERATING_SYSTEM + + "The device supports remote terminal sessions." + REMOTE_TERMINAL + + "The device provides information about its runtime." + RUNTIME_INFO + + "The device can be updated remotely." + SOFTWARE_UPDATES + + "The device provides information about its storage units." + STORAGE + + "The device provides information about its system." + SYSTEM_INFO + + "The device provides information about its system status." + SYSTEM_STATUS + + "The device telemetry can be configured." + TELEMETRY_CONFIG + + "The device provides information about surrounding WiFi APs." + WIFI +} + +enum DeviceLedBehavior { + "Blink for 60 seconds." + BLINK + + "Double blink for 60 seconds." + DOUBLE_BLINK + + "Slow blink for 60 seconds." + SLOW_BLINK +} + +enum DeploymentEventType { + "The deployment is getting deleted." + DELETING + + "The deployment encountered an error." + ERROR + + "The deployment is started." + STARTED + + "The deployment is starting." + STARTING + + "The deployment is stopped." + STOPPED + + "The deployment is stopping." + STOPPING + + "The deployment is getting updated." + UPDATING +} + +enum ApplicationDeploymentState { + "The deployment has been created in the database layer, the device yet has to receive it." + PENDING + + "The deployment description has been sent to the device." + SENT + + "The deployment is started on the device." + STARTED + + "The deployment is stopped on the device." + STOPPED +} + +input ContainerEnvVarInput { + value: String! + key: String! +} + +type ContainerEnvVar { + value: String! + key: String! +} + +input LocalizedAttributeUpdateInput { + value: String + languageTag: String! +} + +input LocalizedAttributeInput { + value: String! + languageTag: String! +} + +type LocalizedAttribute { + value: String! + languageTag: String! +} + +"The result of the :delete_base_image_collection mutation" +type DeleteBaseImageCollectionResult { + "The record that was successfully deleted" + result: BaseImageCollection + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :update_base_image_collection mutation" +type UpdateBaseImageCollectionResult { + "The successful result of the mutation" + result: BaseImageCollection + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateBaseImageCollectionInput { + "The display name of the base image collection." + name: String + + """ + The identifier of the base image collection. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String +} + +"The result of the :create_base_image_collection mutation" +type CreateBaseImageCollectionResult { + "The successful result of the mutation" + result: BaseImageCollection + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateBaseImageCollectionInput { + "The display name of the base image collection." + name: String! + + """ + The identifier of the base image collection. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The ID of the system model that is targeted by the base image collection" + systemModelId: ID! +} + +enum BaseImageCollectionSortField { + ID + NAME + HANDLE +} + +":base_image_collection connection" +type BaseImageCollectionConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":base_image_collection edges" + edges: [BaseImageCollectionEdge!] +} + +":base_image_collection edge" +type BaseImageCollectionEdge { + "Cursor" + cursor: String! + + ":base_image_collection node" + node: BaseImageCollection! +} + +input BaseImageCollectionFilterHandle { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input BaseImageCollectionFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input BaseImageCollectionFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input BaseImageCollectionFilterInput { + and: [BaseImageCollectionFilterInput!] + + or: [BaseImageCollectionFilterInput!] + + not: [BaseImageCollectionFilterInput!] + + id: BaseImageCollectionFilterId + + "The display name of the base image collection." + name: BaseImageCollectionFilterName + + """ + The identifier of the base image collection. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: BaseImageCollectionFilterHandle + + "The system model associated with the base image collection." + systemModel: SystemModelFilterInput + + "The base images associated with the base image collection." + baseImages: BaseImageFilterInput +} + +input BaseImageCollectionSortInput { + order: SortOrder + field: BaseImageCollectionSortField! +} + +""" +Represents a collection of Base Images. + +A base image collection represents the collection of all Base Images that can run on a specific System Model. +""" +type BaseImageCollection implements Node { + id: ID! + + "The display name of the base image collection." + name: String! + + """ + The identifier of the base image collection. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The system model associated with the base image collection." + systemModel: SystemModel! + + "The base images associated with the base image collection." + baseImages( + "How to sort the records in the response" + sort: [BaseImageSortInput] + + "A filter to limit the results" + filter: BaseImageFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): BaseImageConnection! +} + +"The result of the :delete_base_image mutation" +type DeleteBaseImageResult { + "The record that was successfully deleted" + result: BaseImage + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :update_base_image mutation" +type UpdateBaseImageResult { + "The successful result of the mutation" + result: BaseImage + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateBaseImageInput { + "The starting version requirement for the base image." + startingVersionRequirement: String + + "A list of descriptions in different languages." + localizedDescriptions: [LocalizedAttributeUpdateInput!] + + "A list of release display names in different languages." + localizedReleaseDisplayNames: [LocalizedAttributeUpdateInput!] +} + +"The result of the :create_base_image mutation" +type CreateBaseImageResult { + "The successful result of the mutation" + result: BaseImage + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateBaseImageInput { + "The base image version." + version: String! + + "The starting version requirement for the base image." + startingVersionRequirement: String + + "The ID of the base image collection this base image will belong to." + baseImageCollectionId: ID! + + "The base image file, which will be uploaded to the storage." + file: Upload! + + "A list of descriptions in different languages." + localizedDescriptions: [LocalizedAttributeInput!] + + "A list of release display names in different languages." + localizedReleaseDisplayNames: [LocalizedAttributeInput!] +} + +enum BaseImageSortField { + ID + VERSION + STARTING_VERSION_REQUIREMENT + URL +} + +":base_image connection" +type BaseImageConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":base_image edges" + edges: [BaseImageEdge!] +} + +":base_image edge" +type BaseImageEdge { + "Cursor" + cursor: String! + + ":base_image node" + node: BaseImage! +} + +input BaseImageFilterUrl { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input BaseImageFilterStartingVersionRequirement { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input BaseImageFilterVersion { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input BaseImageFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input BaseImageFilterInput { + and: [BaseImageFilterInput!] + + or: [BaseImageFilterInput!] + + not: [BaseImageFilterInput!] + + id: BaseImageFilterId + + "The base image version." + version: BaseImageFilterVersion + + "The starting version requirement for the base image." + startingVersionRequirement: BaseImageFilterStartingVersionRequirement + + "The url where the base image can be downloaded." + url: BaseImageFilterUrl + + "The base image collection that this base image belongs to." + baseImageCollection: BaseImageCollectionFilterInput +} + +input BaseImageSortInput { + order: SortOrder + field: BaseImageSortField! +} + +""" +Represents an uploaded Base Image. + +A base image represents a downloadable base image that can be installed on a device +""" +type BaseImage implements Node { + id: ID! + + "The base image version." + version: String! + + "The starting version requirement for the base image." + startingVersionRequirement: String + + "The url where the base image can be downloaded." + url: String! + + "The base image collection that this base image belongs to." + baseImageCollection: BaseImageCollection! + + "A list of descriptions in different languages." + localizedDescriptions(preferredLanguageTags: [String!]): [LocalizedAttribute!] + + "A list of release display names in different languages." + localizedReleaseDisplayNames(preferredLanguageTags: [String!]): [LocalizedAttribute!] + + "Derived Base Image Name from version and localized release display name" + name: String +} + +"A relay page info" +type PageInfo { + "When paginating backwards, are there more items?" + hasPreviousPage: Boolean! + + "When paginating forwards, are there more items?" + hasNextPage: Boolean! + + "When paginating backwards, the cursor to continue" + startCursor: String + + "When paginating forwards, the cursor to continue" + endCursor: String +} + +"A relay node" +interface Node { + "A unique identifier" + id: ID! +} + +enum SortOrder { + DESC + DESC_NULLS_FIRST + DESC_NULLS_LAST + ASC + ASC_NULLS_FIRST + ASC_NULLS_LAST +} + +"An error generated by a failed mutation" +type MutationError { + "The human readable error message" + message: String + + "A shorter error message, with vars not replaced" + shortMessage: String + + "Replacements for the short message" + vars: Json + + "An error code for the given error" + code: String + + "The field or fields that produced the error" + fields: [String!] +} + +input ApplicationCreateInitialReleaseInput { + version: String! + containers: [ReleaseCreateContainersInput!] + requiredSystemModels: [ReleaseCreateRequiredSystemModelsInput!] +} + +input ReleaseCreateContainersInput { + env: [ContainerEnvVarInput!] + id: ID + memory: Int + image: ContainerCreateWithNestedImageInput + hostname: String + networks: [ContainerCreateWithNestedNetworksInput!] + volumes: [ContainerCreateWithNestedVolumesInput!] + deviceMappings: [ContainerCreateWithNestedDeviceMappingsInput!] + portBindings: [String!] + restartPolicy: String + networkMode: String + privileged: Boolean + extraHosts: [String!] + capAdd: [String!] + capDrop: [String!] + cpuPeriod: Int + cpuQuota: Int + cpuRealtimePeriod: Int + cpuRealtimeRuntime: Int + memoryReservation: Int + memorySwap: Int + memorySwappiness: Int + volumeDriver: String + storageOpt: [String!] + readOnlyRootfs: Boolean + tmpfs: [String!] + binds: [String!] +} + +input ReleaseCreateRequiredSystemModelsInput { + id: ID +} + +enum ContainerVolumeSortField { + TARGET + VOLUME_ID +} + +":container_volume connection" +type ContainerVolumeConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":container_volume edges" + edges: [ContainerVolumeEdge!] +} + +":container_volume edge" +type ContainerVolumeEdge { + "Cursor" + cursor: String! + + ":container_volume node" + node: ContainerVolume! +} + +input ContainerVolumeFilterVolumeId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ContainerVolumeFilterTarget { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ContainerVolumeFilterInput { + and: [ContainerVolumeFilterInput!] + or: [ContainerVolumeFilterInput!] + not: [ContainerVolumeFilterInput!] + target: ContainerVolumeFilterTarget + volumeId: ContainerVolumeFilterVolumeId + volume: VolumeFilterInput +} + +input ContainerVolumeSortInput { + order: SortOrder + field: ContainerVolumeSortField! +} + +type ContainerVolume { + "A unique identifier" + id: ID! + + target: String! + + volumeId: ID! + + volume: Volume! +} + +enum DeviceMappingDeploymentSortField { + ID + STATE + DEVICE_MAPPING_ID +} + +":device_mapping_deployment connection" +type DeviceMappingDeploymentConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":device_mapping_deployment edges" + edges: [DeviceMappingDeploymentEdge!] +} + +":device_mapping_deployment edge" +type DeviceMappingDeploymentEdge { + "Cursor" + cursor: String! + + ":device_mapping_deployment node" + node: DeviceMappingDeployment! +} + +input DeviceMappingDeploymentFilterDeviceMappingId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeviceMappingDeploymentFilterState { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String +} + +input DeviceMappingDeploymentFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeviceMappingDeploymentFilterInput { + and: [DeviceMappingDeploymentFilterInput!] + or: [DeviceMappingDeploymentFilterInput!] + not: [DeviceMappingDeploymentFilterInput!] + id: DeviceMappingDeploymentFilterId + state: DeviceMappingDeploymentFilterState + deviceMappingId: DeviceMappingDeploymentFilterDeviceMappingId + deviceMapping: DeviceMappingFilterInput + containerDeployments: ContainerDeploymentFilterInput +} + +input DeviceMappingDeploymentSortInput { + order: SortOrder + field: DeviceMappingDeploymentSortField! +} + +type DeviceMappingDeployment { + id: ID! + state: String + deviceMappingId: ID + deviceMapping: DeviceMapping + containerDeployments( + "How to sort the records in the response" + sort: [ContainerDeploymentSortInput] + + "A filter to limit the results" + filter: ContainerDeploymentFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [ContainerDeployment!]! +} + +enum DeviceMappingSortField { + ID + PATH_ON_HOST + PATH_IN_CONTAINER + CGROUP_PERMISSIONS + CONTAINER_ID +} + +":device_mapping connection" +type DeviceMappingConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":device_mapping edges" + edges: [DeviceMappingEdge!] +} + +":device_mapping edge" +type DeviceMappingEdge { + "Cursor" + cursor: String! + + ":device_mapping node" + node: DeviceMapping! +} + +input DeviceMappingFilterContainerId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeviceMappingFilterCgroupPermissions { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceMappingFilterPathInContainer { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceMappingFilterPathOnHost { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceMappingFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeviceMappingFilterInput { + and: [DeviceMappingFilterInput!] + or: [DeviceMappingFilterInput!] + not: [DeviceMappingFilterInput!] + id: DeviceMappingFilterId + pathOnHost: DeviceMappingFilterPathOnHost + pathInContainer: DeviceMappingFilterPathInContainer + cgroupPermissions: DeviceMappingFilterCgroupPermissions + containerId: DeviceMappingFilterContainerId + container: ContainerFilterInput +} + +input DeviceMappingSortInput { + order: SortOrder + field: DeviceMappingSortField! +} + +type DeviceMapping { + id: ID! + pathOnHost: String! + pathInContainer: String! + cgroupPermissions: String! + containerId: ID + container: Container +} + +enum VolumeDeploymentSortField { + ID + STATE + VOLUME_ID +} + +":volume_deployment connection" +type VolumeDeploymentConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":volume_deployment edges" + edges: [VolumeDeploymentEdge!] +} + +":volume_deployment edge" +type VolumeDeploymentEdge { + "Cursor" + cursor: String! + + ":volume_deployment node" + node: VolumeDeployment! +} + +input VolumeDeploymentFilterVolumeId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input VolumeDeploymentFilterState { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String +} + +input VolumeDeploymentFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input VolumeDeploymentFilterInput { + and: [VolumeDeploymentFilterInput!] + or: [VolumeDeploymentFilterInput!] + not: [VolumeDeploymentFilterInput!] + id: VolumeDeploymentFilterId + state: VolumeDeploymentFilterState + volumeId: VolumeDeploymentFilterVolumeId + volume: VolumeFilterInput + containerDeployments: ContainerDeploymentFilterInput +} + +input VolumeDeploymentSortInput { + order: SortOrder + field: VolumeDeploymentSortField! +} + +type VolumeDeployment { + id: ID! + state: String + volumeId: ID + volume: Volume + containerDeployments( + "How to sort the records in the response" + sort: [ContainerDeploymentSortInput] + + "A filter to limit the results" + filter: ContainerDeploymentFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [ContainerDeployment!]! +} + +"The result of the :delete_volume mutation" +type DeleteVolumeResult { + "The record that was successfully deleted" + result: Volume + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :create_volume mutation" +type CreateVolumeResult { + "The successful result of the mutation" + result: Volume + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateVolumeInput { + label: String! + driver: String + options: JsonString +} + +enum VolumeSortField { + ID + LABEL + DRIVER + OPTIONS +} + +":volume connection" +type VolumeConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":volume edges" + edges: [VolumeEdge!] +} + +":volume edge" +type VolumeEdge { + "Cursor" + cursor: String! + + ":volume node" + node: Volume! +} + +input VolumeFilterOptions { + isNil: Boolean + eq: JsonString + notEq: JsonString + in: [JsonString!] + lessThan: JsonString + greaterThan: JsonString + lessThanOrEqual: JsonString + greaterThanOrEqual: JsonString +} + +input VolumeFilterDriver { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input VolumeFilterLabel { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input VolumeFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input VolumeFilterInput { + and: [VolumeFilterInput!] + or: [VolumeFilterInput!] + not: [VolumeFilterInput!] + id: VolumeFilterId + label: VolumeFilterLabel + driver: VolumeFilterDriver + options: VolumeFilterOptions + devices: DeviceFilterInput +} + +input VolumeSortInput { + order: SortOrder + field: VolumeSortField! +} + +type Volume implements Node { + id: ID! + label: String! + driver: String! + options: JsonString! + devices( + "How to sort the records in the response" + sort: [DeviceSortInput] + + "A filter to limit the results" + filter: DeviceFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceConnection! +} + +enum NetworkDeploymentSortField { + ID + STATE + NETWORK_ID +} + +":network_deployment connection" +type NetworkDeploymentConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":network_deployment edges" + edges: [NetworkDeploymentEdge!] +} + +":network_deployment edge" +type NetworkDeploymentEdge { + "Cursor" + cursor: String! + + ":network_deployment node" + node: NetworkDeployment! +} + +input NetworkDeploymentFilterNetworkId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input NetworkDeploymentFilterState { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String +} + +input NetworkDeploymentFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input NetworkDeploymentFilterInput { + and: [NetworkDeploymentFilterInput!] + or: [NetworkDeploymentFilterInput!] + not: [NetworkDeploymentFilterInput!] + id: NetworkDeploymentFilterId + state: NetworkDeploymentFilterState + networkId: NetworkDeploymentFilterNetworkId + network: NetworkFilterInput + containerDeployments: ContainerDeploymentFilterInput +} + +input NetworkDeploymentSortInput { + order: SortOrder + field: NetworkDeploymentSortField! +} + +type NetworkDeployment { + id: ID! + state: String + networkId: ID + network: Network + containerDeployments( + "How to sort the records in the response" + sort: [ContainerDeploymentSortInput] + + "A filter to limit the results" + filter: ContainerDeploymentFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [ContainerDeployment!]! +} + +"The result of the :delete_network mutation" +type DeleteNetworkResult { + "The record that was successfully deleted" + result: Network + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :create_network mutation" +type CreateNetworkResult { + "The successful result of the mutation" + result: Network + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateNetworkInput { + label: String + driver: String + internal: Boolean + enableIpv6: Boolean + options: JsonString +} + +enum NetworkSortField { + ID + LABEL + DRIVER + INTERNAL + ENABLE_IPV6 + OPTIONS +} + +":network connection" +type NetworkConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":network edges" + edges: [NetworkEdge!] +} + +":network edge" +type NetworkEdge { + "Cursor" + cursor: String! + + ":network node" + node: Network! +} + +input NetworkFilterOptions { + isNil: Boolean + eq: JsonString + notEq: JsonString + in: [JsonString!] + lessThan: JsonString + greaterThan: JsonString + lessThanOrEqual: JsonString + greaterThanOrEqual: JsonString +} + +input NetworkFilterEnableIpv6 { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean +} + +input NetworkFilterInternal { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean +} + +input NetworkFilterDriver { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input NetworkFilterLabel { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input NetworkFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input NetworkFilterInput { + and: [NetworkFilterInput!] + or: [NetworkFilterInput!] + not: [NetworkFilterInput!] + id: NetworkFilterId + label: NetworkFilterLabel + driver: NetworkFilterDriver + internal: NetworkFilterInternal + enableIpv6: NetworkFilterEnableIpv6 + options: NetworkFilterOptions + containers: ContainerFilterInput + devices: DeviceFilterInput +} + +input NetworkSortInput { + order: SortOrder + field: NetworkSortField! +} + +type Network implements Node { + id: ID! + label: String + driver: String! + internal: Boolean! + enableIpv6: Boolean! + options: JsonString! + containers( + "How to sort the records in the response" + sort: [ContainerSortInput] + + "A filter to limit the results" + filter: ContainerFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ContainerConnection! + devices( + "How to sort the records in the response" + sort: [DeviceSortInput] + + "A filter to limit the results" + filter: DeviceFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceConnection! +} + +"The result of the :delete_release mutation" +type DeleteReleaseResult { + "The record that was successfully deleted" + result: Release + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :create_release mutation" +type CreateReleaseResult { + "The successful result of the mutation" + result: Release + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateReleaseInput { + version: String! + applicationId: ID + containers: [ReleaseCreateContainersInput!] + requiredSystemModels: [ReleaseCreateRequiredSystemModelsInput!] +} + +enum ReleaseSortField { + ID + VERSION + APPLICATION_ID +} + +":release connection" +type ReleaseConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":release edges" + edges: [ReleaseEdge!] +} + +":release edge" +type ReleaseEdge { + "Cursor" + cursor: String! + + ":release node" + node: Release! +} + +input ReleaseFilterApplicationId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ReleaseFilterVersion { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ReleaseFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ReleaseFilterInput { + and: [ReleaseFilterInput!] + or: [ReleaseFilterInput!] + not: [ReleaseFilterInput!] + id: ReleaseFilterId + version: ReleaseFilterVersion + applicationId: ReleaseFilterApplicationId + application: ApplicationFilterInput + deployments: DeploymentFilterInput + containers: ContainerFilterInput + systemModels: SystemModelFilterInput +} + +input ReleaseSortInput { + order: SortOrder + field: ReleaseSortField! +} + +type Release implements Node { + id: ID! + version: String! + applicationId: ID + application: Application + deployments( + "How to sort the records in the response" + sort: [DeploymentSortInput] + + "A filter to limit the results" + filter: DeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeploymentConnection! + containers( + "How to sort the records in the response" + sort: [ContainerSortInput] + + "A filter to limit the results" + filter: ContainerFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ContainerConnection! + systemModels( + "How to sort the records in the response" + sort: [SystemModelSortInput] + + "A filter to limit the results" + filter: SystemModelFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [SystemModel!]! +} + +"The result of the :delete_image_credentials mutation" +type DeleteImageCredentialsResult { + "The record that was successfully deleted" + result: ImageCredentials + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :create_image_credentials mutation" +type CreateImageCredentialsResult { + "The successful result of the mutation" + result: ImageCredentials + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateImageCredentialsInput { + label: String! + username: String! + password: String! +} + +enum ImageCredentialsSortField { + ID + LABEL + USERNAME +} + +":image_credentials connection" +type ImageCredentialsConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":image_credentials edges" + edges: [ImageCredentialsEdge!] +} + +":image_credentials edge" +type ImageCredentialsEdge { + "Cursor" + cursor: String! + + ":image_credentials node" + node: ImageCredentials! +} + +input ImageCredentialsFilterUsername { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ImageCredentialsFilterLabel { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ImageCredentialsFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ImageCredentialsFilterInput { + and: [ImageCredentialsFilterInput!] + or: [ImageCredentialsFilterInput!] + not: [ImageCredentialsFilterInput!] + id: ImageCredentialsFilterId + label: ImageCredentialsFilterLabel + username: ImageCredentialsFilterUsername +} + +input ImageCredentialsSortInput { + order: SortOrder + field: ImageCredentialsSortField! +} + +""" +Contains the credentials used to pull an image from a device. + +Credentials are uniquely identified trough their `:id`, a unique +`name` field is also provided. The module stores `username` and +`password` +""" +type ImageCredentials implements Node { + id: ID! + label: String! + username: String! +} + +input ImageDeploymentFilterImageId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ImageDeploymentFilterState { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String +} + +input ImageDeploymentFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ImageDeploymentFilterInput { + and: [ImageDeploymentFilterInput!] + or: [ImageDeploymentFilterInput!] + not: [ImageDeploymentFilterInput!] + id: ImageDeploymentFilterId + state: ImageDeploymentFilterState + imageId: ImageDeploymentFilterImageId + image: ImageFilterInput +} + +type ImageDeployment { + id: ID! + state: String + imageId: ID + image: Image +} + +input ImageFilterImageCredentialsId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ImageFilterReference { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ImageFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ImageFilterInput { + and: [ImageFilterInput!] + or: [ImageFilterInput!] + not: [ImageFilterInput!] + id: ImageFilterId + reference: ImageFilterReference + imageCredentialsId: ImageFilterImageCredentialsId + credentials: ImageCredentialsFilterInput + devices: DeviceFilterInput + containers: ContainerFilterInput +} + +type Image { + id: ID! + reference: String! + imageCredentialsId: ID + credentials: ImageCredentials + devices( + "How to sort the records in the response" + sort: [DeviceSortInput] + + "A filter to limit the results" + filter: DeviceFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceConnection! + containers( + "How to sort the records in the response" + sort: [ContainerSortInput] + + "A filter to limit the results" + filter: ContainerFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [Container!]! +} + +enum DeploymentEventSortField { + ID + TYPE + MESSAGE + INSERTED_AT + UPDATED_AT +} + +":deployment_event connection" +type DeploymentEventConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":deployment_event edges" + edges: [DeploymentEventEdge!] +} + +":deployment_event edge" +type DeploymentEventEdge { + "Cursor" + cursor: String! + + ":deployment_event node" + node: DeploymentEvent! +} + +input DeploymentEventFilterUpdatedAt { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime!] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input DeploymentEventFilterInsertedAt { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime!] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input DeploymentEventFilterMessage { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeploymentEventFilterType { + isNil: Boolean + eq: DeploymentEventType + notEq: DeploymentEventType + in: [DeploymentEventType!] + lessThan: DeploymentEventType + greaterThan: DeploymentEventType + lessThanOrEqual: DeploymentEventType + greaterThanOrEqual: DeploymentEventType +} + +input DeploymentEventFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeploymentEventFilterInput { + and: [DeploymentEventFilterInput!] + or: [DeploymentEventFilterInput!] + not: [DeploymentEventFilterInput!] + id: DeploymentEventFilterId + type: DeploymentEventFilterType + message: DeploymentEventFilterMessage + insertedAt: DeploymentEventFilterInsertedAt + updatedAt: DeploymentEventFilterUpdatedAt +} + +input DeploymentEventSortInput { + order: SortOrder + field: DeploymentEventSortField! +} + +type DeploymentEvent { + id: ID! + type: DeploymentEventType! + message: String + addInfo: [String!] + insertedAt: DateTime! + updatedAt: DateTime! +} + +"The result of the :upgrade_deployment mutation" +type UpgradeDeploymentResult { + "The successful result of the mutation" + result: Deployment + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpgradeDeploymentInput { + target: ID! +} + +"The result of the :send_deployment mutation" +type SendDeploymentResult { + "The successful result of the mutation" + result: Deployment + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :delete_deployment mutation" +type DeleteDeploymentResult { + "The successful result of the mutation" + result: Deployment + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :stop_deployment mutation" +type StopDeploymentResult { + "The successful result of the mutation" + result: Deployment + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :start_deployment mutation" +type StartDeploymentResult { + "The successful result of the mutation" + result: Deployment + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :deploy_release mutation" +type DeployReleaseResult { + "The successful result of the mutation" + result: Deployment + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input DeployReleaseInput { + releaseId: ID + deviceId: ID! +} + +enum DeploymentSortField { + ID + STATE + TIMED_OUT + DEVICE_ID + RELEASE_ID +} + +":deployment connection" +type DeploymentConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":deployment edges" + edges: [DeploymentEdge!] +} + +":deployment edge" +type DeploymentEdge { + "Cursor" + cursor: String! + + ":deployment node" + node: Deployment! +} + +input DeploymentFilterReleaseId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeploymentFilterDeviceId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input DeploymentFilterTimedOut { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean +} + +input DeploymentFilterState { + isNil: Boolean + eq: ApplicationDeploymentState + notEq: ApplicationDeploymentState + in: [ApplicationDeploymentState] + lessThan: ApplicationDeploymentState + greaterThan: ApplicationDeploymentState + lessThanOrEqual: ApplicationDeploymentState + greaterThanOrEqual: ApplicationDeploymentState +} + +input DeploymentFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input DeploymentFilterInput { + and: [DeploymentFilterInput!] + + or: [DeploymentFilterInput!] + + not: [DeploymentFilterInput!] + + id: DeploymentFilterId + + state: DeploymentFilterState + + timedOut: DeploymentFilterTimedOut + + deviceId: DeploymentFilterDeviceId + + releaseId: DeploymentFilterReleaseId + + device: DeviceFilterInput + + release: ReleaseFilterInput + + containerDeployments: ContainerDeploymentFilterInput + + events: DeploymentEventFilterInput + + """ + The deployment target of a deployment campaign that created this deployment. + Only returns targets for deploy and upgrade operation campaigns. + Returns nil for other operation types (start, stop, delete). + """ + campaignTarget: CampaignTargetFilterInput +} + +input DeploymentSortInput { + order: SortOrder + field: DeploymentSortField! +} + +type Deployment implements Node { + id: ID! + + state: ApplicationDeploymentState + + timedOut: Boolean! + + deviceId: Int + + releaseId: ID + + device: Device + + release: Release + + containerDeployments( + "How to sort the records in the response" + sort: [ContainerDeploymentSortInput] + + "A filter to limit the results" + filter: ContainerDeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ContainerDeploymentConnection! + + events( + "How to sort the records in the response" + sort: [DeploymentEventSortInput] + + "A filter to limit the results" + filter: DeploymentEventFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeploymentEventConnection! + + """ + The deployment target of a deployment campaign that created this deployment. + Only returns targets for deploy and upgrade operation campaigns. + Returns nil for other operation types (start, stop, delete). + """ + campaignTarget: CampaignTarget + + isReady: Boolean +} + +enum ContainerDeploymentSortField { + ID + STATE + CONTAINER_ID + DEVICE_ID + IMAGE_DEPLOYMENT_ID +} + +":container_deployment connection" +type ContainerDeploymentConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":container_deployment edges" + edges: [ContainerDeploymentEdge!] +} + +":container_deployment edge" +type ContainerDeploymentEdge { + "Cursor" + cursor: String! + + ":container_deployment node" + node: ContainerDeployment! +} + +input ContainerDeploymentFilterImageDeploymentId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ContainerDeploymentFilterDeviceId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerDeploymentFilterContainerId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ContainerDeploymentFilterState { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String +} + +input ContainerDeploymentFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ContainerDeploymentFilterInput { + and: [ContainerDeploymentFilterInput!] + or: [ContainerDeploymentFilterInput!] + not: [ContainerDeploymentFilterInput!] + id: ContainerDeploymentFilterId + state: ContainerDeploymentFilterState + containerId: ContainerDeploymentFilterContainerId + deviceId: ContainerDeploymentFilterDeviceId + imageDeploymentId: ContainerDeploymentFilterImageDeploymentId + container: ContainerFilterInput + device: DeviceFilterInput + imageDeployment: ImageDeploymentFilterInput + networkDeployments: NetworkDeploymentFilterInput + volumeDeployments: VolumeDeploymentFilterInput + deviceMappingDeployments: DeviceMappingDeploymentFilterInput +} + +input ContainerDeploymentSortInput { + order: SortOrder + field: ContainerDeploymentSortField! +} + +type ContainerDeployment { + id: ID! + state: String + containerId: ID + deviceId: Int + imageDeploymentId: ID + container: Container + device: Device + imageDeployment: ImageDeployment + networkDeployments( + "How to sort the records in the response" + sort: [NetworkDeploymentSortInput] + + "A filter to limit the results" + filter: NetworkDeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): NetworkDeploymentConnection! + volumeDeployments( + "How to sort the records in the response" + sort: [VolumeDeploymentSortInput] + + "A filter to limit the results" + filter: VolumeDeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): VolumeDeploymentConnection! + deviceMappingDeployments( + "How to sort the records in the response" + sort: [DeviceMappingDeploymentSortInput] + + "A filter to limit the results" + filter: DeviceMappingDeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceMappingDeploymentConnection! +} + +enum ContainerSortField { + ID + RESTART_POLICY + HOSTNAME + PRIVILEGED + NETWORK_MODE + CPU_PERIOD + CPU_QUOTA + CPU_REALTIME_PERIOD + CPU_REALTIME_RUNTIME + MEMORY + MEMORY_RESERVATION + MEMORY_SWAP + MEMORY_SWAPPINESS + VOLUME_DRIVER + READ_ONLY_ROOTFS + IMAGE_ID +} + +":container connection" +type ContainerConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":container edges" + edges: [ContainerEdge!] +} + +":container edge" +type ContainerEdge { + "Cursor" + cursor: String! + + ":container node" + node: Container! +} + +input ContainerFilterImageId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ContainerFilterReadOnlyRootfs { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean +} + +input ContainerFilterVolumeDriver { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ContainerFilterMemorySwappiness { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterMemorySwap { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterMemoryReservation { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterMemory { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterCpuRealtimeRuntime { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterCpuRealtimePeriod { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterCpuQuota { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterCpuPeriod { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ContainerFilterNetworkMode { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ContainerFilterPrivileged { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean +} + +input ContainerFilterHostname { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ContainerFilterRestartPolicy { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String +} + +input ContainerFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ContainerFilterInput { + and: [ContainerFilterInput!] + or: [ContainerFilterInput!] + not: [ContainerFilterInput!] + id: ContainerFilterId + restartPolicy: ContainerFilterRestartPolicy + hostname: ContainerFilterHostname + privileged: ContainerFilterPrivileged + networkMode: ContainerFilterNetworkMode + cpuPeriod: ContainerFilterCpuPeriod + cpuQuota: ContainerFilterCpuQuota + cpuRealtimePeriod: ContainerFilterCpuRealtimePeriod + cpuRealtimeRuntime: ContainerFilterCpuRealtimeRuntime + memory: ContainerFilterMemory + memoryReservation: ContainerFilterMemoryReservation + memorySwap: ContainerFilterMemorySwap + memorySwappiness: ContainerFilterMemorySwappiness + volumeDriver: ContainerFilterVolumeDriver + readOnlyRootfs: ContainerFilterReadOnlyRootfs + imageId: ContainerFilterImageId + image: ImageFilterInput + releases: ReleaseFilterInput + networks: NetworkFilterInput + devices: DeviceFilterInput + containerVolumes: ContainerVolumeFilterInput + deviceMappings: DeviceMappingFilterInput +} + +input ContainerSortInput { + order: SortOrder + field: ContainerSortField! +} + +type Container { + id: ID! + restartPolicy: String + portBindings: [String!]! + hostname: String! + env: [ContainerEnvVar!]! + privileged: Boolean + networkMode: String! + extraHosts: [String!]! + capAdd: [String!]! + capDrop: [String!]! + cpuPeriod: Int + cpuQuota: Int + cpuRealtimePeriod: Int + cpuRealtimeRuntime: Int + memory: Int + memoryReservation: Int + memorySwap: Int + memorySwappiness: Int + volumeDriver: String! + storageOpt: [String!]! + readOnlyRootfs: Boolean! + tmpfs: [String!]! + binds: [String!]! + imageId: ID! + image: Image! + releases( + "How to sort the records in the response" + sort: [ReleaseSortInput] + + "A filter to limit the results" + filter: ReleaseFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ReleaseConnection! + networks( + "How to sort the records in the response" + sort: [NetworkSortInput] + + "A filter to limit the results" + filter: NetworkFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): NetworkConnection! + devices( + "How to sort the records in the response" + sort: [DeviceSortInput] + + "A filter to limit the results" + filter: DeviceFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceConnection! + containerVolumes( + "How to sort the records in the response" + sort: [ContainerVolumeSortInput] + + "A filter to limit the results" + filter: ContainerVolumeFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ContainerVolumeConnection! + deviceMappings( + "How to sort the records in the response" + sort: [DeviceMappingSortInput] + + "A filter to limit the results" + filter: DeviceMappingFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceMappingConnection! +} + +"The result of the :delete_application mutation" +type DeleteApplicationResult { + "The record that was successfully deleted" + result: Application + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :create_application mutation" +type CreateApplicationResult { + "The successful result of the mutation" + result: Application + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateApplicationInput { + name: String! + description: String + initialRelease: ApplicationCreateInitialReleaseInput + systemModelId: ID +} + +enum ApplicationSortField { + ID + NAME + DESCRIPTION +} + +":application connection" +type ApplicationConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":application edges" + edges: [ApplicationEdge!] +} + +":application edge" +type ApplicationEdge { + "Cursor" + cursor: String! + + ":application node" + node: Application! +} + +input ApplicationFilterDescription { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ApplicationFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ApplicationFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input ApplicationFilterInput { + and: [ApplicationFilterInput!] + or: [ApplicationFilterInput!] + not: [ApplicationFilterInput!] + id: ApplicationFilterId + name: ApplicationFilterName + description: ApplicationFilterDescription + releases: ReleaseFilterInput +} + +input ApplicationSortInput { + order: SortOrder + field: ApplicationSortField! +} + +type Application implements Node { + id: ID! + name: String! + description: String + releases( + "How to sort the records in the response" + sort: [ReleaseSortInput] + + "A filter to limit the results" + filter: ReleaseFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ReleaseConnection! +} + +enum SystemModelPartNumberSortField { + ID + PART_NUMBER +} + +":system_model_part_number connection" +type SystemModelPartNumberConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":system_model_part_number edges" + edges: [SystemModelPartNumberEdge!] +} + +":system_model_part_number edge" +type SystemModelPartNumberEdge { + "Cursor" + cursor: String! + + ":system_model_part_number node" + node: SystemModelPartNumber! +} + +input SystemModelPartNumberFilterPartNumber { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input SystemModelPartNumberFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input SystemModelPartNumberFilterInput { + and: [SystemModelPartNumberFilterInput!] + + or: [SystemModelPartNumberFilterInput!] + + not: [SystemModelPartNumberFilterInput!] + + id: SystemModelPartNumberFilterId + + "The part number identifier." + partNumber: SystemModelPartNumberFilterPartNumber + + systemModel: SystemModelFilterInput +} + +input SystemModelPartNumberSortInput { + order: SortOrder + field: SystemModelPartNumberSortField! +} + +type SystemModelPartNumber { + id: ID! + + "The part number identifier." + partNumber: String! + + systemModel: SystemModel +} + +"The result of the :delete_system_model mutation" +type DeleteSystemModelResult { + "The record that was successfully deleted" + result: SystemModel + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :update_system_model mutation" +type UpdateSystemModelResult { + "The successful result of the mutation" + result: SystemModel + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateSystemModelInput { + """ + The identifier of the system model. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String + + "The display name of the system model." + name: String + + "A URL to a picture representing the system model." + pictureUrl: String + + "The list of part numbers associated with the system model." + partNumbers: [String!] + + "A picture representing the system model that will be uploaded to a bucket." + pictureFile: Upload + + """ + A list of descriptions in different languages. + + If a language already exists it is updated. If a null value is passed, the language + is deleted. + """ + localizedDescriptions: [LocalizedAttributeUpdateInput!] +} + +"The result of the :create_system_model mutation" +type CreateSystemModelResult { + "The successful result of the mutation" + result: SystemModel + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateSystemModelInput { + """ + The identifier of the system model. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The display name of the system model." + name: String! + + "A URL to a picture representing the system model." + pictureUrl: String + + "The ID of the hardware type that can be used by devices of this model" + hardwareTypeId: ID! + + "The list of part numbers associated with the system model." + partNumbers: [String!]! + + "A picture representing the system model that will be uploaded to a bucket." + pictureFile: Upload + + "A list of descriptions in different languages." + localizedDescriptions: [LocalizedAttributeInput!] +} + +enum SystemModelSortField { + ID + HANDLE + NAME + PICTURE_URL +} + +":system_model connection" +type SystemModelConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":system_model edges" + edges: [SystemModelEdge!] +} + +":system_model edge" +type SystemModelEdge { + "Cursor" + cursor: String! + + ":system_model node" + node: SystemModel! +} + +input SystemModelFilterPictureUrl { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input SystemModelFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input SystemModelFilterHandle { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input SystemModelFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input SystemModelFilterInput { + and: [SystemModelFilterInput!] + + or: [SystemModelFilterInput!] + + not: [SystemModelFilterInput!] + + id: SystemModelFilterId + + """ + The identifier of the system model. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: SystemModelFilterHandle + + "The display name of the system model." + name: SystemModelFilterName + + "A URL to a picture representing the system model." + pictureUrl: SystemModelFilterPictureUrl + + "The list of part numbers associated with the system model." + partNumbers: SystemModelPartNumberFilterInput + + "The Hardware type associated with the System Model" + hardwareType: HardwareTypeFilterInput + + "The various application releases that require the system model to be deployed." + releases: ReleaseFilterInput +} + +input SystemModelSortInput { + order: SortOrder + field: SystemModelSortField! +} + +""" +A system model corresponds to what the users thinks as functionally +equivalent devices (e.g. two revisions of a device containing two different +embedded chips but having the same enclosure and the same functionality). +Each SystemModel must be associated to a specific HardwareType. +""" +type SystemModel implements Node { + id: ID! + + """ + The identifier of the system model. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The display name of the system model." + name: String! + + "A URL to a picture representing the system model." + pictureUrl: String + + "The list of part numbers associated with the system model." + partNumbers( + "How to sort the records in the response" + sort: [SystemModelPartNumberSortInput] + + "A filter to limit the results" + filter: SystemModelPartNumberFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): SystemModelPartNumberConnection! + + "The Hardware type associated with the System Model" + hardwareType: HardwareType + + "The various application releases that require the system model to be deployed." + releases( + "How to sort the records in the response" + sort: [ReleaseSortInput] + + "A filter to limit the results" + filter: ReleaseFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [Release!]! + + "A list of descriptions in different languages." + localizedDescriptions(preferredLanguageTags: [String!]): [LocalizedAttribute!] +} + +enum HardwareTypePartNumberSortField { + ID + PART_NUMBER +} + +":hardware_type_part_number connection" +type HardwareTypePartNumberConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":hardware_type_part_number edges" + edges: [HardwareTypePartNumberEdge!] +} + +":hardware_type_part_number edge" +type HardwareTypePartNumberEdge { + "Cursor" + cursor: String! + + ":hardware_type_part_number node" + node: HardwareTypePartNumber! +} + +input HardwareTypePartNumberFilterPartNumber { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input HardwareTypePartNumberFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input HardwareTypePartNumberFilterInput { + and: [HardwareTypePartNumberFilterInput!] + + or: [HardwareTypePartNumberFilterInput!] + + not: [HardwareTypePartNumberFilterInput!] + + id: HardwareTypePartNumberFilterId + + "The part number identifier." + partNumber: HardwareTypePartNumberFilterPartNumber + + hardwareType: HardwareTypeFilterInput +} + +input HardwareTypePartNumberSortInput { + order: SortOrder + field: HardwareTypePartNumberSortField! +} + +type HardwareTypePartNumber { + id: ID! + + "The part number identifier." + partNumber: String! + + hardwareType: HardwareType +} + +"The result of the :delete_hardware_type mutation" +type DeleteHardwareTypeResult { + "The record that was successfully deleted" + result: HardwareType + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :update_hardware_type mutation" +type UpdateHardwareTypeResult { + "The successful result of the mutation" + result: HardwareType + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateHardwareTypeInput { + """ + The identifier of the hardware type. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String + + "The display name of the hardware type." + name: String + + "The list of part numbers associated with the hardware type." + partNumbers: [String!] +} + +"The result of the :create_hardware_type mutation" +type CreateHardwareTypeResult { + "The successful result of the mutation" + result: HardwareType + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateHardwareTypeInput { + """ + The identifier of the hardware type. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The display name of the hardware type." + name: String! + + partNumbers: [String!]! +} + +enum HardwareTypeSortField { + ID + HANDLE + NAME +} + +":hardware_type connection" +type HardwareTypeConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":hardware_type edges" + edges: [HardwareTypeEdge!] +} + +":hardware_type edge" +type HardwareTypeEdge { + "Cursor" + cursor: String! + + ":hardware_type node" + node: HardwareType! +} + +input HardwareTypeFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input HardwareTypeFilterHandle { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input HardwareTypeFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input HardwareTypeFilterInput { + and: [HardwareTypeFilterInput!] + + or: [HardwareTypeFilterInput!] + + not: [HardwareTypeFilterInput!] + + id: HardwareTypeFilterId + + """ + The identifier of the hardware type. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: HardwareTypeFilterHandle + + "The display name of the hardware type." + name: HardwareTypeFilterName + + "The list of part numbers associated with the hardware type." + partNumbers: HardwareTypePartNumberFilterInput +} + +input HardwareTypeSortInput { + order: SortOrder + field: HardwareTypeSortField! +} + +""" +Denotes a type of hardware that devices can have. + +It refers to the physical components embedded in a device. +This can represent, e.g., multiple revisions of a PCB (each with a +different part number) which are functionally equivalent from the device +point of view. +""" +type HardwareType implements Node { + id: ID! + + """ + The identifier of the hardware type. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The display name of the hardware type." + name: String! + + "The list of part numbers associated with the hardware type." + partNumbers( + "How to sort the records in the response" + sort: [HardwareTypePartNumberSortInput] + + "A filter to limit the results" + filter: HardwareTypePartNumberFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): HardwareTypePartNumberConnection! +} + +type device_changed_result { + created: Device + updated: Device +} + +"The result of the :set_device_led_behavior mutation" +type SetDeviceLedBehaviorResult { + "The successful result of the mutation" + result: Device + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input SetDeviceLedBehaviorInput { + "The led behavior." + behavior: DeviceLedBehavior! +} + +"The result of the :remove_device_tags mutation" +type RemoveDeviceTagsResult { + "The successful result of the mutation" + result: Device + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input RemoveDeviceTagsInput { + tags: [String!]! +} + +"The result of the :add_device_tags mutation" +type AddDeviceTagsResult { + "The successful result of the mutation" + result: Device + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input AddDeviceTagsInput { + tags: [String!]! +} + +"The result of the :update_device mutation" +type UpdateDeviceResult { + "The successful result of the mutation" + result: Device + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateDeviceInput { + "The display name of the device." + name: String +} + +enum DeviceSortField { + ID + DEVICE_ID + NAME + ONLINE + LAST_CONNECTION + LAST_DISCONNECTION + LAST_SEEN_IP + SERIAL_NUMBER + PART_NUMBER +} + +":device connection" +type DeviceConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":device edges" + edges: [DeviceEdge!] +} + +":device edge" +type DeviceEdge { + "Cursor" + cursor: String! + + ":device node" + node: Device! +} + +input DeviceFilterPartNumber { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceFilterSerialNumber { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceFilterLastSeenIp { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceFilterLastDisconnection { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input DeviceFilterLastConnection { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input DeviceFilterOnline { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean +} + +input DeviceFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceFilterDeviceId { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input DeviceFilterInput { + and: [DeviceFilterInput!] + + or: [DeviceFilterInput!] + + not: [DeviceFilterInput!] + + id: DeviceFilterId + + "The Astarte device ID of the device." + deviceId: DeviceFilterDeviceId + + "The display name of the device." + name: DeviceFilterName + + "Whether the device is connected or not to Astarte" + online: DeviceFilterOnline + + "The date at which the device last connected to Astarte." + lastConnection: DeviceFilterLastConnection + + "The date at which the device last disconnected from Astarte." + lastDisconnection: DeviceFilterLastDisconnection + + "The IP address at which the device last connected to Astarte." + lastSeenIp: DeviceFilterLastSeenIp + + "The serial number of the device." + serialNumber: DeviceFilterSerialNumber + + partNumber: DeviceFilterPartNumber + + "The system model of the device" + systemModel: SystemModelFilterInput + + "The tags of the device" + tags: TagFilterInput + + "The groups the device belongs to." + deviceGroups: DeviceGroupFilterInput + + "The existing OTA operations for this device" + otaOperations: OtaOperationFilterInput + + applicationDeployments: DeploymentFilterInput +} + +input DeviceSortInput { + order: SortOrder + field: DeviceSortField! +} + +""" +Denotes a device instance that connects and exchanges data. + +Each Device is associated to a specific SystemModel, which in turn is +associated to a specific HardwareType. +A Device also exposes info about its connection status and some sets of data read by its operating system. +""" +type Device implements Node { + id: ID! + + "The Astarte device ID of the device." + deviceId: String! + + "The display name of the device." + name: String! + + "Whether the device is connected or not to Astarte" + online: Boolean! + + "The date at which the device last connected to Astarte." + lastConnection: DateTime + + "The date at which the device last disconnected from Astarte." + lastDisconnection: DateTime + + "The IP address at which the device last connected to Astarte." + lastSeenIp: String + + "The serial number of the device." + serialNumber: String + + partNumber: String + + "The system model of the device" + systemModel: SystemModel + + "The tags of the device" + tags( + "How to sort the records in the response" + sort: [TagSortInput] + + "A filter to limit the results" + filter: TagFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): TagConnection! + + "The groups the device belongs to." + deviceGroups( + "How to sort the records in the response" + sort: [DeviceGroupSortInput] + + "A filter to limit the results" + filter: DeviceGroupFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [DeviceGroup!]! + + "The existing OTA operations for this device" + otaOperations( + "How to sort the records in the response" + sort: [OtaOperationSortInput] + + "A filter to limit the results" + filter: OtaOperationFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): OtaOperationConnection! + + applicationDeployments( + "How to sort the records in the response" + sort: [DeploymentSortInput] + + "A filter to limit the results" + filter: DeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeploymentConnection! + + availableImages: [ImageStatus!] + + availableVolumes: [VolumeStatus!] + + availableNetworks: [NetworkStatus!] + + "The capabilities that the device can support." + capabilities: [DeviceCapability!]! + + cellularConnection: [Modem!] + + availableDeployments: [DeploymentStatus!] + + baseImage: BaseImageInfo + + availableContainers: [ContainerStatus!] + + availableDeviceMappings: [DeviceMappingStatus!] + + batteryStatus: [BatterySlot!] + + hardwareInfo: HardwareInfo + + """ + Describes the place where the device is located. + + The field holds information about the device's address, which is + estimated by means of Edgehog's geolocation modules and the data + published by the device. + """ + location: Location + + networkInterfaces: [NetworkInterface!] + + osInfo: OsInfo + + """ + Describes the position of a device. + + The field holds information about the GPS coordinates of the device, + which are estimated by means of Edgehog's geolocation modules and the + data published by the device. + """ + position: Position + + runtimeInfo: RuntimeInfo + + storageUsage: [StorageUnit!] + + systemStatus: SystemStatus + + wifiScanResults: [WifiScanResult!] +} + +input RequestForwarderSessionInput { + deviceId: ID! +} + +"The details of a forwarder session." +type ForwarderSession { + "The token that identifies the session." + id: ID! + + "The token that identifies the session." + token: String! + + "The status of the session." + status: ForwarderSessionStatus! + + "The hostname of the forwarder instance." + forwarderHostname: String! + + "The port of the forwarder instance." + forwarderPort: Int! + + "Indicates if TLS is used when the device connects to the forwarder." + secure: Boolean! +} + +"The details of a forwarder instance." +type ForwarderConfig { + "A unique identifier" + id: ID! + + "The hostname of the forwarder instance." + hostname: String! + + "The port of the forwarder instance." + port: Int! + + "Indicates if TLS should used when connecting to the forwarder." + secureSessions: Boolean! +} + +"The result of the :delete_device_group mutation" +type DeleteDeviceGroupResult { + "The record that was successfully deleted" + result: DeviceGroup + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :update_device_group mutation" +type UpdateDeviceGroupResult { + "The successful result of the mutation" + result: DeviceGroup + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateDeviceGroupInput { + "The display name of the device group." + name: String + + """ + The identifier of the device group. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String + + """ + The Selector that will determine which devices belong to the device group. + + This must be a valid selector expression, consult the Selector section of the Edgehog documentation for more information about Selectors. + """ + selector: String +} + +"The result of the :create_device_group mutation" +type CreateDeviceGroupResult { + "The successful result of the mutation" + result: DeviceGroup + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateDeviceGroupInput { + "The display name of the device group." + name: String! + + """ + The identifier of the device group. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + """ + The Selector that will determine which devices belong to the device group. + + This must be a valid selector expression, consult the Selector section of the Edgehog documentation for more information about Selectors. + """ + selector: String! +} + +enum DeviceGroupSortField { + ID + NAME + HANDLE + SELECTOR +} + +":device_group connection" +type DeviceGroupConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":device_group edges" + edges: [DeviceGroupEdge!] +} + +":device_group edge" +type DeviceGroupEdge { + "Cursor" + cursor: String! + + ":device_group node" + node: DeviceGroup! +} + +input DeviceGroupFilterSelector { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceGroupFilterHandle { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceGroupFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input DeviceGroupFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input DeviceGroupFilterInput { + and: [DeviceGroupFilterInput!] + + or: [DeviceGroupFilterInput!] + + not: [DeviceGroupFilterInput!] + + id: DeviceGroupFilterId + + "The display name of the device group." + name: DeviceGroupFilterName + + """ + The identifier of the device group. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: DeviceGroupFilterHandle + + """ + The Selector that will determine which devices belong to the device group. + + This must be a valid selector expression, consult the Selector section of the Edgehog documentation for more information about Selectors. + """ + selector: DeviceGroupFilterSelector + + "The devices belonging to the group." + devices: DeviceFilterInput + + "The channel associated with the group, if present." + channel: ChannelFilterInput +} + +input DeviceGroupSortInput { + order: SortOrder + field: DeviceGroupSortField! +} + +type DeviceGroup implements Node { + id: ID! + + "The display name of the device group." + name: String! + + """ + The identifier of the device group. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + """ + The Selector that will determine which devices belong to the device group. + + This must be a valid selector expression, consult the Selector section of the Edgehog documentation for more information about Selectors. + """ + selector: String! + + "The devices belonging to the group." + devices( + "How to sort the records in the response" + sort: [DeviceSortInput] + + "A filter to limit the results" + filter: DeviceFilterInput + + "The number of records to return." + limit: Int + + "The number of records to skip." + offset: Int + ): [Device!]! + + "The channel associated with the group, if present." + channel: Channel +} + +enum TagSortField { + ID + NAME +} + +":tag connection" +type TagConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":tag edges" + edges: [TagEdge!] +} + +":tag edge" +type TagEdge { + "Cursor" + cursor: String! + + ":tag node" + node: Tag! +} + +input TagFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input TagFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input TagFilterInput { + and: [TagFilterInput!] + or: [TagFilterInput!] + not: [TagFilterInput!] + id: TagFilterId + name: TagFilterName +} + +input TagSortInput { + order: SortOrder + field: TagSortField! +} + +"A Tag that can be applied to a resource." +type Tag { + id: ID! + name: String! +} + +"The result of the :create_manual_ota_operation mutation" +type CreateManualOtaOperationResult { + "The successful result of the mutation" + result: OtaOperation + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateManualOtaOperationInput { + "The ID identifying the Device the OTA Operation will be sent to" + deviceId: ID! + + "The base image file, which will be uploaded to the storage." + baseImageFile: Upload! +} + +enum OtaOperationSortField { + ID + BASE_IMAGE_URL + STATUS + STATUS_PROGRESS + STATUS_CODE + MESSAGE + CREATED_AT + UPDATED_AT +} + +":ota_operation connection" +type OtaOperationConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":ota_operation edges" + edges: [OtaOperationEdge!] +} + +":ota_operation edge" +type OtaOperationEdge { + "Cursor" + cursor: String! + + ":ota_operation node" + node: OtaOperation! +} + +input OtaOperationFilterUpdatedAt { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime!] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input OtaOperationFilterCreatedAt { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime!] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input OtaOperationFilterMessage { + isNil: Boolean + eq: String + notEq: String + in: [String] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input OtaOperationFilterStatusCode { + isNil: Boolean + eq: OtaOperationStatusCode + notEq: OtaOperationStatusCode + in: [OtaOperationStatusCode] + lessThan: OtaOperationStatusCode + greaterThan: OtaOperationStatusCode + lessThanOrEqual: OtaOperationStatusCode + greaterThanOrEqual: OtaOperationStatusCode +} + +input OtaOperationFilterStatusProgress { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input OtaOperationFilterStatus { + isNil: Boolean + eq: OtaOperationStatus + notEq: OtaOperationStatus + in: [OtaOperationStatus!] + lessThan: OtaOperationStatus + greaterThan: OtaOperationStatus + lessThanOrEqual: OtaOperationStatus + greaterThanOrEqual: OtaOperationStatus +} + +input OtaOperationFilterBaseImageUrl { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input OtaOperationFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input OtaOperationFilterInput { + and: [OtaOperationFilterInput!] + + or: [OtaOperationFilterInput!] + + not: [OtaOperationFilterInput!] + + id: OtaOperationFilterId + + "The URL of the base image being installed on the device" + baseImageUrl: OtaOperationFilterBaseImageUrl + + "The current status of the operation" + status: OtaOperationFilterStatus + + "The percentage progress [0-100] for the current status" + statusProgress: OtaOperationFilterStatusProgress + + "The current status code of the operation" + statusCode: OtaOperationFilterStatusCode + + "A message with additional details about the current status" + message: OtaOperationFilterMessage + + "The creation timestamp of the operation" + createdAt: OtaOperationFilterCreatedAt + + "The timestamp of the last update to the operation" + updatedAt: OtaOperationFilterUpdatedAt + + "The device targeted from the operation" + device: DeviceFilterInput + + """ + The update target of an update campaign that created the managed + ota operation, if any. + """ + campaignTarget: CampaignTargetFilterInput +} + +input OtaOperationSortInput { + order: SortOrder + field: OtaOperationSortField! +} + +"An OTA update operation" +type OtaOperation { + id: ID! + + "The URL of the base image being installed on the device" + baseImageUrl: String! + + "The current status of the operation" + status: OtaOperationStatus! + + "The percentage progress [0-100] for the current status" + statusProgress: Int! + + "The current status code of the operation" + statusCode: OtaOperationStatusCode + + "A message with additional details about the current status" + message: String + + "The creation timestamp of the operation" + createdAt: DateTime! + + "The timestamp of the last update to the operation" + updatedAt: DateTime! + + "The device targeted from the operation" + device: Device! + + """ + The update target of an update campaign that created the managed + ota operation, if any. + """ + campaignTarget: CampaignTarget +} + +type TenantInfo { + id: ID! + + "The tenant name." + name: String! + + "The tenant slug." + slug: String! + + "The default locale supported by the tenant." + defaultLocale: String! +} + +"The result of the :delete_channel mutation" +type DeleteChannelResult { + "The record that was successfully deleted" + result: Channel + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +"The result of the :update_channel mutation" +type UpdateChannelResult { + "The successful result of the mutation" + result: Channel + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input UpdateChannelInput { + """ + The identifier of the channel. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String + + "The display name of the channel." + name: String + + "The IDs of the target groups that are targeted by this channel." + targetGroupIds: [ID!] +} + +"The result of the :create_channel mutation" +type CreateChannelResult { + "The successful result of the mutation" + result: Channel + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateChannelInput { + """ + The identifier of the channel. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The display name of the channel." + name: String! + + "The IDs of the target groups that are targeted by this channel." + targetGroupIds: [ID!] +} + +enum ChannelSortField { + ID + HANDLE + NAME +} + +":channel connection" +type ChannelConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":channel edges" + edges: [ChannelEdge!] +} + +":channel edge" +type ChannelEdge { + "Cursor" + cursor: String! + + ":channel node" + node: Channel! +} + +input ChannelFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ChannelFilterHandle { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input ChannelFilterId { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input ChannelFilterInput { + and: [ChannelFilterInput!] + + or: [ChannelFilterInput!] + + not: [ChannelFilterInput!] + + id: ChannelFilterId + + """ + The identifier of the channel. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: ChannelFilterHandle + + "The display name of the channel." + name: ChannelFilterName + + "The device groups targeted by the channel." + targetGroups: DeviceGroupFilterInput + + campaigns: CampaignFilterInput +} + +input ChannelSortInput { + order: SortOrder + field: ChannelSortField! +} + +""" +Represents an Channel. + +An Channel represents a set of device groups that can be targeted in an Campaign. +""" +type Channel implements Node { + id: ID! + + """ + The identifier of the channel. + + It should start with a lower case ASCII letter and only contain lower case ASCII letters, digits and the hyphen - symbol. + """ + handle: String! + + "The display name of the channel." + name: String! + + "The device groups targeted by the channel." + targetGroups( + "How to sort the records in the response" + sort: [DeviceGroupSortInput] + + "A filter to limit the results" + filter: DeviceGroupFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceGroupConnection! + + campaigns( + "How to sort the records in the response" + sort: [CampaignSortInput] + + "A filter to limit the results" + filter: CampaignFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): CampaignConnection! +} + +enum CampaignTargetSortField { + ID + STATUS + RETRY_COUNT + LATEST_ATTEMPT + COMPLETION_TIMESTAMP +} + +":campaign_target connection" +type CampaignTargetConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":campaign_target edges" + edges: [CampaignTargetEdge!] +} + +":campaign_target edge" +type CampaignTargetEdge { + "Cursor" + cursor: String! + + ":campaign_target node" + node: CampaignTarget! +} + +input CampaignTargetFilterCompletionTimestamp { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input CampaignTargetFilterLatestAttempt { + isNil: Boolean + eq: DateTime + notEq: DateTime + in: [DateTime] + lessThan: DateTime + greaterThan: DateTime + lessThanOrEqual: DateTime + greaterThanOrEqual: DateTime +} + +input CampaignTargetFilterRetryCount { + isNil: Boolean + eq: Int + notEq: Int + in: [Int!] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input CampaignTargetFilterStatus { + isNil: Boolean + eq: CampaignTargetStatus + notEq: CampaignTargetStatus + in: [CampaignTargetStatus!] + lessThan: CampaignTargetStatus + greaterThan: CampaignTargetStatus + lessThanOrEqual: CampaignTargetStatus + greaterThanOrEqual: CampaignTargetStatus +} + +input CampaignTargetFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input CampaignTargetFilterInput { + and: [CampaignTargetFilterInput!] + + or: [CampaignTargetFilterInput!] + + not: [CampaignTargetFilterInput!] + + id: CampaignTargetFilterId + + "The status of the campaign target." + status: CampaignTargetFilterStatus + + """ + The number of retries of the campaign target. This indicated how many times + Edgehog retried to send all the necessary information about an operation towards + the device without receiving acks. + """ + retryCount: CampaignTargetFilterRetryCount + + "The timestamp of the latest attempt to deploy to the campaign target." + latestAttempt: CampaignTargetFilterLatestAttempt + + """ + The timestamp when the campaign target completed its update, either with + a success or a failure. + """ + completionTimestamp: CampaignTargetFilterCompletionTimestamp + + campaign: CampaignFilterInput + + device: DeviceFilterInput + + deployment: DeploymentFilterInput + + otaOperation: OtaOperationFilterInput +} + +input CampaignTargetSortInput { + order: SortOrder + field: CampaignTargetSortField! +} + +""" +Represents a CampaignTarget. + +Campaign targets are the targets of a Campaign, which is composed +by the target device and the state of the target in the linked +Campaign +""" +type CampaignTarget { + id: ID! + + "The status of the campaign target." + status: CampaignTargetStatus! + + """ + The number of retries of the campaign target. This indicated how many times + Edgehog retried to send all the necessary information about an operation towards + the device without receiving acks. + """ + retryCount: Int! + + "The timestamp of the latest attempt to deploy to the campaign target." + latestAttempt: DateTime + + """ + The timestamp when the campaign target completed its update, either with + a success or a failure. + """ + completionTimestamp: DateTime + + campaign: Campaign! + + device: Device! + + deployment: Deployment + + otaOperation: OtaOperation +} + +"The result of the :create_campaign mutation" +type CreateCampaignResult { + "The successful result of the mutation" + result: Campaign + + "Any errors generated, if the mutation failed" + errors: [MutationError!]! +} + +input CreateCampaignInput { + name: String! + + "The campaign mechanism to carry the campaign." + campaignMechanism: CampaignMechanismInput! + + "The ID of the channel that will be targeted by the campaign." + channelId: ID! +} + +enum CampaignSortField { + ID + NAME + STATUS + OUTCOME + TOTAL_TARGET_COUNT + IDLE_TARGET_COUNT + IN_PROGRESS_TARGET_COUNT + FAILED_TARGET_COUNT + SUCCESSFUL_TARGET_COUNT +} + +":campaign connection" +type CampaignConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":campaign edges" + edges: [CampaignEdge!] +} + +":campaign edge" +type CampaignEdge { + "Cursor" + cursor: String! + + ":campaign node" + node: Campaign! +} + +input CampaignFilterSuccessfulTargetCount { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input CampaignFilterFailedTargetCount { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input CampaignFilterInProgressTargetCount { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input CampaignFilterIdleTargetCount { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input CampaignFilterTotalTargetCount { + isNil: Boolean + eq: Int + notEq: Int + in: [Int] + lessThan: Int + greaterThan: Int + lessThanOrEqual: Int + greaterThanOrEqual: Int +} + +input CampaignFilterOutcome { + isNil: Boolean + eq: CampaignOutcome + notEq: CampaignOutcome + in: [CampaignOutcome] + lessThan: CampaignOutcome + greaterThan: CampaignOutcome + lessThanOrEqual: CampaignOutcome + greaterThanOrEqual: CampaignOutcome +} + +input CampaignFilterStatus { + isNil: Boolean + eq: CampaignStatus + notEq: CampaignStatus + in: [CampaignStatus!] + lessThan: CampaignStatus + greaterThan: CampaignStatus + lessThanOrEqual: CampaignStatus + greaterThanOrEqual: CampaignStatus +} + +input CampaignFilterName { + isNil: Boolean + eq: String + notEq: String + in: [String!] + lessThan: String + greaterThan: String + lessThanOrEqual: String + greaterThanOrEqual: String + like: String + ilike: String +} + +input CampaignFilterId { + isNil: Boolean + eq: ID + notEq: ID + in: [ID!] + lessThan: ID + greaterThan: ID + lessThanOrEqual: ID + greaterThanOrEqual: ID +} + +input CampaignFilterInput { + and: [CampaignFilterInput!] + + or: [CampaignFilterInput!] + + not: [CampaignFilterInput!] + + id: CampaignFilterId + + name: CampaignFilterName + + "The status of the campaign." + status: CampaignFilterStatus + + "The outcome of the campaign." + outcome: CampaignFilterOutcome + + "The channel associated with the campaign." + channel: ChannelFilterInput + + "The campaign targets belonging to the campaign." + campaignTargets: CampaignTargetFilterInput + + "The total number of campaign targets." + totalTargetCount: CampaignFilterTotalTargetCount + + "The number of campaign targets with an idle status." + idleTargetCount: CampaignFilterIdleTargetCount + + "The number of campaign targets with an in-progress status." + inProgressTargetCount: CampaignFilterInProgressTargetCount + + "The number of campaign targets with a failed status." + failedTargetCount: CampaignFilterFailedTargetCount + + "The number of campaign targets with a successful status." + successfulTargetCount: CampaignFilterSuccessfulTargetCount +} + +input CampaignSortInput { + order: SortOrder + field: CampaignSortField! +} + +type Campaign implements Node { + id: ID! + + name: String! + + "The status of the campaign." + status: CampaignStatus! + + "The outcome of the campaign." + outcome: CampaignOutcome + + "The campaign mechanism to carry the campaign." + campaignMechanism: CampaignMechanism! + + "The channel associated with the campaign." + channel: Channel! + + "The campaign targets belonging to the campaign." + campaignTargets( + "How to sort the records in the response" + sort: [CampaignTargetSortInput] + + "A filter to limit the results" + filter: CampaignTargetFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): CampaignTargetConnection! + + "The total number of campaign targets." + totalTargetCount: Int! + + "The number of campaign targets with an idle status." + idleTargetCount: Int! + + "The number of campaign targets with an in-progress status." + inProgressTargetCount: Int! + + "The number of campaign targets with a failed status." + failedTargetCount: Int! + + "The number of campaign targets with a successful status." + successfulTargetCount: Int! +} + +type RootQueryType { + "Returns the desired campaign." + campaign( + "The id of the record" + id: ID! + ): Campaign + + "Returns all update campaigns." + updateCampaigns( + "How to sort the records in the response" + sort: [CampaignSortInput] + + "A filter to limit the results" + filter: CampaignFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + + types: [String!] + ): CampaignConnection + + "Returns all deployment campaigns." + deploymentCampaigns( + "How to sort the records in the response" + sort: [CampaignSortInput] + + "A filter to limit the results" + filter: CampaignFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + + types: [String!] + ): CampaignConnection + + "Returns all available campaigns." + campaigns( + "How to sort the records in the response" + sort: [CampaignSortInput] + + "A filter to limit the results" + filter: CampaignFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): CampaignConnection + + "Returns a single channel." + channel( + "The id of the record" + id: ID! + ): Channel + + "Returns a list of channels." + channels( + "How to sort the records in the response" + sort: [ChannelSortInput] + + "A filter to limit the results" + filter: ChannelFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ChannelConnection + + "Retrieves the current tenant." + tenantInfo: TenantInfo! + + "Returns the list of device tags associated to some device group." + existingDeviceTags( + "How to sort the records in the response" + sort: [TagSortInput] + + "A filter to limit the results" + filter: TagFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): TagConnection + + "Returns a single device group." + deviceGroup( + "The id of the record" + id: ID! + ): DeviceGroup + + "Returns a list of device groups." + deviceGroups( + "How to sort the records in the response" + sort: [DeviceGroupSortInput] + + "A filter to limit the results" + filter: DeviceGroupFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceGroupConnection + + """ + Fetches the forwarder config, if available. + Without a configuration, forwarding functionalities are not available. + """ + forwarderConfig: ForwarderConfig + + "Fetches a forwarder session by its token and the device ID." + forwarderSession(token: String!, deviceId: ID!): ForwarderSession + + "Returns a single device." + device( + "The id of the record" + id: ID! + ): Device + + "Returns a list of devices." + devices( + "How to sort the records in the response" + sort: [DeviceSortInput] + + "A filter to limit the results" + filter: DeviceFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeviceConnection + + "Returns a single hardware type." + hardwareType( + "The id of the record" + id: ID! + ): HardwareType + + "Returns a list of hardware types." + hardwareTypes( + "How to sort the records in the response" + sort: [HardwareTypeSortInput] + + "A filter to limit the results" + filter: HardwareTypeFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): HardwareTypeConnection + + "Returns a single system model." + systemModel( + "The id of the record" + id: ID! + ): SystemModel + + "Returns a list of system models." + systemModels( + "How to sort the records in the response" + sort: [SystemModelSortInput] + + "A filter to limit the results" + filter: SystemModelFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): SystemModelConnection + + "Returns all the available applications." + applications( + "How to sort the records in the response" + sort: [ApplicationSortInput] + + "A filter to limit the results" + filter: ApplicationFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ApplicationConnection + + "Returns the desired application." + application( + "The id of the record" + id: ID! + ): Application + + "Returns all available deployments." + deployments( + "How to sort the records in the response" + sort: [DeploymentSortInput] + + "A filter to limit the results" + filter: DeploymentFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): DeploymentConnection + + "Returns the desired deployment." + deployment( + "The id of the record" + id: ID! + ): Deployment + + "Returns the desired image credentials." + imageCredentials( + "The id of the record" + id: ID! + ): ImageCredentials + + "Returns all available image credentials." + listImageCredentials( + "How to sort the records in the response" + sort: [ImageCredentialsSortInput] + + "A filter to limit the results" + filter: ImageCredentialsFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): ImageCredentialsConnection + + "Returns the desired release." + release( + "The id of the record" + id: ID! + ): Release + + "Returns the desired network." + network( + "The id of the record" + id: ID! + ): Network + + "Returns all available networks." + networks( + "How to sort the records in the response" + sort: [NetworkSortInput] + + "A filter to limit the results" + filter: NetworkFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): NetworkConnection + + "Returns the desired volume." + volume( + "The id of the record" + id: ID! + ): Volume + + "Returns all available volumes." + volumes( + "How to sort the records in the response" + sort: [VolumeSortInput] + + "A filter to limit the results" + filter: VolumeFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): VolumeConnection + + "Retrieves a Node from its global id" + node( + "The Node unique identifier" + id: ID! + ): Node! + + "Returns a single base image." + baseImage( + "The id of the record" + id: ID! + ): BaseImage + + "Returns a single base image collection." + baseImageCollection( + "The id of the record" + id: ID! + ): BaseImageCollection + + "Returns a list of base image collections." + baseImageCollections( + "How to sort the records in the response" + sort: [BaseImageCollectionSortInput] + + "A filter to limit the results" + filter: BaseImageCollectionFilterInput + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): BaseImageCollectionConnection +} + +type RootMutationType { + "Creates a new campaign." + createCampaign(input: CreateCampaignInput!): CreateCampaignResult + + "Creates a new channel." + createChannel(input: CreateChannelInput!): CreateChannelResult + + "Updates an channel." + updateChannel(id: ID!, input: UpdateChannelInput): UpdateChannelResult + + "Deletes an channel." + deleteChannel(id: ID!): DeleteChannelResult + + "Initiates an OTA update with a user provided OS image" + createManualOtaOperation(input: CreateManualOtaOperationInput!): CreateManualOtaOperationResult + + "Creates a new device group." + createDeviceGroup(input: CreateDeviceGroupInput!): CreateDeviceGroupResult + + "Updates a device group." + updateDeviceGroup(id: ID!, input: UpdateDeviceGroupInput): UpdateDeviceGroupResult + + "Deletes a device group." + deleteDeviceGroup(id: ID!): DeleteDeviceGroupResult + + """ + Requests a forwarder session for the specified device. + Returns the session token. + """ + requestForwarderSession(input: RequestForwarderSessionInput!): String! + + "Updates a device." + updateDevice(id: ID!, input: UpdateDeviceInput): UpdateDeviceResult + + "Add tags to a device." + addDeviceTags(id: ID!, input: AddDeviceTagsInput!): AddDeviceTagsResult + + "Remove tags from a device." + removeDeviceTags(id: ID!, input: RemoveDeviceTagsInput!): RemoveDeviceTagsResult + + "Sets led behavior." + setDeviceLedBehavior(id: ID!, input: SetDeviceLedBehaviorInput!): SetDeviceLedBehaviorResult + + "Creates a hardware type." + createHardwareType(input: CreateHardwareTypeInput!): CreateHardwareTypeResult + + "Updates a hardware type." + updateHardwareType(id: ID!, input: UpdateHardwareTypeInput): UpdateHardwareTypeResult + + "Deletes a hardware type." + deleteHardwareType(id: ID!): DeleteHardwareTypeResult + + "Creates a system model." + createSystemModel(input: CreateSystemModelInput!): CreateSystemModelResult + + "Updates an system model." + updateSystemModel(id: ID!, input: UpdateSystemModelInput): UpdateSystemModelResult + + "Deletes a system model." + deleteSystemModel(id: ID!): DeleteSystemModelResult + + "Create a new application." + createApplication(input: CreateApplicationInput!): CreateApplicationResult + + deleteApplication(id: ID!): DeleteApplicationResult + + "Deploy the application on a device" + deployRelease(input: DeployReleaseInput!): DeployReleaseResult + + "Sends a :start command to the release on the device." + startDeployment(id: ID!): StartDeploymentResult + + "Sends a :stop command to the release on the device." + stopDeployment(id: ID!): StopDeploymentResult + + "Sends a :delete command to the release on the device." + deleteDeployment(id: ID!): DeleteDeploymentResult + + """ + Sends the deployment to the device. + Deploys the necessary resources and sends the deployment request. + """ + sendDeployment(id: ID!): SendDeploymentResult + + upgradeDeployment(id: ID!, input: UpgradeDeploymentInput!): UpgradeDeploymentResult + + "Create image credentials." + createImageCredentials(input: CreateImageCredentialsInput!): CreateImageCredentialsResult + + deleteImageCredentials(id: ID!): DeleteImageCredentialsResult + + "Create a new release." + createRelease(input: CreateReleaseInput!): CreateReleaseResult + + "Delete a release and cleanup dangling resources" + deleteRelease(id: ID!): DeleteReleaseResult + + "Create a new network." + createNetwork(input: CreateNetworkInput): CreateNetworkResult + + "Delete a network if not used by any container." + deleteNetwork(id: ID!): DeleteNetworkResult + + "Create a new volume." + createVolume(input: CreateVolumeInput!): CreateVolumeResult + + "Delete a volume if not used by any container." + deleteVolume(id: ID!): DeleteVolumeResult + + "Create a new base image in a base image collection." + createBaseImage(input: CreateBaseImageInput!): CreateBaseImageResult + + "Updates a base image." + updateBaseImage(id: ID!, input: UpdateBaseImageInput): UpdateBaseImageResult + + "Deletes a base image." + deleteBaseImage(id: ID!): DeleteBaseImageResult + + "Creates a new base image collection." + createBaseImageCollection(input: CreateBaseImageCollectionInput!): CreateBaseImageCollectionResult + + "Updates a base image collection." + updateBaseImageCollection(id: ID!, input: UpdateBaseImageCollectionInput): UpdateBaseImageCollectionResult + + "Deletes a base image collection." + deleteBaseImageCollection(id: ID!): DeleteBaseImageCollectionResult +} + +type RootSubscriptionType { + deviceChanged( + "A filter to limit the results" + filter: DeviceFilterInput + ): device_changed_result +} + +""" +The `Json` scalar type represents arbitrary json string data, represented as UTF-8 +character sequences. The Json type is most often used to represent a free-form +human-readable json string. +""" +scalar JsonString + +""" +The `Json` scalar type represents arbitrary json string data, represented as UTF-8 +character sequences. The Json type is most often used to represent a free-form +human-readable json string. +""" +scalar Json + +""" +The `DateTime` scalar type represents a date and time in the UTC +timezone. The DateTime appears in a JSON response as an ISO8601 formatted +string, including UTC timezone ("Z"). The parsed date and time string will +be converted to UTC if there is an offset. +""" +scalar DateTime + +"Represents an uploaded file." +scalar Upload + +""" +Describes hardware-related info of a device. + +It exposes data read by a device's operating system about the underlying hardware. +""" +type HardwareInfo { + "The architecture of the CPU." + cpuArchitecture: String + + "The reference code of the CPU model." + cpuModel: String + + "The display name of the CPU model." + cpuModelName: String + + "The vendor's name." + cpuVendor: String + + "The Bytes count of memory." + memoryTotalBytes: Int +} + +"Describes the current usage of a storage unit on a device." +type StorageUnit { + "The label of the storage unit." + label: String! + + "The total number of bytes of the storage unit." + totalBytes: Int + + "The number of free bytes of the storage unit." + freeBytes: Int +} + +"Describes the information on the system's base image for a device." +type BaseImageInfo { + "The name of the image." + name: String + + "The version of the image." + version: String + + "Human readable build identifier of the image." + buildId: String + + "A unique string that identifies the release, usually the image hash." + fingerprint: String +} + +"Describes an operating system of a device." +type OsInfo { + "The name of the operating system." + name: String + + "The version of the operating system." + version: String +} + +"Describes the current status of the operating system of a device." +type SystemStatus { + "The identifier of the performed boot sequence." + bootId: String + + "The number of free bytes of memory." + memoryFreeBytes: Int + + "The number of running tasks on the system." + taskCount: Int + + "The number of milliseconds since the last system boot." + uptimeMilliseconds: Int + + "The date at which the system status was read." + timestamp: DateTime! +} + +"Describes the list of WiFi Access Points found by the device." +type WifiScanResult { + "The channel used by the Access Point." + channel: Int + + "Indicates whether the device is connected to the Access Point." + connected: Boolean + + "The ESSID advertised by the Access Point." + essid: String + + "The MAC address advertised by the Access Point." + macAddress: String + + "The power of the radio signal, measured in dBm." + rssi: Int + + "The date at which the device found the Access Point." + timestamp: DateTime! +} + +"Describes the status of a container on a device." +type ContainerStatus { + "The identifier of the container." + id: String + + "The status of the container." + status: String +} + +"Describes an Edgehog runtime." +type RuntimeInfo { + "The name of the Edgehog runtime." + name: String + + "The version of the Edgehog runtime." + version: String + + "The environment of the Edgehog runtime." + environment: String + + "The URL that uniquely identifies the Edgehog runtime implementation." + url: String +} + +"Describe the available images on the device." +type ImageStatus { + "The image id." + id: String + + "Whether the image is pulled or not." + pulled: Boolean +} + +"Describes the status of a deployment on a device." +type DeploymentStatus { + "The deployment id." + id: String + + "The deployment status, can be :stopped or :started" + status: String +} + +"Describes the status of a volume on a device." +type VolumeStatus { + "The volume id." + id: String + + "The volume status, whether it was created or not." + created: Boolean +} + +"Describe the available networks on the device." +type NetworkStatus { + "The network id." + id: String + + "Whether the network has been created." + created: Boolean +} + +"Describe the available device mappings on the device." +type DeviceMappingStatus { + "The device mapping id." + id: String + + "Whether the device referenced in the mapping is present or not." + present: Boolean +} diff --git a/tools/e2e_test/graphql/schema.graphql.license b/tools/e2e_test/graphql/schema.graphql.license new file mode 100644 index 000000000..5647f82a7 --- /dev/null +++ b/tools/e2e_test/graphql/schema.graphql.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2025 SECO Mind Srl + +SPDX-License-Identifier: Apache-2.0 diff --git a/tools/e2e_test/src/image_credentials/mod.rs b/tools/e2e_test/src/image_credentials/mod.rs new file mode 100644 index 000000000..d139beda2 --- /dev/null +++ b/tools/e2e_test/src/image_credentials/mod.rs @@ -0,0 +1,70 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use mutations::create_image_credentials::CreateImageCredentials; +use queries::get_image_credentials::GetImageCredentials; +use rand::distr::{Alphabetic, SampleString}; + +use crate::suite::client; + +pub mod mutations; +pub mod queries; + +pub async fn run_test(client: client::EdgehogClient) -> eyre::Result<()> { + let username = Alphabetic.sample_string(&mut rand::rng(), 5); + let label = Alphabetic.sample_string(&mut rand::rng(), 5); + let password = Alphabetic.sample_string(&mut rand::rng(), 10); + + let image_credentials_result = CreateImageCredentials::create_image_credentials( + &client, + &username, + &password, + &label + ) + .await?; + + assert_eq!(image_credentials_result.errors, None); + + let created_credentials = + image_credentials_result + .data + .expect("Error wile unwrapping image credentials creation result") + .create_image_credentials + .expect("Error while unwrapping image credentials creation result") + .result + .expect("Error while unwrapping image credentials creation result"); + + assert_eq!(username, created_credentials.username); + assert_eq!(label, created_credentials.label); + + let id = created_credentials.id.clone(); + + let image_credentials = + GetImageCredentials::get_image_credentials(&client, &id).await? + .data + .expect(format!("Error while retrieving image credentials with id {}", &id).as_str()) + .image_credentials + .expect(format!("Error while retrieving image credentials with id {}", &id).as_str()); + + assert_eq!(image_credentials.username, username); + assert_eq!(image_credentials.label, label); + + println!("[ PASSED ] image credentials tests"); + + Ok(()) +} diff --git a/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs b/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs new file mode 100644 index 000000000..885294b36 --- /dev/null +++ b/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs @@ -0,0 +1,52 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use create_image_credentials::{CreateImageCredentialsInput, ResponseData, Variables}; +use graphql_client::{GraphQLQuery, Response}; +use std::fmt::Debug; + +use crate::suite::client::EdgehogClient; + +// The paths are relative to the directory where your `Cargo.toml` is located. +// Both json and the GraphQL schema language are supported as sources for the schema +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/mutations/create_image_credentials.graphql", + response_derives = "Debug" +)] +pub struct CreateImageCredentials; + +impl CreateImageCredentials { + pub async fn create_image_credentials( + client: &EdgehogClient, + username: &String, + password: &String, + label: &String, + ) -> eyre::Result> { + // this is the important line + let input = CreateImageCredentialsInput { + username: String::from(username), + label: String::from(label), + password: String::from(password), + }; + let variables = Variables { input }; + let request_body = CreateImageCredentials::build_query(variables); + client.send(&request_body) .await + } +} diff --git a/tools/e2e_test/src/image_credentials/mutations/mod.rs b/tools/e2e_test/src/image_credentials/mutations/mod.rs new file mode 100644 index 000000000..4f92f6e5a --- /dev/null +++ b/tools/e2e_test/src/image_credentials/mutations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pub mod create_image_credentials; diff --git a/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs b/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs new file mode 100644 index 000000000..f04924a0c --- /dev/null +++ b/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs @@ -0,0 +1,45 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use get_image_credentials::{ResponseData, Variables}; +use graphql_client::{GraphQLQuery, Response}; +use std::fmt::Debug; + +use crate::suite::client::EdgehogClient; + +// The paths are relative to the directory where your `Cargo.toml` is located. +// Both json and the GraphQL schema language are supported as sources for the schema +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/image_credentials.graphql", + response_derives = "Debug" +)] +pub struct GetImageCredentials; + +impl GetImageCredentials { + pub async fn get_image_credentials( + client: &EdgehogClient, + id: &String, + ) -> eyre::Result> { + // this is the important line + let variables = Variables { id: String::from(id) }; + let request_body = GetImageCredentials::build_query(variables); + client.send(&request_body).await + } +} diff --git a/tools/e2e_test/src/image_credentials/queries/mod.rs b/tools/e2e_test/src/image_credentials/queries/mod.rs new file mode 100644 index 000000000..6d17b8e0c --- /dev/null +++ b/tools/e2e_test/src/image_credentials/queries/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pub mod get_image_credentials; diff --git a/tools/e2e_test/src/main.rs b/tools/e2e_test/src/main.rs index e7a11a969..73098b973 100644 --- a/tools/e2e_test/src/main.rs +++ b/tools/e2e_test/src/main.rs @@ -1,3 +1,31 @@ -fn main() { - println!("Hello, world!"); +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +mod image_credentials; +mod suite; + +use clap::Parser; +use suite::client::EdgehogClient; +use suite::config::Config; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let config = Config::parse(); + let client = EdgehogClient::create(&config)?; + image_credentials::run_test(client).await } diff --git a/tools/e2e_test/src/suite/client.rs b/tools/e2e_test/src/suite/client.rs new file mode 100644 index 000000000..585199db3 --- /dev/null +++ b/tools/e2e_test/src/suite/client.rs @@ -0,0 +1,54 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use reqwest::{header::{HeaderMap, HeaderValue, AUTHORIZATION}, Client, Url}; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::suite::config::Config; + +#[derive(Clone)] +pub struct EdgehogClient { + url: Url, + client: Client, +} + +impl EdgehogClient { + pub fn create(config: &Config) -> eyre::Result { + let full_url = format!( + "{}://{}/tenants/{}/api", + config.scheme, config.hostname, config.tenant + ).parse()?; + + let mut headers = HeaderMap::new(); + let mut token = HeaderValue::try_from(format!("Bearer {}", config.bearer))?; + token.set_sensitive(true); + + headers.insert(AUTHORIZATION, token); + + let client = reqwest::Client::builder().default_headers(headers).build()?; + + Ok(Self{ + url: full_url, + client + }) + } + + pub async fn send(&self, value: &T) -> eyre::Result> where T: Serialize, U: DeserializeOwned { + self.client.post(self.url.clone()).json(value).send().await?.error_for_status()?.json().await.map_err(Into::into) + } +} diff --git a/tools/e2e_test/src/suite/config.rs b/tools/e2e_test/src/suite/config.rs new file mode 100644 index 000000000..8ad8fccee --- /dev/null +++ b/tools/e2e_test/src/suite/config.rs @@ -0,0 +1,43 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct Config { + /// Edgehog api host name, e.g. api.edgehog.localhost + #[arg( + long, + default_value = "api.edgehog.localhost", + env = "EDGEHOG_TEST_HOSTNAME" + )] + pub hostname: String, + + /// Scheme to run graphql queries, e.g. http + #[arg(long, default_value = "http", env = "EDGEHOG_TEST_SCHEME")] + pub scheme: String, + + /// tenant jwt to authorize requests + #[arg(long, env = "EDGEHOG_TEST_BEARER")] + pub bearer: String, + + /// tenant slug + #[arg(long, default_value = "test", env = "EDGEHOG_TEST_TENANT")] + pub tenant: String, +} diff --git a/tools/e2e_test/src/suite/mod.rs b/tools/e2e_test/src/suite/mod.rs new file mode 100644 index 000000000..62f640642 --- /dev/null +++ b/tools/e2e_test/src/suite/mod.rs @@ -0,0 +1,20 @@ +// This file is part of Edgehog. +// +// Copyright 2025 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pub mod client; +pub mod config; From b8d04f148d01fc568f8096b329ac6b9220d13473 Mon Sep 17 00:00:00 2001 From: Luca Zaninotto Date: Fri, 12 Dec 2025 11:59:41 +0100 Subject: [PATCH 3/9] refactor: `cargo test` The default rust `test` utilities are quite powerful. This PR leverages them in order to: - natively use multiprocessing to run tests in parallel - have comprehensive `pass` and `error` logs Signed-off-by: Luca Zaninotto --- tools/e2e_test/src/image_credentials/mod.rs | 4 +-- tools/e2e_test/src/main.rs | 33 ++++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/tools/e2e_test/src/image_credentials/mod.rs b/tools/e2e_test/src/image_credentials/mod.rs index d139beda2..9f61d9920 100644 --- a/tools/e2e_test/src/image_credentials/mod.rs +++ b/tools/e2e_test/src/image_credentials/mod.rs @@ -25,7 +25,7 @@ use crate::suite::client; pub mod mutations; pub mod queries; -pub async fn run_test(client: client::EdgehogClient) -> eyre::Result<()> { +pub async fn test_image_credentials(client: client::EdgehogClient) -> eyre::Result<()> { let username = Alphabetic.sample_string(&mut rand::rng(), 5); let label = Alphabetic.sample_string(&mut rand::rng(), 5); let password = Alphabetic.sample_string(&mut rand::rng(), 10); @@ -64,7 +64,5 @@ pub async fn run_test(client: client::EdgehogClient) -> eyre::Result<()> { assert_eq!(image_credentials.username, username); assert_eq!(image_credentials.label, label); - println!("[ PASSED ] image credentials tests"); - Ok(()) } diff --git a/tools/e2e_test/src/main.rs b/tools/e2e_test/src/main.rs index 73098b973..604c0ee14 100644 --- a/tools/e2e_test/src/main.rs +++ b/tools/e2e_test/src/main.rs @@ -19,13 +19,32 @@ mod image_credentials; mod suite; -use clap::Parser; -use suite::client::EdgehogClient; -use suite::config::Config; - #[tokio::main] async fn main() -> eyre::Result<()> { - let config = Config::parse(); - let client = EdgehogClient::create(&config)?; - image_credentials::run_test(client).await + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + + use suite::client::EdgehogClient; + use suite::config::Config; + + fn test_config() -> Config { + Config { + hostname: "api.edgehog.localhost".to_string(), + scheme: "http".to_string(), + bearer: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJlX3RnYSI6IioiLCJpYXQiOjE3Mzg5NDgzODh9.TTiXYs1LucAnS_6RGp7pWg-S30NSt7eqL7lU8BzT5BWlHctk7NYZwC6lftA6WeEb1HKEJfPoUqWeOeZ6oYA0AA".to_string(), + tenant: "test".to_string() + } + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn image_credentials() -> eyre::Result<()> { + let config = test_config(); + + let client = EdgehogClient::create(&config)?; + image_credentials::test_image_credentials(client).await + } } From 742cd18c0cafadd9f1f48d8fbc1b3dbf2ebfecc8 Mon Sep 17 00:00:00 2001 From: Luca Zaninotto Date: Mon, 24 Nov 2025 13:59:09 +0100 Subject: [PATCH 4/9] ci: Init e2e testing in CI Adds a github action triggering an end to end test of edgehog on backend changes. Signed-off-by: Luca Zaninotto --- .github/actions/export-container/action.yaml | 34 ++++++++++++++++++++ .github/actions/import-container/action.yaml | 30 +++++++++++++++++ .github/workflows/backend-e2e.yaml | 0 justfile | 2 +- 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 .github/actions/export-container/action.yaml create mode 100644 .github/actions/import-container/action.yaml create mode 100644 .github/workflows/backend-e2e.yaml diff --git a/.github/actions/export-container/action.yaml b/.github/actions/export-container/action.yaml new file mode 100644 index 000000000..3aaf14ed6 --- /dev/null +++ b/.github/actions/export-container/action.yaml @@ -0,0 +1,34 @@ +# +# This file is part of Edgehog. +# +# Copyright 2025 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +name: export-container +description: "Export backend conteatiner into a `backend.tar` artifact." +runs: + using: "composite" + steps: + - name: Create image tar + shell: bash + run: | + docker image save edgehogdevicemanager/edgehog-backend:latest -o backend.tar + - uses: actions/upload-artifact@v4 + with: + path: backend.tar + name: backend.tar + if-no-files-found: error diff --git a/.github/actions/import-container/action.yaml b/.github/actions/import-container/action.yaml new file mode 100644 index 000000000..539ad4afb --- /dev/null +++ b/.github/actions/import-container/action.yaml @@ -0,0 +1,30 @@ +# +# This file is part of Edgehog. +# +# Copyright 2025 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +name: import container +description: "Export backend conteatiner into a `backend.tar` artifact." +runs: + using: "composite" + steps: + - uses: actions/download-artifact@v5 + - name: Import backend container + shell: bash + run: | + docker image load < backend.tar diff --git a/.github/workflows/backend-e2e.yaml b/.github/workflows/backend-e2e.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/justfile b/justfile index ac285abe1..3dbe97c76 100644 --- a/justfile +++ b/justfile @@ -104,7 +104,7 @@ _init-edgehog: _create-edgehog-tenant edgehog-hostname="api.edgehog.localhost": #!/usr/bin/env bash admin_jwt=$(cat backend/priv/repo/seeds/keys/admin_jwt.txt) - curl -sf -X POST "http://{{edgehog-hostname}}/admin-api/v1/tenants" \ + curl --fail-with-body -X POST "http://{{edgehog-hostname}}/admin-api/v1/tenants" \ -H "Content-Type: application/vnd.api+json" \ -H "Accept: application/vnd.api+json" \ -H "Authorization: Bearer $admin_jwt" \ From 608e22863ad98eeaf19efee40a071fe698bc8428 Mon Sep 17 00:00:00 2001 From: Osman Hadzic Date: Thu, 12 Feb 2026 12:17:18 +0100 Subject: [PATCH 5/9] refactor: improve code formatting and structure Code formatting applied using the command: `cargo fmt`. Signed-off-by: Osman Hadzic --- tools/e2e_test/src/image_credentials/mod.rs | 24 +++++++------ .../mutations/create_image_credentials.rs | 2 +- .../queries/get_image_credentials.rs | 4 ++- tools/e2e_test/src/suite/client.rs | 36 ++++++++++++++----- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/tools/e2e_test/src/image_credentials/mod.rs b/tools/e2e_test/src/image_credentials/mod.rs index 9f61d9920..eacb6c27d 100644 --- a/tools/e2e_test/src/image_credentials/mod.rs +++ b/tools/e2e_test/src/image_credentials/mod.rs @@ -30,18 +30,20 @@ pub async fn test_image_credentials(client: client::EdgehogClient) -> eyre::Resu let label = Alphabetic.sample_string(&mut rand::rng(), 5); let password = Alphabetic.sample_string(&mut rand::rng(), 10); - let image_credentials_result = CreateImageCredentials::create_image_credentials( - &client, - &username, - &password, - &label - ) - .await?; + let image_credentials_result = + CreateImageCredentials::create_image_credentials(&client, &username, &password, &label) + .await?; - assert_eq!(image_credentials_result.errors, None); + println!("Image credentials creation result:"); - let created_credentials = + println!( + "Image credentials creation result: {:?}", image_credentials_result + ); + + assert_eq!(image_credentials_result.errors, None); + + let created_credentials = image_credentials_result .data .expect("Error wile unwrapping image credentials creation result") .create_image_credentials @@ -54,8 +56,8 @@ pub async fn test_image_credentials(client: client::EdgehogClient) -> eyre::Resu let id = created_credentials.id.clone(); - let image_credentials = - GetImageCredentials::get_image_credentials(&client, &id).await? + let image_credentials = GetImageCredentials::get_image_credentials(&client, &id) + .await? .data .expect(format!("Error while retrieving image credentials with id {}", &id).as_str()) .image_credentials diff --git a/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs b/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs index 885294b36..87c0fb887 100644 --- a/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs +++ b/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs @@ -47,6 +47,6 @@ impl CreateImageCredentials { }; let variables = Variables { input }; let request_body = CreateImageCredentials::build_query(variables); - client.send(&request_body) .await + client.send(&request_body).await } } diff --git a/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs b/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs index f04924a0c..2140ec0d3 100644 --- a/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs +++ b/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs @@ -38,7 +38,9 @@ impl GetImageCredentials { id: &String, ) -> eyre::Result> { // this is the important line - let variables = Variables { id: String::from(id) }; + let variables = Variables { + id: String::from(id), + }; let request_body = GetImageCredentials::build_query(variables); client.send(&request_body).await } diff --git a/tools/e2e_test/src/suite/client.rs b/tools/e2e_test/src/suite/client.rs index 585199db3..64e6f9932 100644 --- a/tools/e2e_test/src/suite/client.rs +++ b/tools/e2e_test/src/suite/client.rs @@ -16,8 +16,11 @@ // // SPDX-License-Identifier: Apache-2.0 -use reqwest::{header::{HeaderMap, HeaderValue, AUTHORIZATION}, Client, Url}; -use serde::{de::DeserializeOwned, Serialize}; +use reqwest::{ + Client, Url, + header::{AUTHORIZATION, HeaderMap, HeaderValue}, +}; +use serde::{Serialize, de::DeserializeOwned}; use crate::suite::config::Config; @@ -32,23 +35,38 @@ impl EdgehogClient { let full_url = format!( "{}://{}/tenants/{}/api", config.scheme, config.hostname, config.tenant - ).parse()?; + ) + .parse()?; let mut headers = HeaderMap::new(); let mut token = HeaderValue::try_from(format!("Bearer {}", config.bearer))?; token.set_sensitive(true); - headers.insert(AUTHORIZATION, token); + headers.insert(AUTHORIZATION, token); - let client = reqwest::Client::builder().default_headers(headers).build()?; + let client = reqwest::Client::builder() + .default_headers(headers) + .build()?; - Ok(Self{ + Ok(Self { url: full_url, - client + client, }) } - pub async fn send(&self, value: &T) -> eyre::Result> where T: Serialize, U: DeserializeOwned { - self.client.post(self.url.clone()).json(value).send().await?.error_for_status()?.json().await.map_err(Into::into) + pub async fn send(&self, value: &T) -> eyre::Result> + where + T: Serialize, + U: DeserializeOwned, + { + self.client + .post(self.url.clone()) + .json(value) + .send() + .await? + .error_for_status()? + .json() + .await + .map_err(Into::into) } } From b8d1d22f49aaaa7c29f7924728915876f63a92a0 Mon Sep 17 00:00:00 2001 From: Osman Hadzic Date: Thu, 12 Feb 2026 12:21:55 +0100 Subject: [PATCH 6/9] fix: use .env variable for test configuration use environment variables for test configuration instead of hardcoding values in the code. Signed-off-by: Osman Hadzic --- tools/e2e_test/src/main.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/e2e_test/src/main.rs b/tools/e2e_test/src/main.rs index 604c0ee14..e9c696bec 100644 --- a/tools/e2e_test/src/main.rs +++ b/tools/e2e_test/src/main.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ // // SPDX-License-Identifier: Apache-2.0 +mod containers; mod image_credentials; mod suite; @@ -28,15 +29,18 @@ async fn main() -> eyre::Result<()> { mod test { use super::*; + use std::env; use suite::client::EdgehogClient; use suite::config::Config; fn test_config() -> Config { Config { - hostname: "api.edgehog.localhost".to_string(), - scheme: "http".to_string(), - bearer: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJlX3RnYSI6IioiLCJpYXQiOjE3Mzg5NDgzODh9.TTiXYs1LucAnS_6RGp7pWg-S30NSt7eqL7lU8BzT5BWlHctk7NYZwC6lftA6WeEb1HKEJfPoUqWeOeZ6oYA0AA".to_string(), - tenant: "test".to_string() + hostname: env::var("EDGEHOG_TEST_HOSTNAME") + .unwrap_or_else(|_| "api.edgehog.localhost".to_string()), + scheme: env::var("EDGEHOG_TEST_SCHEME").unwrap_or_else(|_| "http".to_string()), + bearer: env::var("EDGEHOG_TEST_BEARER") + .expect("Bearer token must be set in EDGEHOG_TEST_BEARER"), + tenant: env::var("EDGEHOG_TEST_TENANT").unwrap_or_else(|_| "test".to_string()), } } From f489ac3cfd6aa1eca54853be00cde57917ceaf9b Mon Sep 17 00:00:00 2001 From: Osman Hadzic Date: Thu, 12 Feb 2026 12:33:52 +0100 Subject: [PATCH 7/9] feat: add tests for application management add GraphQL mutations and queries for application management Signed-off-by: Osman Hadzic --- .../mutations/create_application.graphql | 27 +++++++++ .../graphql/queries/get_application.graphql | 25 ++++++++ tools/e2e_test/src/containers/mod.rs | 60 +++++++++++++++++++ .../mutations/create_application.rs | 51 ++++++++++++++++ .../e2e_test/src/containers/mutations/mod.rs | 19 ++++++ .../src/containers/queries/get_application.rs | 46 ++++++++++++++ tools/e2e_test/src/containers/queries/mod.rs | 19 ++++++ tools/e2e_test/src/main.rs | 10 ++++ 8 files changed, 257 insertions(+) create mode 100644 tools/e2e_test/graphql/mutations/create_application.graphql create mode 100644 tools/e2e_test/graphql/queries/get_application.graphql create mode 100644 tools/e2e_test/src/containers/mod.rs create mode 100644 tools/e2e_test/src/containers/mutations/create_application.rs create mode 100644 tools/e2e_test/src/containers/mutations/mod.rs create mode 100644 tools/e2e_test/src/containers/queries/get_application.rs create mode 100644 tools/e2e_test/src/containers/queries/mod.rs diff --git a/tools/e2e_test/graphql/mutations/create_application.graphql b/tools/e2e_test/graphql/mutations/create_application.graphql new file mode 100644 index 000000000..7c887f680 --- /dev/null +++ b/tools/e2e_test/graphql/mutations/create_application.graphql @@ -0,0 +1,27 @@ +# This file is part of Edgehog. +# +# Copyright 2025 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +mutation CreateApplication($input: CreateApplicationInput!) { + createApplication(input: $input) { + result { + id + name + description + } + } +} diff --git a/tools/e2e_test/graphql/queries/get_application.graphql b/tools/e2e_test/graphql/queries/get_application.graphql new file mode 100644 index 000000000..e8f567be6 --- /dev/null +++ b/tools/e2e_test/graphql/queries/get_application.graphql @@ -0,0 +1,25 @@ +# This file is part of Edgehog. +# +# Copyright 2026 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +query GetApplication($id: ID!) { + application(id: $id) { + id + name + description + } +} diff --git a/tools/e2e_test/src/containers/mod.rs b/tools/e2e_test/src/containers/mod.rs new file mode 100644 index 000000000..e8e6fdd3c --- /dev/null +++ b/tools/e2e_test/src/containers/mod.rs @@ -0,0 +1,60 @@ +// This file is part of Edgehog. +// +// Copyright 2026 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use mutations::create_application::CreateApplication; +use queries::get_application::GetApplication; +use rand::distr::{Alphabetic, SampleString}; + +use crate::suite::client; + +pub mod mutations; +pub mod queries; + +pub async fn test_application(client: client::EdgehogClient) -> eyre::Result<()> { + let name = Alphabetic.sample_string(&mut rand::rng(), 10); + let description = Some(Alphabetic.sample_string(&mut rand::rng(), 20)); + + let application_result = + CreateApplication::create_application(&client, &name, description.clone()).await?; + + assert_eq!(application_result.errors, None); + + let created_application = application_result + .data + .expect("Error while unwrapping application creation result") + .create_application + .expect("Error while unwrapping application creation result") + .result + .expect("Error while unwrapping application creation result"); + + assert_eq!(description, created_application.description); + + let id = created_application.id.clone(); + + let application = GetApplication::get_application(&client, &id) + .await? + .data + .expect(format!("Error while retrieving application with id {}", &id).as_str()) + .application + .expect(format!("Error while retrieving application with id {}", &id).as_str()); + + assert_eq!(application.name, name); + assert_eq!(application.description, description); + + Ok(()) +} diff --git a/tools/e2e_test/src/containers/mutations/create_application.rs b/tools/e2e_test/src/containers/mutations/create_application.rs new file mode 100644 index 000000000..3ee04e887 --- /dev/null +++ b/tools/e2e_test/src/containers/mutations/create_application.rs @@ -0,0 +1,51 @@ +// This file is part of Edgehog. +// +// Copyright 2026 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use create_application::{CreateApplicationInput, ResponseData, Variables}; +use graphql_client::{GraphQLQuery, Response}; +use std::fmt::Debug; + +use crate::suite::client::EdgehogClient; + +// The paths are relative to the directory where your `Cargo.toml` is located. +// Both json and the GraphQL schema language are supported as sources for the schema +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/mutations/create_application.graphql", + response_derives = "Debug" +)] +pub struct CreateApplication; + +impl CreateApplication { + pub async fn create_application( + client: &EdgehogClient, + name: &String, + description: Option, + ) -> eyre::Result> { + let input = CreateApplicationInput { + name: String::from(name), + description, + initial_release: None, + system_model_id: None, + }; + let variables = Variables { input }; + let request_body = CreateApplication::build_query(variables); + client.send(&request_body).await + } +} diff --git a/tools/e2e_test/src/containers/mutations/mod.rs b/tools/e2e_test/src/containers/mutations/mod.rs new file mode 100644 index 000000000..b4c74396e --- /dev/null +++ b/tools/e2e_test/src/containers/mutations/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Edgehog. +// +// Copyright 2026 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pub mod create_application; diff --git a/tools/e2e_test/src/containers/queries/get_application.rs b/tools/e2e_test/src/containers/queries/get_application.rs new file mode 100644 index 000000000..427b9cb64 --- /dev/null +++ b/tools/e2e_test/src/containers/queries/get_application.rs @@ -0,0 +1,46 @@ +// This file is part of Edgehog. +// +// Copyright 2026 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +use get_application::{ResponseData, Variables}; +use graphql_client::{GraphQLQuery, Response}; +use std::fmt::Debug; + +use crate::suite::client::EdgehogClient; + +// The paths are relative to the directory where your `Cargo.toml` is located. +// Both json and the GraphQL schema language are supported as sources for the schema +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/get_application.graphql", + response_derives = "Debug" +)] +pub struct GetApplication; + +impl GetApplication { + pub async fn get_application( + client: &EdgehogClient, + id: &String, + ) -> eyre::Result> { + let variables = Variables { + id: String::from(id), + }; + let request_body = GetApplication::build_query(variables); + client.send(&request_body).await + } +} diff --git a/tools/e2e_test/src/containers/queries/mod.rs b/tools/e2e_test/src/containers/queries/mod.rs new file mode 100644 index 000000000..5585b802e --- /dev/null +++ b/tools/e2e_test/src/containers/queries/mod.rs @@ -0,0 +1,19 @@ +// This file is part of Edgehog. +// +// Copyright 2026 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +pub mod get_application; diff --git a/tools/e2e_test/src/main.rs b/tools/e2e_test/src/main.rs index e9c696bec..e3dd4e495 100644 --- a/tools/e2e_test/src/main.rs +++ b/tools/e2e_test/src/main.rs @@ -51,4 +51,14 @@ mod test { let client = EdgehogClient::create(&config)?; image_credentials::test_image_credentials(client).await } + + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] + async fn application() -> eyre::Result<()> { + let config = test_config(); + + println!("Test config: {:?}", config); + + let client = EdgehogClient::create(&config)?; + containers::test_application(client).await + } } From f49cf6a9d552319c4df8bd8b1b9986c245ac9007 Mon Sep 17 00:00:00 2001 From: Osman Hadzic Date: Thu, 12 Feb 2026 15:36:57 +0100 Subject: [PATCH 8/9] feat: add backend E2E formatter workflow add a new GitHub Actions workflow to format the backend codebase before running E2E tests. Signed-off-by: Osman Hadzic --- .github/workflows/backend-e2e-formater.yaml | 40 ++++++++++++++++++++ .github/workflows/backend-e2e.yaml | 42 +++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 .github/workflows/backend-e2e-formater.yaml diff --git a/.github/workflows/backend-e2e-formater.yaml b/.github/workflows/backend-e2e-formater.yaml new file mode 100644 index 000000000..bb5e102fa --- /dev/null +++ b/.github/workflows/backend-e2e-formater.yaml @@ -0,0 +1,40 @@ +# This file is part of Edgehog. +# +# Copyright 2026 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +name: Backend E2E formatter test +on: + workflow_call: + workflow_dispatch: +permissions: + contents: read +defaults: + run: + shell: bash + working-directory: tools/e2e_test +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +jobs: + run-e2e-formatter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - name: Run E2E tests + run: cargo fmt --check diff --git a/.github/workflows/backend-e2e.yaml b/.github/workflows/backend-e2e.yaml index e69de29bb..b0fe31c5e 100644 --- a/.github/workflows/backend-e2e.yaml +++ b/.github/workflows/backend-e2e.yaml @@ -0,0 +1,42 @@ +# This file is part of Edgehog. +# +# Copyright 2026 SECO Mind Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +name: Backend E2E tests +on: + # Run when pushing to stable branches + push: + paths: + - "tools/e2e_test/**" + - ".tool-versions" + - ".github/workflows/backend-e2e-*.yaml" + branches: + - "main" + - "release-*" + # Run on pull requests matching apps + pull_request: + paths: + - "tools/e2e_test/**" + - ".tool-versions" + - ".github/workflows/backend-e2e-*.yaml" +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + run-e2e-formatter: + uses: ./.github/workflows/backend-e2e-formater.yaml From 7b353564665203a2ef637ee6669c12fab9289e7a Mon Sep 17 00:00:00 2001 From: Osman Hadzic Date: Fri, 13 Feb 2026 09:23:07 +0100 Subject: [PATCH 9/9] fix: update copyright year update copyright year in various files to 2025 - 2026 Signed-off-by: Osman Hadzic --- .github/actions/export-container/action.yaml | 2 +- .github/actions/import-container/action.yaml | 2 +- REUSE.toml | 2 +- tools/e2e_test/.gitignore | 2 +- tools/e2e_test/Cargo.lock.license | 2 +- tools/e2e_test/Cargo.toml | 2 +- tools/e2e_test/graphql/mutations/create_application.graphql | 2 +- .../e2e_test/graphql/mutations/create_image_credentials.graphql | 2 +- tools/e2e_test/graphql/queries/image_credentials.graphql | 2 +- tools/e2e_test/graphql/schema.graphql.license | 2 +- tools/e2e_test/src/image_credentials/mod.rs | 2 +- .../src/image_credentials/mutations/create_image_credentials.rs | 2 +- tools/e2e_test/src/image_credentials/mutations/mod.rs | 2 +- .../src/image_credentials/queries/get_image_credentials.rs | 2 +- tools/e2e_test/src/image_credentials/queries/mod.rs | 2 +- tools/e2e_test/src/suite/client.rs | 2 +- tools/e2e_test/src/suite/config.rs | 2 +- tools/e2e_test/src/suite/mod.rs | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/actions/export-container/action.yaml b/.github/actions/export-container/action.yaml index 3aaf14ed6..8ff40dd15 100644 --- a/.github/actions/export-container/action.yaml +++ b/.github/actions/export-container/action.yaml @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025 - 2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/actions/import-container/action.yaml b/.github/actions/import-container/action.yaml index 539ad4afb..b5d140a0b 100644 --- a/.github/actions/import-container/action.yaml +++ b/.github/actions/import-container/action.yaml @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025 - 2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/REUSE.toml b/REUSE.toml index b76002ad7..bf72d41a0 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -66,7 +66,7 @@ SPDX-License-Identifier = "Apache-2.0" [[annotations]] path = "justfile" precedence = "aggregate" -SPDX-FileCopyrightText = "2025 Seco Mind Srl" +SPDX-FileCopyrightText = "2025-2026 Seco Mind Srl" SPDX-License-Identifier = "Apache-2.0" [[annotations]] diff --git a/tools/e2e_test/.gitignore b/tools/e2e_test/.gitignore index 0e50bf173..4e5824401 100644 --- a/tools/e2e_test/.gitignore +++ b/tools/e2e_test/.gitignore @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2025 SECO Mind Srl +# SPDX-FileCopyrightText: 2025 - 2026 SECO Mind Srl # SPDX-License-Identifier: CC0-1.0 # Generated by Cargo diff --git a/tools/e2e_test/Cargo.lock.license b/tools/e2e_test/Cargo.lock.license index fec65eb06..9438a92fa 100644 --- a/tools/e2e_test/Cargo.lock.license +++ b/tools/e2e_test/Cargo.lock.license @@ -1,6 +1,6 @@ This file is part of Edgehog. -Copyright 2025 SECO Mind Srl +Copyright 2025 - 2026 SECO Mind Srl Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/Cargo.toml b/tools/e2e_test/Cargo.toml index 03cb9a1d8..4920d5f4d 100644 --- a/tools/e2e_test/Cargo.toml +++ b/tools/e2e_test/Cargo.toml @@ -1,6 +1,6 @@ # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025 - 2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/graphql/mutations/create_application.graphql b/tools/e2e_test/graphql/mutations/create_application.graphql index 7c887f680..82545922d 100644 --- a/tools/e2e_test/graphql/mutations/create_application.graphql +++ b/tools/e2e_test/graphql/mutations/create_application.graphql @@ -1,6 +1,6 @@ # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025 - 2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/graphql/mutations/create_image_credentials.graphql b/tools/e2e_test/graphql/mutations/create_image_credentials.graphql index 02e8c8e96..5ffe4a1cb 100644 --- a/tools/e2e_test/graphql/mutations/create_image_credentials.graphql +++ b/tools/e2e_test/graphql/mutations/create_image_credentials.graphql @@ -1,6 +1,6 @@ # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025 - 2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/graphql/queries/image_credentials.graphql b/tools/e2e_test/graphql/queries/image_credentials.graphql index 60c1bba05..9f029e715 100644 --- a/tools/e2e_test/graphql/queries/image_credentials.graphql +++ b/tools/e2e_test/graphql/queries/image_credentials.graphql @@ -1,6 +1,6 @@ # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025 - 2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/graphql/schema.graphql.license b/tools/e2e_test/graphql/schema.graphql.license index 5647f82a7..303a209b7 100644 --- a/tools/e2e_test/graphql/schema.graphql.license +++ b/tools/e2e_test/graphql/schema.graphql.license @@ -1,3 +1,3 @@ -SPDX-FileCopyrightText: 2025 SECO Mind Srl +SPDX-FileCopyrightText: 2025 - 2026 SECO Mind Srl SPDX-License-Identifier: Apache-2.0 diff --git a/tools/e2e_test/src/image_credentials/mod.rs b/tools/e2e_test/src/image_credentials/mod.rs index eacb6c27d..7ddc1738e 100644 --- a/tools/e2e_test/src/image_credentials/mod.rs +++ b/tools/e2e_test/src/image_credentials/mod.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs b/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs index 87c0fb887..d5bb0ac8b 100644 --- a/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs +++ b/tools/e2e_test/src/image_credentials/mutations/create_image_credentials.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/image_credentials/mutations/mod.rs b/tools/e2e_test/src/image_credentials/mutations/mod.rs index 4f92f6e5a..d3937ea4f 100644 --- a/tools/e2e_test/src/image_credentials/mutations/mod.rs +++ b/tools/e2e_test/src/image_credentials/mutations/mod.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs b/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs index 2140ec0d3..06be5f162 100644 --- a/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs +++ b/tools/e2e_test/src/image_credentials/queries/get_image_credentials.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/image_credentials/queries/mod.rs b/tools/e2e_test/src/image_credentials/queries/mod.rs index 6d17b8e0c..3f752efe5 100644 --- a/tools/e2e_test/src/image_credentials/queries/mod.rs +++ b/tools/e2e_test/src/image_credentials/queries/mod.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/suite/client.rs b/tools/e2e_test/src/suite/client.rs index 64e6f9932..46ffba5ed 100644 --- a/tools/e2e_test/src/suite/client.rs +++ b/tools/e2e_test/src/suite/client.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/suite/config.rs b/tools/e2e_test/src/suite/config.rs index 8ad8fccee..e0c8e8686 100644 --- a/tools/e2e_test/src/suite/config.rs +++ b/tools/e2e_test/src/suite/config.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tools/e2e_test/src/suite/mod.rs b/tools/e2e_test/src/suite/mod.rs index 62f640642..db07481f1 100644 --- a/tools/e2e_test/src/suite/mod.rs +++ b/tools/e2e_test/src/suite/mod.rs @@ -1,6 +1,6 @@ // This file is part of Edgehog. // -// Copyright 2025 SECO Mind Srl +// Copyright 2025 - 2026 SECO Mind Srl // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.