diff --git a/.github/scripts/test-matrix.py b/.github/scripts/test-matrix.py index c43204ec..bc2fb7c8 100644 --- a/.github/scripts/test-matrix.py +++ b/.github/scripts/test-matrix.py @@ -3,7 +3,7 @@ TEST_DIR = "bin/icp-cli/tests" -MACOS_TESTS = ["hello_tests"] +MACOS_TESTS = ["network_tests"] def test_names(): all_files = os.listdir(TEST_DIR) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a4cf6093..ae7d8d29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,14 @@ on: - main pull_request: +env: + # When getting Rust dependencies, retry on network error: + CARGO_NET_RETRY: 10 + # Use the local .curlrc + CURL_HOME: . + # Disable DFX telemetry + DFX_TELEMETRY: 'off' + jobs: discover: runs-on: ubuntu-latest @@ -38,6 +46,14 @@ jobs: target key: ${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-test-1 + - name: Install dfx + uses: dfinity/setup-dfx@main + - name: Set up path to dfx for tests and to pocketic for icp + run: | + dfx cache install + echo "ICPTEST_DFX_PATH=$(dfx cache show)/dfx" >> "$GITHUB_ENV" + echo "ICP_POCKET_IC_PATH=$(dfx cache show)/pocket-ic" >> "$GITHUB_ENV" + - name: Run ${{ matrix.test }} run: cargo test --test ${{ matrix.test }} diff --git a/Cargo.lock b/Cargo.lock index 3ff5e126..bf44fe56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,33 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,12 +38,80 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "assert_cmd" version = "2.0.17" @@ -33,18 +128,157 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "async-watch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a078faf4e27c0c6cc0efb20e5da59dcccc04968ebf2801d8e0b2195124cdcdb2" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "getrandom 0.2.16", + "instant", + "rand 0.8.5", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "binread" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" +dependencies = [ + "binread_derive", + "lazy_static", + "rustversion", +] + +[[package]] +name = "binread_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" +dependencies = [ + "either", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "1.12.0" @@ -52,8 +286,83 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", - "regex-automata", + "regex-automata 0.4.9", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cached" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8466736fe5dbcaf8b8ee24f9bbefe43c884dc3e9ff7178da70f55bffca1133c" +dependencies = [ + "ahash", + "hashbrown 0.14.5", + "instant", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "candid" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d90f5a1426d0489283a0bd5da9ed406fb3e69597e0d823dcb88a1965bb58d2" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive", + "hex", + "ic_principal", + "leb128", + "num-bigint", + "num-traits", + "paste", + "pretty", "serde", + "serde_bytes", + "stacker", + "thiserror 1.0.69", +] + +[[package]] +name = "candid_derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3de398570c386726e7a59d9887b68763c481477f9a043fb998a2e09d428df1a9" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "cc" +version = "1.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +dependencies = [ + "shlex", ] [[package]] @@ -63,278 +372,2832 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "difflib" -version = "0.4.0" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "doc-comment" -version = "0.3.3" +name = "clap" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +dependencies = [ + "clap_builder", + "clap_derive", +] [[package]] -name = "errno" -version = "0.3.11" +name = "clap_builder" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ - "libc", - "windows-sys", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "fastrand" -version = "2.3.0" +name = "clap_derive" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] -name = "float-cmp" +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ - "num-traits", + "core-foundation-sys", + "libc", ] [[package]] -name = "getrandom" -version = "0.3.2" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "cfg-if", "libc", - "r-efi", - "wasi", ] [[package]] -name = "icp-cli" -version = "0.1.0" +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "assert_cmd", - "predicates", - "tempfile", + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[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.101", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +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", + "futures-sink", +] + +[[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-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[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-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[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 = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[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", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 0.26.11", +] + +[[package]] +name = "hyper-util" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "ic-agent" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4832787330765f1bdf67123928855390b7f0b5a16dd0a7ea67674b7d3178ffd0" +dependencies = [ + "arc-swap", + "async-channel", + "async-lock", + "async-trait", + "async-watch", + "backoff", + "cached", + "candid", + "der", + "ecdsa", + "ed25519-consensus", + "elliptic-curve", + "futures-util", + "hex", + "http", + "http-body", + "ic-certification", + "ic-transport-types 0.40.1", + "ic-verify-bls-signature", + "k256", + "leb128", + "p256", + "pem", + "pkcs8", + "rand 0.8.5", + "rangemap", + "reqwest", + "sec1", + "serde", + "serde_bytes", + "serde_cbor", + "serde_repr", + "sha2 0.10.9", + "simple_asn1", + "stop-token", + "thiserror 2.0.12", + "time", + "tokio", + "tower-service", + "url", +] + +[[package]] +name = "ic-certification" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb40d73f9f8273dc6569a68859003bbd467c9dc6d53c6fd7d174742f857209d" +dependencies = [ + "hex", + "serde", + "serde_bytes", + "sha2 0.10.9", +] + +[[package]] +name = "ic-management-canister-types" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98554c2d8a30c00b6bfda18062fdcef21215cad07a52d8b8b1eb3130e51bfe71" +dependencies = [ + "candid", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-transport-types" +version = "0.39.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "979ee7bee5a67150a4c090fb012c93c294a528b4a867bad9a15cc6d01cb4227f" +dependencies = [ + "candid", + "hex", + "ic-certification", + "leb128", + "serde", + "serde_bytes", + "serde_cbor", + "serde_repr", + "sha2 0.10.9", + "thiserror 2.0.12", +] + +[[package]] +name = "ic-transport-types" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e7706e55836e8104c98149ec0796d20d5213fef972ac01b544657d410f1883" +dependencies = [ + "candid", + "hex", + "ic-certification", + "leb128", + "serde", + "serde_bytes", + "serde_cbor", + "serde_repr", + "sha2 0.10.9", + "thiserror 2.0.12", +] + +[[package]] +name = "ic-verify-bls-signature" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d420b25c0091059f6c3c23a21427a81915e6e0aca3b79e0d403ed767f286a3b9" +dependencies = [ + "hex", + "ic_bls12_381", + "lazy_static", + "pairing", + "rand 0.8.5", + "sha2 0.10.9", +] + +[[package]] +name = "ic_bls12_381" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e828f9e804ccefe4b9b15b2195f474c60fd4f95ccd14fcb554eb6d7dfafde3" +dependencies = [ + "digest 0.10.7", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ic_principal" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1762deb6f7c8d8c2bdee4b6c5a47b60195b74e9b5280faa5ba29692f8e17429c" +dependencies = [ + "crc32fast", + "data-encoding", + "serde", + "sha2 0.10.9", + "thiserror 1.0.69", +] + +[[package]] +name = "icp-cli" +version = "0.1.0" +dependencies = [ + "assert_cmd", + "clap", + "icp-fs", + "icp-network", + "predicates", + "reqwest", + "snafu", + "tempfile", + "tokio", +] + +[[package]] +name = "icp-fs" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "snafu", +] + +[[package]] +name = "icp-identity" +version = "0.1.0" + +[[package]] +name = "icp-network" +version = "0.1.0" +dependencies = [ + "candid", + "fd-lock", + "hex", + "ic-agent", + "icp-fs", + "pocket-ic", + "reqwest", + "serde", + "serde_json", + "snafu", + "time", + "tokio", + "uuid", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +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 = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.3", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[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.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.9", + "signature", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[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 = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pocket-ic" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0dee25e0f699db883fa2228b18b6e86ae874a0f538dd362aef70679ca5cc6d" +dependencies = [ + "backoff", + "base64 0.13.1", + "candid", + "flate2", + "hex", + "ic-certification", + "ic-management-canister-types", + "ic-transport-types 0.39.3", + "reqwest", + "schemars", + "serde", + "serde_bytes", + "serde_cbor", + "serde_json", + "sha2 0.10.9", + "slog", + "strum", + "strum_macros", + "tempfile", + "thiserror 2.0.12", + "tokio", + "tracing", + "tracing-appender", + "tracing-subscriber", + "wslpath", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "pretty" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac98773b7109bc75f475ab5a134c9b64b87e59d776d31098d8f346922396a477" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-width", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +dependencies = [ + "cc", +] + +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +dependencies = [ + "bytes", + "getrandom 0.3.2", + "lru-slab", + "rand 0.9.1", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[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 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", +] + +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-socks", + "tokio-util", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 0.26.11", + "windows-registry", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[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 = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.101", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[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 = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simple_asn1" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.12", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" +dependencies = [ + "erased-serde", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "snafu" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stacker" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + +[[package]] +name = "stop-token" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af91f480ee899ab2d9f8435bfdfc14d08a5754bd9d3fef1f1a1c23336aad6c8b" +dependencies = [ + "async-channel", + "cfg-if", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[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.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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.101", +] + +[[package]] +name = "tempfile" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +dependencies = [ + "fastrand", + "getrandom 0.3.2", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[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.101", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-socks" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" +dependencies = [ + "either", + "futures-util", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +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", + "tokio", + "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-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror 1.0.69", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "time", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", ] [[package]] -name = "icp-identity" -version = "0.1.0" +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "icp-network" -version = "0.1.0" +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "libc" -version = "0.2.172" +name = "uuid" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "getrandom 0.3.2", + "serde", +] [[package]] -name = "linux-raw-sys" -version = "0.9.4" +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] -name = "memchr" -version = "2.7.4" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "normalize-line-endings" -version = "0.3.0" +name = "wait-timeout" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] [[package]] -name = "num-traits" -version = "0.2.19" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "autocfg", + "try-lock", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "predicates" -version = "3.1.3" +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ - "anstyle", - "difflib", - "float-cmp", - "normalize-line-endings", - "predicates-core", - "regex", + "wit-bindgen-rt", ] [[package]] -name = "predicates-core" -version = "1.0.9" +name = "wasm-bindgen" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] [[package]] -name = "predicates-tree" -version = "1.0.12" +name = "wasm-bindgen-backend" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ - "predicates-core", - "termtree", + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", ] [[package]] -name = "proc-macro2" -version = "1.0.95" +name = "wasm-bindgen-futures" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ - "unicode-ident", + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "quote" -version = "1.0.40" +name = "wasm-bindgen-macro" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ - "proc-macro2", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "r-efi" -version = "5.2.0" +name = "wasm-bindgen-macro-support" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] [[package]] -name = "regex" -version = "1.11.1" +name = "wasm-bindgen-shared" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "unicode-ident", ] [[package]] -name = "regex-automata" -version = "0.4.9" +name = "wasm-streams" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] -name = "regex-syntax" -version = "0.8.5" +name = "web-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] -name = "rustix" -version = "1.0.7" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "serde" -version = "1.0.219" +name = "webpki-roots" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "serde_derive", + "webpki-roots 1.0.0", ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "webpki-roots" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "rustls-pki-types", ] [[package]] -name = "syn" -version = "2.0.101" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "tempfile" -version = "3.19.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" -dependencies = [ - "fastrand", - "getrandom", - "once_cell", - "rustix", - "windows-sys", -] +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "termtree" -version = "0.5.1" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "unicode-ident" -version = "1.0.18" +name = "windows-link" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] -name = "wait-timeout" -version = "0.2.1" +name = "windows-registry" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "libc", + "windows-result", + "windows-strings", + "windows-targets 0.53.0", ] [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "windows-result" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "wit-bindgen-rt", + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + +[[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]] @@ -343,7 +3206,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -352,14 +3215,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -368,48 +3247,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -418,3 +3345,119 @@ checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "wslpath" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04a2ecdf2cc4d33a6a93d71bcfbc00bb1f635cdb8029a2cc0709204a045ec7a3" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[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.101", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] diff --git a/Cargo.toml b/Cargo.toml index d8c72e45..369e08c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,24 @@ members = [ "bin/icp-cli", "lib/icp-identity", "lib/icp-network", + "lib/icp-fs" ] resolver = "3" +[workspace.dependencies] +candid = "0.10.14" +fd-lock = "4.0.4" +hex = "0.4.3" +ic-agent = { version = "0.40.1" } +pocket-ic = "9.0.0" +reqwest = { version = "0.12.15", default-features = false, features = [ + "rustls-tls", +] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +snafu = "0.8.5" +tempfile = "3" +time = "0.3.9" +tokio = { version = "1.45.0", features = ["macros", "rt-multi-thread"] } +uuid = { version = "1.16.0", features = ["serde", "v4"] } diff --git a/README.md b/README.md index 94259636..fd4f0ec3 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# icp-cli \ No newline at end of file +# icp-cli + +## Running the local network + +The `ICP_POCKET_IC_PATH` environment variable should point to +the path of the `pocket-ic` binary. + +## Running Tests + +These tests use dfx to stand up and interact with a local Internet Computer instance. +To ensure test isolation, they run in a temporary HOME directory and +**cannot use the dfx shim from dfxvm**. + +To run the tests, it's necessary to set the ICPTEST_DFX_PATH environment variable +to a valid dfx path, as well as the ICP_POCKET_IC_PATH environment variable. +Here is one way to do that: + +``` +# Ensure dfx is installed and the cache is populated +dfx cache install + +# Export the path to the actual dfx binary (not the shim) +export ICPTEST_DFX_PATH="$(dfx cache show)/dfx" + +# Export the path to the pocket-ic binary +export ICP_POCKET_IC_PATH="$(dfx cache show)/pocket-ic" + +# Run tests +cargo test +``` + +If ICPTEST_DFX_PATH is not set, tests that depend on dfx will fail. diff --git a/bin/icp-cli/Cargo.toml b/bin/icp-cli/Cargo.toml index 6698d248..be0b294d 100644 --- a/bin/icp-cli/Cargo.toml +++ b/bin/icp-cli/Cargo.toml @@ -9,8 +9,14 @@ name = "icp" path = "src/main.rs" [dependencies] +clap = { version = "4.5.35", features = ["derive"] } +icp-network = { path = "../../lib/icp-network" } +icp-fs = { path = "../../lib/icp-fs" } +snafu = { workspace = true } +tokio = { workspace = true } [dev-dependencies] assert_cmd = "2" predicates = "3" +reqwest = { workspace = true } tempfile = "3" diff --git a/bin/icp-cli/src/commands.rs b/bin/icp-cli/src/commands.rs new file mode 100644 index 00000000..cdfe90e0 --- /dev/null +++ b/bin/icp-cli/src/commands.rs @@ -0,0 +1,29 @@ +use crate::commands::network::NetworkCommandError; +use clap::{Parser, Subcommand}; +use snafu::Snafu; + +mod network; + +#[derive(Parser, Debug)] +pub struct Cli { + #[command(subcommand)] + subcommand: Subcmd, +} + +#[derive(Subcommand, Debug)] +pub enum Subcmd { + Network(network::Cmd), +} + +pub async fn dispatch(cli: Cli) -> Result<(), DispatchError> { + match cli.subcommand { + Subcmd::Network(opts) => network::dispatch(opts).await?, + } + Ok(()) +} + +#[derive(Debug, Snafu)] +pub enum DispatchError { + #[snafu(transparent)] + Network { source: NetworkCommandError }, +} diff --git a/bin/icp-cli/src/commands/network.rs b/bin/icp-cli/src/commands/network.rs new file mode 100644 index 00000000..450cdad0 --- /dev/null +++ b/bin/icp-cli/src/commands/network.rs @@ -0,0 +1,29 @@ +use crate::commands::network::run::RunNetworkCommandError; +use clap::{Parser, Subcommand}; +use snafu::Snafu; + +mod run; + +#[derive(Parser, Debug)] +pub struct Cmd { + #[command(subcommand)] + subcmd: Subcmd, +} + +#[derive(Subcommand, Debug)] +pub enum Subcmd { + Run(run::Cmd), +} + +pub async fn dispatch(cmd: Cmd) -> Result<(), NetworkCommandError> { + match cmd.subcmd { + Subcmd::Run(cmd) => run::exec(cmd).await?, + } + Ok(()) +} + +#[derive(Debug, Snafu)] +pub enum NetworkCommandError { + #[snafu(transparent)] + Run { source: RunNetworkCommandError }, +} diff --git a/bin/icp-cli/src/commands/network/run.rs b/bin/icp-cli/src/commands/network/run.rs new file mode 100644 index 00000000..45c1c200 --- /dev/null +++ b/bin/icp-cli/src/commands/network/run.rs @@ -0,0 +1,31 @@ +use crate::commands::network::run::RunNetworkCommandError::ProjectStructureNotFound; +use crate::project::structure::ProjectDirectoryStructure; +use clap::Parser; +use icp_network::{ManagedNetworkModel, RunNetworkError, run_network}; +use snafu::Snafu; + +/// Run the local network +#[derive(Parser, Debug)] +pub struct Cmd {} + +pub async fn exec(_cmd: Cmd) -> Result<(), RunNetworkCommandError> { + let config = ManagedNetworkModel::default(); + let pds = ProjectDirectoryStructure::find().ok_or(ProjectStructureNotFound)?; + let nds = pds.network("local"); + + eprintln!("Project root: {}", pds.root().display()); + eprintln!("Network root: {}", nds.network_root().display()); + + run_network(config, nds).await?; + + Ok(()) +} + +#[derive(Debug, Snafu)] +pub enum RunNetworkCommandError { + #[snafu(display("no project (icp.yaml) found in current directory or its parents"))] + ProjectStructureNotFound, + + #[snafu(transparent)] + NetworkExecutionFailed { source: RunNetworkError }, +} diff --git a/bin/icp-cli/src/main.rs b/bin/icp-cli/src/main.rs index e7a11a96..579157bb 100644 --- a/bin/icp-cli/src/main.rs +++ b/bin/icp-cli/src/main.rs @@ -1,3 +1,13 @@ -fn main() { - println!("Hello, world!"); +use crate::commands::Cli; +use clap::Parser; + +mod commands; +mod project; + +#[tokio::main] +async fn main() { + if let Err(e) = commands::dispatch(Cli::parse()).await { + eprintln!("Error: {}", e); + std::process::exit(1); + } } diff --git a/bin/icp-cli/src/project.rs b/bin/icp-cli/src/project.rs new file mode 100644 index 00000000..26a4f5f4 --- /dev/null +++ b/bin/icp-cli/src/project.rs @@ -0,0 +1 @@ +pub mod structure; diff --git a/bin/icp-cli/src/project/structure.rs b/bin/icp-cli/src/project/structure.rs new file mode 100644 index 00000000..a8b03f56 --- /dev/null +++ b/bin/icp-cli/src/project/structure.rs @@ -0,0 +1,40 @@ +use icp_network::structure::NetworkDirectoryStructure; +use std::path::PathBuf; + +pub struct ProjectDirectoryStructure { + root: PathBuf, +} + +impl ProjectDirectoryStructure { + pub fn find() -> Option { + let current_dir = std::env::current_dir().ok()?; + let mut path = current_dir.clone(); + loop { + if path.join("icp.yaml").exists() { + break Some(Self { root: path }); + } + if !path.pop() { + break None; + } + } + } + + pub fn root(&self) -> &PathBuf { + &self.root + } + + #[allow(dead_code)] + pub fn network_config_path(&self, name: &str) -> PathBuf { + self.root.join("networks").join(format!("{name}.yaml")) + } + + fn work_dir(&self) -> PathBuf { + self.root.join(".icp") + } + + pub fn network(&self, network_name: &str) -> NetworkDirectoryStructure { + let network_root = self.work_dir().join("networks").join(network_name); + + NetworkDirectoryStructure::new(&network_root) + } +} diff --git a/bin/icp-cli/tests/common/guard.rs b/bin/icp-cli/tests/common/guard.rs new file mode 100644 index 00000000..f59fa9f8 --- /dev/null +++ b/bin/icp-cli/tests/common/guard.rs @@ -0,0 +1,33 @@ +use std::process::{Child, Command}; + +pub struct ChildGuard { + child: Child, +} + +impl ChildGuard { + pub fn spawn(cmd: &mut Command) -> std::io::Result { + let child = cmd.spawn()?; + Ok(Self { child }) + } +} + +impl Drop for ChildGuard { + fn drop(&mut self) { + match self.child.try_wait() { + Ok(Some(_)) => { + // Already exited, nothing to do + } + Ok(None) => { + if let Err(e) = self.child.kill() { + eprintln!("Failed to kill child process: {}", e); + } + if let Err(e) = self.child.wait() { + eprintln!("Failed to wait on child process: {}", e); + } + } + Err(e) => { + eprintln!("Failed to check child process status: {}", e); + } + } + } +} diff --git a/bin/icp-cli/tests/common/mod.rs b/bin/icp-cli/tests/common/mod.rs index 7f99bec0..f48eb74d 100644 --- a/bin/icp-cli/tests/common/mod.rs +++ b/bin/icp-cli/tests/common/mod.rs @@ -1,3 +1,5 @@ +pub mod guard; +mod os; mod test_env; pub use test_env::TestEnv; diff --git a/bin/icp-cli/tests/common/os.rs b/bin/icp-cli/tests/common/os.rs new file mode 100644 index 00000000..eae60822 --- /dev/null +++ b/bin/icp-cli/tests/common/os.rs @@ -0,0 +1,5 @@ +#[cfg(unix)] +pub const PATH_SEPARATOR: &str = ":"; + +#[cfg(windows)] +pub const PATH_SEPARATOR: &str = ";"; diff --git a/bin/icp-cli/tests/common/test_env.rs b/bin/icp-cli/tests/common/test_env.rs index c6eaf3e1..57f332e0 100644 --- a/bin/icp-cli/tests/common/test_env.rs +++ b/bin/icp-cli/tests/common/test_env.rs @@ -1,25 +1,108 @@ +use crate::common::os::PATH_SEPARATOR; use assert_cmd::Command; -use std::path::Path; +use std::env; +use std::ffi::OsString; +use std::fs; +use std::fs::create_dir_all; +use std::path::{Path, PathBuf}; use tempfile::TempDir; pub struct TestEnv { home_dir: TempDir, + bin_dir: PathBuf, + dfx_path: Option, + os_path: OsString, } impl TestEnv { pub fn new() -> Self { + let home_dir = tempfile::tempdir().expect("failed to create temp home dir"); + let bin_dir = home_dir.path().join("bin"); + fs::create_dir(&bin_dir).expect("failed to create bin dir"); + let os_path = Self::build_os_path(&bin_dir); + eprintln!( + "Test environment home directory: {}", + home_dir.path().display() + ); + Self { - home_dir: tempfile::tempdir().expect("create home dir for test"), + home_dir, + bin_dir, + dfx_path: None, + os_path, + } + } + + /// Sets up `dfx` in the test environment by copying the binary from $ICPTEST_DFX_PATH + pub fn with_dfx(mut self) -> Self { + let dfx_path = std::env::var_os("ICPTEST_DFX_PATH") + .expect("ICPTEST_DFX_PATH must be set to use with_dfx()"); + let src = PathBuf::from(dfx_path); + assert!( + src.exists(), + "ICPTEST_DFX_PATH points to non-existent file: {}", + src.display() + ); + + let dest = self.bin_dir.join("dfx"); + fs::copy(&src, &dest).unwrap_or_else(|e| panic!("Failed to copy dfx to test bin dir: {e}")); + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(&dest) + .unwrap_or_else(|e| panic!("Failed to read metadata for {}: {}", dest.display(), e)) + .permissions(); + perms.set_mode(0o500); + fs::set_permissions(&dest, perms).unwrap(); } + + self.dfx_path = Some(dest); + self } pub fn home_path(&self) -> &Path { self.home_dir.path() } + #[allow(dead_code)] pub fn icp(&self) -> Command { - let mut cmd = Command::cargo_bin("icp").expect("binary exists"); - cmd.env("HOME", self.home_path()); + let mut cmd = Command::cargo_bin("icp").expect("icp binary exists"); + self.isolate(&mut cmd); cmd } + + pub fn dfx(&self) -> Command { + let dfx_path = self + .dfx_path + .as_ref() + .expect("dfx not configured in test env — call with_dfx() first"); + let mut cmd = Command::new(dfx_path); + self.isolate(&mut cmd); + cmd + } + + fn isolate(&self, cmd: &mut Command) { + cmd.current_dir(self.home_path()); + cmd.env("HOME", self.home_path()); + cmd.env("PATH", self.os_path.clone()); + } + + fn build_os_path(bin_dir: &Path) -> OsString { + let old_path = env::var_os("PATH").unwrap_or_default(); + let mut new_path = bin_dir.as_os_str().to_os_string(); + new_path.push(PATH_SEPARATOR); + new_path.push(old_path); + new_path + } + + pub fn configure_dfx_local_network(&self) { + let dfx_config_dir = self.home_path().join(".config").join("dfx"); + create_dir_all(&dfx_config_dir).expect("create .config directory"); + let networks_json_path = dfx_config_dir.join("networks.json"); + + let bind_address = "127.0.0.1:8000"; + let networks = format!(r#"{{"local": {{"bind": "{}"}}}}"#, bind_address); + fs::write(&networks_json_path, networks).unwrap(); + } } diff --git a/bin/icp-cli/tests/hello_tests.rs b/bin/icp-cli/tests/hello_tests.rs deleted file mode 100644 index a9058a96..00000000 --- a/bin/icp-cli/tests/hello_tests.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod common; - -use crate::common::TestEnv; -use predicates::str::contains; - -#[test] -fn hello() { - let testenv = TestEnv::new(); - testenv - .icp() - .assert() - .success() - .stdout(contains("Hello, world!")); -} diff --git a/bin/icp-cli/tests/network_tests.rs b/bin/icp-cli/tests/network_tests.rs new file mode 100644 index 00000000..3ed34b67 --- /dev/null +++ b/bin/icp-cli/tests/network_tests.rs @@ -0,0 +1,92 @@ +mod common; + +use std::process::Command; + +use crate::common::TestEnv; +use crate::common::guard::ChildGuard; +use predicates::str::contains; + +#[test] +fn hello() { + let testenv = TestEnv::new().with_dfx(); + + let icp_project_dir = testenv.home_path().join("icp"); + std::fs::create_dir_all(&icp_project_dir).expect("Failed to create icp project directory"); + std::fs::write(icp_project_dir.join("icp.yaml"), "").expect("Failed to write project file"); + + let icp_path = env!("CARGO_BIN_EXE_icp"); + let mut cmd = Command::new(icp_path); + cmd.env("HOME", testenv.home_path()) + .current_dir(icp_project_dir) + .arg("network") + .arg("run"); + + let _child_guard = ChildGuard::spawn(&mut cmd).expect("failed to spawn icp network "); + + testenv.configure_dfx_local_network(); + + testenv + .dfx() + .arg("ping") + .arg("--wait-healthy") + .assert() + .success(); + + testenv + .dfx() + .arg("new") + .arg("hello") + .arg("--type") + .arg("motoko") + .arg("--frontend") + .arg("simple-assets") + .assert() + .success(); + + let project_dir = testenv.home_path().join("hello"); + testenv + .dfx() + .current_dir(&project_dir) + .arg("deploy") + .arg("--no-wallet") + .assert() + .success(); + + testenv + .dfx() + .current_dir(&project_dir) + .arg("canister") + .arg("call") + .arg("hello_backend") + .arg("greet") + .arg(r#"("test")"#) + .assert() + .success() + .stdout(contains(r#"("Hello, test!")"#)); + + let output = testenv + .dfx() + .current_dir(&project_dir) + .arg("canister") + .arg("id") + .arg("hello_frontend") + .assert() + .success() + .get_output() + .stdout + .clone(); + + let frontend_canister_id = std::str::from_utf8(&output) + .expect("stdout was not valid UTF-8") + .trim(); + + let url = format!("http://localhost:8000/sample-asset.txt?canisterId={frontend_canister_id}"); + let response = reqwest::blocking::get(&url) + .expect("Failed to fetch static asset") + .text() + .expect("Failed to read response text"); + assert_eq!( + response, "This is a sample asset!\n", + "Static asset content mismatch" + ); +} diff --git a/lib/icp-fs/Cargo.toml b/lib/icp-fs/Cargo.toml new file mode 100644 index 00000000..f2714918 --- /dev/null +++ b/lib/icp-fs/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "icp-fs" +version = "0.1.0" +edition = "2024" + +[dependencies] +serde = { workspace = true } +serde_json = { workspace = true } +snafu = { workspace = true } diff --git a/lib/icp-fs/src/fs.rs b/lib/icp-fs/src/fs.rs new file mode 100644 index 00000000..049d0ebf --- /dev/null +++ b/lib/icp-fs/src/fs.rs @@ -0,0 +1,60 @@ +use snafu::prelude::*; +use std::path::{Path, PathBuf}; + +#[derive(Snafu, Debug)] +#[snafu(display("failed to create directory {} and parents", path.display()))] +pub struct CreateDirAllError { + pub path: PathBuf, + pub source: std::io::Error, +} + +pub fn create_dir_all(path: &Path) -> Result<(), CreateDirAllError> { + std::fs::create_dir_all(path).context(CreateDirAllSnafu { path }) +} + +#[derive(Snafu, Debug)] +#[snafu(display("failed to read {}", path.display()))] +pub struct ReadFileError { + pub path: PathBuf, + pub source: std::io::Error, +} + +pub fn read>(path: P) -> Result, ReadFileError> { + let path = path.as_ref(); + std::fs::read(path).context(ReadFileSnafu { path }) +} + +#[derive(Snafu, Debug)] +#[snafu(display("failed to remove directory {} and contents", path.display()))] +pub struct RemoveDirAllError { + pub path: PathBuf, + pub source: std::io::Error, +} + +pub fn remove_dir_all(path: &Path) -> Result<(), RemoveDirAllError> { + std::fs::remove_dir_all(path).context(RemoveDirAllSnafu { path }) +} + +#[derive(Snafu, Debug)] +#[snafu(display("failed to remove file {}", path.display()))] +pub struct RemoveFileError { + pub path: PathBuf, + pub source: std::io::Error, +} + +pub fn remove_file>(path: P) -> Result<(), RemoveFileError> { + let path = path.as_ref(); + std::fs::remove_file(path).context(RemoveFileSnafu { path }) +} + +#[derive(Snafu, Debug)] +#[snafu(display("failed to write {}", path.display()))] +pub struct WriteFileError { + pub path: PathBuf, + pub source: std::io::Error, +} + +pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<(), WriteFileError> { + let path = path.as_ref(); + std::fs::write(path, contents).context(WriteFileSnafu { path }) +} diff --git a/lib/icp-fs/src/json.rs b/lib/icp-fs/src/json.rs new file mode 100644 index 00000000..880271a3 --- /dev/null +++ b/lib/icp-fs/src/json.rs @@ -0,0 +1,42 @@ +use crate::fs::{ReadFileError, WriteFileError, read}; +use serde::Serialize; +use snafu::prelude::*; +use std::path::{Path, PathBuf}; + +#[derive(Snafu, Debug)] +pub enum LoadJsonFileError { + #[snafu(display("failed to parse {} as json", path.display()))] + Parse { + path: PathBuf, + source: serde_json::Error, + }, + + #[snafu(transparent)] + Read { source: ReadFileError }, +} + +pub fn load_json_file serde::de::Deserialize<'a>>( + path: &Path, +) -> Result { + let content = read(path)?; + + serde_json::from_slice(content.as_ref()).context(ParseSnafu { path }) +} + +#[derive(Snafu, Debug)] +pub enum SaveJsonFileError { + #[snafu(display("failed to serialize json for {}", path.display()))] + Serialize { + path: PathBuf, + source: serde_json::Error, + }, + + #[snafu(transparent)] + Write { source: WriteFileError }, +} + +pub fn save_json_file(path: &Path, value: &T) -> Result<(), SaveJsonFileError> { + let content = serde_json::to_string_pretty(&value).context(SerializeSnafu { path })?; + crate::fs::write(path, content)?; + Ok(()) +} diff --git a/lib/icp-fs/src/lib.rs b/lib/icp-fs/src/lib.rs new file mode 100644 index 00000000..ba52be04 --- /dev/null +++ b/lib/icp-fs/src/lib.rs @@ -0,0 +1,2 @@ +pub mod fs; +pub mod json; diff --git a/lib/icp-network/Cargo.toml b/lib/icp-network/Cargo.toml index 0aa3015a..57c39bcd 100644 --- a/lib/icp-network/Cargo.toml +++ b/lib/icp-network/Cargo.toml @@ -4,3 +4,16 @@ version = "0.1.0" edition = "2024" [dependencies] +candid = { workspace = true } +fd-lock = { workspace = true } +hex = { workspace = true } +ic-agent = { workspace = true } +icp-fs = { "path" = "../icp-fs" } +pocket-ic = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +uuid = { workspace = true } +snafu = { workspace = true } +time = { workspace = true } +tokio = { workspace = true } diff --git a/lib/icp-network/src/config.rs b/lib/icp-network/src/config.rs new file mode 100644 index 00000000..d9a52514 --- /dev/null +++ b/lib/icp-network/src/config.rs @@ -0,0 +1 @@ +pub(crate) mod model; diff --git a/lib/icp-network/src/config/model.rs b/lib/icp-network/src/config/model.rs new file mode 100644 index 00000000..87d6cc32 --- /dev/null +++ b/lib/icp-network/src/config/model.rs @@ -0,0 +1,4 @@ +pub mod connected; +pub mod managed; +pub mod network_config; +pub mod network_descriptor; diff --git a/lib/icp-network/src/config/model/connected.rs b/lib/icp-network/src/config/model/connected.rs new file mode 100644 index 00000000..ed2d214a --- /dev/null +++ b/lib/icp-network/src/config/model/connected.rs @@ -0,0 +1,9 @@ +use serde::Deserialize; + +/// A "connected network" is a network that we connect to but don't manage. +/// Typical examples are mainnet or testnets. +#[derive(Deserialize)] +pub struct ConnectedNetworkModel { + // /// The URL(s) this network can be reached at. + // providers: Vec, +} diff --git a/lib/icp-network/src/config/model/managed.rs b/lib/icp-network/src/config/model/managed.rs new file mode 100644 index 00000000..1121d3b8 --- /dev/null +++ b/lib/icp-network/src/config/model/managed.rs @@ -0,0 +1,50 @@ +use serde::{Deserialize, Deserializer}; + +/// A "managed network" is a network that we start, configure, stop. +#[derive(Deserialize, Default)] +pub struct ManagedNetworkModel { + pub gateway: GatewayModel, +} + +#[derive(Deserialize)] +pub struct GatewayModel { + #[serde(default = "default_host")] + pub host: String, + #[serde(default = "default_port", deserialize_with = "deserialize_port")] + pub port: BindPort, +} + +#[derive(Debug, Clone, Deserialize)] +pub enum BindPort { + Fixed(u16), + Dynamic, +} + +fn default_host() -> String { + "127.0.0.1".to_string() +} + +fn default_port() -> BindPort { + BindPort::Fixed(8000) +} + +impl Default for GatewayModel { + fn default() -> Self { + Self { + host: default_host(), + port: default_port(), + } + } +} + +fn deserialize_port<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let raw = u16::deserialize(deserializer)?; + Ok(if raw == 0 { + BindPort::Dynamic + } else { + BindPort::Fixed(raw) + }) +} diff --git a/lib/icp-network/src/config/model/network_config.rs b/lib/icp-network/src/config/model/network_config.rs new file mode 100644 index 00000000..c194bda7 --- /dev/null +++ b/lib/icp-network/src/config/model/network_config.rs @@ -0,0 +1,16 @@ +use crate::config::model::connected::ConnectedNetworkModel; +use crate::config::model::managed::ManagedNetworkModel; +use serde::Deserialize; + +#[derive(Deserialize)] +#[serde(tag = "mode", rename_all = "kebab-case")] +pub enum NetworkConfig { + Managed(ManagedNetworkModel), + Connected(ConnectedNetworkModel), +} + +impl NetworkConfig { + pub fn local_default() -> Self { + NetworkConfig::Managed(ManagedNetworkModel::default()) + } +} diff --git a/lib/icp-network/src/config/model/network_descriptor.rs b/lib/icp-network/src/config/model/network_descriptor.rs new file mode 100644 index 00000000..6fe1d23c --- /dev/null +++ b/lib/icp-network/src/config/model/network_descriptor.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use uuid::Uuid; + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct NetworkDescriptorModel { + pub id: Uuid, + pub path: PathBuf, + pub gateway_port: Option, + pub pid: Option, + pub root_key: String, +} diff --git a/lib/icp-network/src/lib.rs b/lib/icp-network/src/lib.rs index 8b137891..256de4f6 100644 --- a/lib/icp-network/src/lib.rs +++ b/lib/icp-network/src/lib.rs @@ -1 +1,9 @@ +pub mod config; +mod managed; +pub mod status; +pub mod structure; +pub use config::model::managed::ManagedNetworkModel; +pub use config::model::network_config::NetworkConfig; +pub use managed::run::RunNetworkError; +pub use managed::run::run_network; diff --git a/lib/icp-network/src/managed.rs b/lib/icp-network/src/managed.rs new file mode 100644 index 00000000..8e3d3864 --- /dev/null +++ b/lib/icp-network/src/managed.rs @@ -0,0 +1,2 @@ +pub mod pocketic; +pub mod run; diff --git a/lib/icp-network/src/managed/pocketic.rs b/lib/icp-network/src/managed/pocketic.rs new file mode 100644 index 00000000..123b6a9a --- /dev/null +++ b/lib/icp-network/src/managed/pocketic.rs @@ -0,0 +1,3 @@ +pub mod admin; +pub mod instance; +pub mod native; diff --git a/lib/icp-network/src/managed/pocketic/admin.rs b/lib/icp-network/src/managed/pocketic/admin.rs new file mode 100644 index 00000000..47060111 --- /dev/null +++ b/lib/icp-network/src/managed/pocketic/admin.rs @@ -0,0 +1,145 @@ +use pocket_ic::common::rest::{ + AutoProgressConfig, CreateHttpGatewayResponse, CreateInstanceResponse, ExtendedSubnetConfigSet, + HttpGatewayBackend, HttpGatewayConfig, HttpGatewayInfo, InstanceConfig, InstanceId, RawTime, + SubnetSpec, Topology, +}; +use reqwest::Url; +use snafu::prelude::*; +use std::path::Path; +use time::OffsetDateTime; + +pub struct PocketIcAdminInterface { + client: reqwest::Client, + base_url: Url, +} + +impl PocketIcAdminInterface { + pub fn new(base_url: Url) -> Self { + let client = reqwest::Client::new(); + Self { client, base_url } + } + + fn post(&self, path: &str) -> reqwest::RequestBuilder { + self.client.post(self.base_url.join(path).unwrap()) + } + + pub async fn create_instance( + &self, + state_dir: &Path, + ) -> Result<(InstanceId, Topology), CreateInstanceError> { + let subnet_config_set = ExtendedSubnetConfigSet { + nns: Some(SubnetSpec::default()), + sns: Some(SubnetSpec::default()), + ii: Some(SubnetSpec::default()), + fiduciary: Some(SubnetSpec::default()), + bitcoin: Some(SubnetSpec::default()), + system: vec![], + verified_application: vec![], + application: vec![<_>::default()], + }; + let resp = self + .post("/instances") + .json(&InstanceConfig { + subnet_config_set, + state_dir: Some(state_dir.to_path_buf()), + nonmainnet_features: true, + log_level: Some("ERROR".to_string()), + bitcoind_addr: None, // bitcoind_addr.clone(), + }) + .send() + .await? + .error_for_status()? + .json::() + .await?; + match resp { + CreateInstanceResponse::Error { message } => { + Err(CreateInstanceError::Create { message }) + } + CreateInstanceResponse::Created { + instance_id, + topology, + } => Ok((instance_id, topology)), + } + } + + pub(crate) async fn set_time(&self, instance_id: InstanceId) -> Result<(), reqwest::Error> { + self.post(&format!("/instances/{instance_id}/update/set_time")) + .json(&RawTime { + nanos_since_epoch: OffsetDateTime::now_utc() + .unix_timestamp_nanos() + .try_into() + .unwrap(), + }) + .send() + .await? + .error_for_status()?; + Ok(()) + } + + pub(crate) async fn auto_progress( + &self, + instance_id: InstanceId, + artificial_delay: i32, + ) -> Result<(), reqwest::Error> { + self.post(&format!("/instances/{instance_id}/auto_progress")) + .json(&AutoProgressConfig { + artificial_delay_ms: Some(artificial_delay as u64), + }) + .send() + .await? + .error_for_status()?; + Ok(()) + } + + pub(crate) async fn create_http_gateway( + &self, + forward_to: HttpGatewayBackend, + port: Option, + ) -> Result { + let resp = self + .post("/http_gateway") + .json(&HttpGatewayConfig { + ip_addr: None, + port, + forward_to, + domains: None, + https_config: None, + }) + .send() + .await? + .error_for_status()? + .json::() + .await?; + + match resp { + CreateHttpGatewayResponse::Error { message } => { + Err(CreateHttpGatewayError::Create { message }) + } + CreateHttpGatewayResponse::Created(info) => Ok(info), + } + } +} + +#[derive(Debug, Snafu)] +pub enum CreateInstanceError { + #[snafu( + display("failed to create PocketIC instance: {message}"), + context(suffix(InstanceSnafu)) + )] + Create { message: String }, + + #[snafu(transparent)] + Reqwest { source: reqwest::Error }, +} + +#[derive(Debug, Snafu)] +pub enum CreateHttpGatewayError { + #[snafu( + display("failed to create HTTP gateway: {message}"), + context(suffix(GatewaySnafu)) + )] + Create { message: String }, + + #[snafu(transparent, context(false))] + Reqwest { source: reqwest::Error }, +} diff --git a/lib/icp-network/src/managed/pocketic/instance.rs b/lib/icp-network/src/managed/pocketic/instance.rs new file mode 100644 index 00000000..e0c71d74 --- /dev/null +++ b/lib/icp-network/src/managed/pocketic/instance.rs @@ -0,0 +1,12 @@ +use crate::managed::pocketic::admin::PocketIcAdminInterface; +use candid::Principal; +use pocket_ic::common::rest::InstanceId; + +#[allow(dead_code)] +pub struct PocketIcInstance { + pub admin: PocketIcAdminInterface, + pub gateway_port: u16, + pub instance_id: InstanceId, + pub effective_canister_id: Principal, + pub root_key: String, +} diff --git a/lib/icp-network/src/managed/pocketic/native.rs b/lib/icp-network/src/managed/pocketic/native.rs new file mode 100644 index 00000000..721adb60 --- /dev/null +++ b/lib/icp-network/src/managed/pocketic/native.rs @@ -0,0 +1,19 @@ +use std::path::Path; + +pub fn spawn_pocketic(pocketic_path: &Path, port_file: &Path) -> tokio::process::Child { + let mut cmd = tokio::process::Command::new(pocketic_path); + cmd.arg("--port-file"); + cmd.arg(port_file.as_os_str()); + cmd.args(["--ttl", "2592000", "--log-levels", "error"]); + + cmd.stdout(std::process::Stdio::inherit()); + cmd.stderr(std::process::Stdio::inherit()); + #[cfg(unix)] + { + //use std::os::unix::process::CommandExt; + cmd.process_group(0); + } + + eprintln!("Starting PocketIC..."); + cmd.spawn().expect("Could not start PocketIC.") +} diff --git a/lib/icp-network/src/managed/run.rs b/lib/icp-network/src/managed/run.rs new file mode 100644 index 00000000..fd834c27 --- /dev/null +++ b/lib/icp-network/src/managed/run.rs @@ -0,0 +1,283 @@ +use crate::RunNetworkError::NoPocketIcPath; +use crate::config::model::managed::ManagedNetworkModel; +use crate::config::model::network_descriptor::NetworkDescriptorModel; +use crate::managed::pocketic::admin::{ + CreateHttpGatewayError, CreateInstanceError, PocketIcAdminInterface, +}; +use crate::managed::pocketic::instance::PocketIcInstance; +use crate::managed::pocketic::native::spawn_pocketic; +use crate::managed::run::InitializePocketicError::NoRootKey; +use crate::status; +use crate::structure::NetworkDirectoryStructure; +use fd_lock::RwLock; +use icp_fs::fs::{ + CreateDirAllError, RemoveDirAllError, RemoveFileError, create_dir_all, remove_dir_all, + remove_file, +}; +use icp_fs::json::{SaveJsonFileError, save_json_file}; +use pocket_ic::common::rest::HttpGatewayBackend; +use reqwest::Url; +use snafu::prelude::*; +use std::env::var_os; +use std::fs::{OpenOptions, read_to_string}; +use std::path::{Path, PathBuf}; +use std::process::ExitStatus; +use std::time::Duration; +use tokio::process::Child; +use tokio::select; +use tokio::signal::ctrl_c; +use tokio::time::sleep; +use uuid::Uuid; + +pub async fn run_network( + config: ManagedNetworkModel, + nds: NetworkDirectoryStructure, +) -> Result<(), RunNetworkError> { + let pocketic_path = PathBuf::from(var_os("ICP_POCKET_IC_PATH").ok_or(NoPocketIcPath)?); + + create_dir_all(nds.network_root())?; + + let mut file = RwLock::new( + OpenOptions::new() + .create(true) + .write(true) + .read(true) + .truncate(true) + .open(nds.lock_path()) + .map_err(|source| RunNetworkError::OpenLockFile { source })?, + ); + let _guard = file + .try_write() + .map_err(|_| RunNetworkError::AlreadyRunningThisProject)?; + eprintln!("Holding lock on {}", nds.lock_path().display()); + + run_pocketic(&pocketic_path, config, nds).await?; + Ok(()) +} + +#[derive(Debug, Snafu)] +pub enum RunNetworkError { + #[snafu(display("already running (this project)"))] + AlreadyRunningThisProject, + + #[snafu(transparent)] + CreateDirFailed { source: CreateDirAllError }, + + #[snafu(display("ICP_POCKET_IC_PATH environment variable is not set"))] + NoPocketIcPath, + + #[snafu(display("failed to open lock file"))] + OpenLockFile { source: std::io::Error }, + + #[snafu(transparent)] + RunPocketIcError { source: RunPocketIcError }, +} + +async fn run_pocketic( + pocketic_path: &Path, + _config: ManagedNetworkModel, + nds: NetworkDirectoryStructure, +) -> Result<(), RunPocketIcError> { + eprintln!("PocketIC path: {}", pocketic_path.display()); + + create_dir_all(&nds.pocketic_dir())?; + let port_file = nds.pocketic_port_file(); + if port_file.exists() { + remove_file(&port_file)?; + } + eprintln!("Port file: {}", port_file.display()); + if nds.state_dir().exists() { + remove_dir_all(&nds.state_dir())?; + } + create_dir_all(&nds.state_dir())?; + let mut child = spawn_pocketic(pocketic_path, &port_file); + + let result = async { + let port = wait_for_port(&port_file, &mut child).await?; + eprintln!("PocketIC started on port {port}"); + let instance = initialize_pocketic(port, &nds.state_dir()).await?; + + let nd = NetworkDescriptorModel { + id: Uuid::new_v4(), + path: nds.network_root().to_path_buf(), + gateway_port: Some(instance.gateway_port), + pid: Some(child.id().unwrap()), + root_key: instance.root_key, + }; + save_json_file(&nds.project_descriptor_path(), &nd)?; + eprintln!("Press Ctrl-C to exit."); + let _ = wait_for_shutdown(&mut child).await; + Ok(()) + } + .await; + + let _ = child.kill().await; + let _ = child.wait().await; + + result +} + +#[derive(Debug, Snafu)] +pub enum RunPocketIcError { + #[snafu(transparent)] + CreateDirAll { source: CreateDirAllError }, + + #[snafu(transparent)] + RemoveDirAll { source: RemoveDirAllError }, + + #[snafu(transparent)] + RemoveFile { source: RemoveFileError }, + + #[snafu(transparent)] + SaveJsonFile { source: SaveJsonFileError }, + + #[snafu(transparent)] + InitPocketIc { source: InitializePocketicError }, + + #[snafu(transparent)] + WaitForPort { source: WaitForPortError }, +} + +pub enum ShutdownReason { + CtrlC, + ChildExited, +} + +async fn wait_for_shutdown(child: &mut Child) -> ShutdownReason { + select!( + _ = ctrl_c() => { + eprintln!("Received Ctrl-C, shutting down PocketIC..."); + ShutdownReason::CtrlC + } + res = notice_child_exit(child) => { + eprintln!("PocketIC exited with status: {:?}", res.status); + ShutdownReason::ChildExited + } + ) +} + +pub async fn wait_for_port_file(path: &Path) -> Result { + let mut retries = 0; + while retries < 3000 { + if let Ok(contents) = read_to_string(path) { + if contents.ends_with('\n') { + if let Ok(port) = contents.trim().parse::() { + return Ok(port); + } + } + } + + sleep(Duration::from_millis(100)).await; + retries += 1; + } + Err(WaitForPortTimeoutError) +} + +#[derive(Debug, Snafu)] +#[snafu(display("timeout waiting for port file"))] +pub struct WaitForPortTimeoutError; + +/// Yields immediately if the child exits. +pub async fn notice_child_exit(child: &mut Child) -> ChildExitError { + loop { + if let Some(status) = child.try_wait().expect("child status query failed") { + return ChildExitError { status }; + } + sleep(Duration::from_millis(100)).await; + } +} + +#[derive(Debug, Snafu)] +#[snafu(display("Child process exited early with status {status}"))] +pub struct ChildExitError { + pub status: ExitStatus, +} + +/// Waits for the child to populate a port number. +/// Exits early if the child exits or the user interrupts. +pub async fn wait_for_port(path: &Path, child: &mut Child) -> Result { + tokio::select! { + res = wait_for_port_file(path) => res.map_err(WaitForPortError::from), + _ = ctrl_c() => Err(WaitForPortError::Interrupted), + err = notice_child_exit(child) => Err(WaitForPortError::ChildExited { source: err }), + } +} + +#[derive(Debug, Snafu)] +pub enum WaitForPortError { + #[snafu(display("Interrupted"))] + Interrupted, + #[snafu(transparent)] + PortFile { source: WaitForPortTimeoutError }, + #[snafu(transparent)] + ChildExited { source: ChildExitError }, +} + +async fn initialize_pocketic( + port: u16, + state_dir: &Path, +) -> Result { + let pic = + PocketIcAdminInterface::new(format!("http://localhost:{port}").parse::().unwrap()); + + eprintln!("Initializing PocketIC instance"); + + eprintln!("Creating instance"); + let (instance_id, topology) = pic.create_instance(state_dir).await?; + let default_effective_canister_id = topology.default_effective_canister_id; + eprintln!("Created instance with id {}", instance_id); + + eprintln!("Setting time"); + pic.set_time(instance_id).await?; + + eprintln!("Set auto-progress"); + let artificial_delay = 600; + pic.auto_progress(instance_id, artificial_delay).await?; + + let gateway_info = pic + .create_http_gateway( + HttpGatewayBackend::PocketIcInstance(instance_id), + Some(8000), + ) + .await?; + eprintln!( + "Created HTTP gateway instance={} port={}", + gateway_info.instance_id, gateway_info.port + ); + + let agent_url = format!("http://localhost:{}", gateway_info.port); + + eprintln!("Agent url is {}", agent_url); + let status = status::ping_and_wait(&agent_url).await?; + + let root_key = status.root_key.ok_or(NoRootKey)?; + let root_key = hex::encode(root_key); + eprintln!("Root key: {root_key}"); + + let props = PocketIcInstance { + admin: pic, + gateway_port: gateway_info.port, + instance_id, + effective_canister_id: default_effective_canister_id.into(), + root_key, + }; + Ok(props) +} + +#[derive(Debug, Snafu)] +pub enum InitializePocketicError { + #[snafu(transparent)] + CreateInstance { source: CreateInstanceError }, + + #[snafu(transparent)] + CreateHttpGateway { source: CreateHttpGatewayError }, + + #[snafu(display("no root key reported in status"))] + NoRootKey, + + #[snafu(transparent)] + PingAndWait { source: status::PingAndWaitError }, + + #[snafu(transparent)] + Reqwest { source: reqwest::Error }, +} diff --git a/lib/icp-network/src/status.rs b/lib/icp-network/src/status.rs new file mode 100644 index 00000000..9db01b3d --- /dev/null +++ b/lib/icp-network/src/status.rs @@ -0,0 +1,42 @@ +use ic_agent::agent::status::Status; +use ic_agent::{Agent, AgentError}; +use snafu::prelude::*; +use std::time::Duration; + +pub async fn ping_and_wait(url: &str) -> Result { + let agent = Agent::builder() + .with_url(url) + .build() + .context(BuildAgentSnafu { url })?; + let mut retries = 0; + loop { + let status = agent.status().await; + match status { + Ok(status) => { + if matches!(&status.replica_health_status, Some(status) if status == "healthy") { + break Ok(status); + } + } + Err(e) => { + if retries >= 60 { + break Err(PingAndWaitError::Timeout { source: e }); + } + tokio::time::sleep(Duration::from_secs(1)).await; + retries += 1; + } + } + } +} + +#[derive(Debug, Snafu)] +pub enum PingAndWaitError { + #[snafu(display("failed to build agent for url {}", url))] + BuildAgent { + source: AgentError, + url: String, + }, + + Timeout { + source: AgentError, + }, +} diff --git a/lib/icp-network/src/structure.rs b/lib/icp-network/src/structure.rs new file mode 100644 index 00000000..cc2aa97f --- /dev/null +++ b/lib/icp-network/src/structure.rs @@ -0,0 +1,42 @@ +use std::path::{Path, PathBuf}; + +pub struct NetworkDirectoryStructure { + pub network_root: PathBuf, +} + +impl NetworkDirectoryStructure {} + +impl NetworkDirectoryStructure { + pub fn new(network_root: &Path) -> Self { + let network_root = network_root.to_path_buf(); + Self { network_root } + } + + pub fn network_root(&self) -> &PathBuf { + &self.network_root + } + + pub fn project_descriptor_path(&self) -> PathBuf { + self.network_root.join("descriptor.json") + } + + pub fn lock_path(&self) -> PathBuf { + self.network_root.join("lock") + } + + pub fn state_dir(&self) -> PathBuf { + self.network_root.join("state") + } + + pub fn pocketic_dir(&self) -> PathBuf { + self.network_root.join("pocket-ic") + } + + // pocketic expects this file not to exist when launching it. + // pocketic populates it with the port number, and deletes the file when it exits. + // if the file exists, pocketic assumes this means another pocketic instance + // is running, and exits with exit code(0). + pub fn pocketic_port_file(&self) -> PathBuf { + self.pocketic_dir().join("port") + } +}